[LON-CAPA-cvs] cvs: loncom /imspackages imsexport.pm /interface londocs.pm

raeburn raeburn at source.lon-capa.org
Sun Jan 29 14:51:01 EST 2012


raeburn		Sun Jan 29 19:51:01 2012 EDT

  Modified files:              
    /loncom/interface	londocs.pm 
    /loncom/imspackages	imsexport.pm 
  Log:
  - Move routines used for IMS exports from londocs.pm to imsexport.pm.
  - Move generation of javascript to separate routine: &export_javascript()
  - javascript functions: propagateCheck() and containerCheck() now take
    two arguments -- form name and item.   
  
  
-------------- next part --------------
Index: loncom/interface/londocs.pm
diff -u loncom/interface/londocs.pm:1.474 loncom/interface/londocs.pm:1.475
--- loncom/interface/londocs.pm:1.474	Tue Jan  3 01:54:39 2012
+++ loncom/interface/londocs.pm	Sun Jan 29 19:50:53 2012
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Documents
 #
-# $Id: londocs.pm,v 1.474 2012/01/03 01:54:39 raeburn Exp $
+# $Id: londocs.pm,v 1.475 2012/01/29 19:50:53 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -265,809 +265,12 @@
     }
 }
 
-
-
 sub exportbutton {
     my $crstype = &Apache::loncommon::course_type();
     return "<a class='LC_menubuttons_link' href='javascript:injectData(document.courseverify, \"dummy\", \"exportcourse\", \"".&mt('IMS Export')."\")'>".&mt('IMS Export')."</a>".
     &Apache::loncommon::help_open_topic('Docs_Export_Course_Docs').'<br />';
 }
 
-
-
-sub exportcourse {
-    my $r=shift;
-    my $crstype = &Apache::loncommon::course_type();
-    my %discussiontime = &Apache::lonnet::dump('discussiontimes',
-                                               $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'});
-    my $numdisc = keys(%discussiontime);
-    my $numprobs = 0;
-    my $navmap = Apache::lonnavmaps::navmap->new();
-    if (!defined($navmap)) {
-        $r->print(&Apache::loncommon::start_page('Export '.$crstype.' to IMS Package').
-                  '<h2>'.&mt('IMS Export Failed').'</h2>'.
-                  '<div class="LC_error">');
-        if ($crstype eq 'Community') {
-            $r->print(&mt('Unable to retrieve information about community contents'));
-        } else {
-            $r->print(&mt('Unable to retrieve information about course contents'));
-        }
-        $r->print('</div><a href="/adm/coursedocs">');
-        if ($crstype eq 'Community') {
-            $r->print(&mt('Return to Community Editor'));
-        } else {
-            $r->print(&mt('Return to Course Editor'));
-        }
-        $r->print('</a>');
-        &Apache::lonnet::logthis('IMS export failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
-        return;
-    }
-    my $it=$navmap->getIterator(undef,undef,undef,1,undef,undef);
-    my $curRes;
-    my $outcome;
-
-    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
-                                            ['finishexport']);
-    if ($env{'form.finishexport'}) {
-        &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
-                                            ['archive','discussion']);
-
-        my $format = $env{'form.format'};
-        my @exportitems = &Apache::loncommon::get_env_multiple('form.archive');
-        my @discussions = &Apache::loncommon::get_env_multiple('form.discussion');
-        if (@exportitems == 0 && @discussions == 0) {
-            $outcome = 
-                '<p class="LC_warning">'
-               .&mt('As you did not select any content items or discussions'
-                   .' for export, an IMS package has not been created.')
-               .'</p>'
-               .'<p>'
-               .&mt('Please [_1]go back[_2] to select either content items'
-                   .' or discussions for export.'
-                       ,'<a href="javascript:history.go(-1)">'
-                       ,'</a>')
-               .'</p>';
-        } else {
-            my $now = time;
-            my %symbs;
-            my $manifestok = 0;
-            my $imsresources;
-            my $tempexport;
-            my $copyresult;
-            my $testbank;
-            my $ims_manifest = &create_ims_store($now,\$manifestok,\$outcome,\$tempexport,$format,\$testbank);
-            if ($manifestok) {
-                &build_package($now,$navmap,\@exportitems,\@discussions,\$outcome,$tempexport,\$copyresult,$ims_manifest,$format,$testbank);
-                close($ims_manifest);
-
-#Create zip file in prtspool
-                my $imszipfile = '/prtspool/'.
-                $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
-                   time.'_'.rand(1000000000).'.zip';
-                my $cwd = &Cwd::getcwd();
-                my $imszip = '/home/httpd/'.$imszipfile;
-                chdir $tempexport;
-                open(OUTPUT, "zip -r $imszip *  2> /dev/null |");
-                close(OUTPUT);
-                chdir $cwd;
-                $outcome .= '<p>'
-                           .&mt('[_1]Your IMS package[_2] is ready for download.'
-                               ,'<a href="'.$imszipfile.'">','</a>')
-                           .'</p>';
-                if ($copyresult) {
-                    $outcome .= '<p class="LC_error">'
-                               .&mt('The following errors occurred during export - [_1]'
-                                   ,$copyresult)
-                               .'</p>';
-                }
-            } else {
-                $outcome = '<p class="LC_error">'
-                          .&mt('Unfortunately you will not be able to retrieve'
-                              .' an IMS archive of your course at this time,'
-                              .' because there was a problem creating a'
-                              .' manifest file.')
-                          .'</p>'
-                          .'<p><a href="javascript:history.go(-1)">'
-                          .&mt('Go Back')
-                          .'</a></p>';
-            }
-        }
-        $r->print(&Apache::loncommon::start_page('Export '.$crstype.' to IMS Package'));
-	$r->print(&Apache::lonhtmlcommon::breadcrumbs('IMS Export'));
-        $r->print($outcome);
-        $r->print(&Apache::loncommon::end_page());
-    } else {
-        my $display='<form name="exportdoc" action="" method="post">'."\n".
-                    '<p>'.
-                    &mt('Choose which items you wish to export from your '.$crstype.'.').
-                    '</p>'.
-                    '<div class="LC_columnSection"><fieldset>'.
-                    '<legend>'.&mt('Content items').'</legend>'.
-                    '<input type="button" value="'.&mt('check all').'" '.
-                    'onclick="javascript:checkAll(document.exportdoc.archive)" />'.
-                    '  <input type="button" value="'.&mt('uncheck all').'"'.
-                    ' onclick="javascript:uncheckAll(document.exportdoc.archive)" /></fieldset>';
-        if ($numdisc > 0) {
-            $display .= '<fieldset>'.
-                        '<legend>'.&mt('Discussion posts').'</legend>'.
-                        '<input type="button" value="'.&mt('check all').'"'.
-                        ' onclick="javascript:checkAll(document.exportdoc.discussion)" />'.
-                        '  <input type="button" value="'.&mt('uncheck all').'"'.
-                        ' onclick="javascript:uncheckAll(document.exportdoc.discussion)" />'.
-                        '</fieldset>';
-        }
-        $display .= '</div>';
-        my $curRes;
-        my $depth = 0;
-        my $count = 0;
-        my $boards = 0;
-        my $startcount = 5;
-        my %parent = ();
-        my %children = ();
-        my $lastcontainer = $startcount;
-        $display .= &Apache::loncommon::start_data_table()
-                   .&Apache::loncommon::start_data_table_header_row()
-                   .'<th>'.&mt('Export content item?').'</th>';
-        if ($numdisc > 0) {
-            $display .= '<th>'.&mt('Export discussion posts?').'</th>';
-        }
-        $display .= &Apache::loncommon::end_data_table_header_row();
-        while ($curRes = $it->next()) {
-            if (ref($curRes)) {
-                $count ++;
-            }
-            if ($curRes == $it->BEGIN_MAP()) {
-                $depth++;
-                $parent{$depth} = $lastcontainer;
-            }
-            if ($curRes == $it->END_MAP()) {
-                $depth--;
-                $lastcontainer = $parent{$depth};
-            }
-            if (ref($curRes)) {
-                my $symb = $curRes->symb();
-                my $ressymb = $symb;
-                if ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) {
-                    unless ($ressymb =~ m|adm/wrapper/adm|) {
-                        $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard';
-                    }
-                }
-                my $currelem = $count+$boards+$startcount;
-                $display .= &Apache::loncommon::start_data_table_row()
-                           .'<td>'."\n"
-                           .'<input type="checkbox" name="archive" value="'.$count.'" ';
-                if (($curRes->is_sequence()) || ($curRes->is_page())) {
-                    $lastcontainer = $currelem;
-                    $display .= 'onclick="javascript:propagateCheck('."'$currelem'".')"';
-                } elsif ($curRes->is_problem()) {
-                    $numprobs ++; 
-                }
-                $display .= ' />'."\n";
-                for (my $i=0; $i<$depth; $i++) {
-                    $display .= ('<img src="/adm/lonIcons/whitespace1.gif" class="LC_docs_spacer" alt="" />' x2)."\n";
-                }
-                if ($curRes->is_sequence()) {
-                    $display .= '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" /> '."\n";
-                } elsif ($curRes->is_page()) {
-                    $display .= '<img src="/adm/lonIcons/navmap.page.open.gif" alt="" /> '."\n";
-                }
-                $children{$parent{$depth}} .= $currelem.':';
-                $display .= ' '.$curRes->title().'</td>'."\n";
-
-                # Existing discussion posts?
-                if ($discussiontime{$ressymb} > 0) {
-                    $boards ++;
-                    $display .= '<td align="right">'
-                               .'<input type="checkbox" name="discussion" value="'.$count.'" />'
-                               .'</td>'."\n";
-                } elsif ($numdisc > 0) {
-                    $display .= '<td> </td>'."\n";
-                }
-                $display .= &Apache::loncommon::end_data_table_row();
-            }
-        }
-        $display .= &Apache::loncommon::end_data_table();
-        my $scripttag = qq|
-<script type="text/javascript">
-// <![CDATA[
-function checkAll(field) {
-    if (field.length > 0) {
-        for (i = 0; i < field.length; i++) {
-            field[i].checked = true ;
-        }
-    } else {
-        field.checked = true
-    }
-}
-
-function uncheckAll(field) {
-    if (field.length > 0) {
-        for (i = 0; i < field.length; i++) {
-            field[i].checked = false ;
-        }
-    } else {
-        field.checked = false ;
-    }
-}
-
-function propagateCheck(item) {
-    if (document.exportdoc.elements[item].checked == true) {
-        containerCheck(item)
-    }
-}
-
-function containerCheck(item) {
-    document.exportdoc.elements[item].checked = true
-    var numitems = $count + $boards + $startcount
-    var parents = new Array(numitems)
-    for (var i=$startcount; i<numitems; i++) {
-        parents[i] = new Array
-    }
-        |;
-
-        foreach my $container (sort { $a <=> $b } (keys(%children))) {
-            my @contents = split(/:/,$children{$container});
-            for (my $i=0; $i<@contents; $i ++) {
-                $scripttag .= '    parents['.$container.']['.$i.'] = '.$contents[$i]."\n";
-            }
-        }
-
-        $scripttag .= qq|
-    if (parents[item].length > 0) {
-        for (var j=0; j<parents[item].length; j++) {
-            containerCheck(parents[item][j])
-        }
-     }
-}
-// ]]>
-</script>
-        |;
-	$r->print(&Apache::loncommon::start_page('Export '.$crstype.' to IMS Package',
-						 $scripttag));
-	$r->print(&Apache::lonhtmlcommon::breadcrumbs('IMS Export'));
-        if ($numprobs > 0) {
-            $display .= '<p><span class="LC_nobreak">'.
-                        &mt('Export format for LON-CAPA problems:').
-                        '<label><input type="radio" name="format" value="xml" checked="checked" />'.
-                        ' '.&mt('XML').'</label>'.(' ' x3).
-                        '<label><input type="radio" name="format" value="html" />'.
-                        ' '.&mt('HTML').'</label>'.(' ' x3).
-                        '<label><input type="radio" name="format" value="plaintext" />'.
-                        ' '.&mt('Text').'</label></span></p>';
-        }
-	$r->print($display.
-                  '<p><input type="hidden" name="finishexport" value="1" />'.
-                  '<input type="submit" name="exportcourse" value="'.
-                  &mt('Export').'" /></p></form>');
-    }
-}
-
-sub create_ims_store {
-    my ($now,$manifestok,$outcome,$tempexport,$format,$testbank) = @_;
-    $$tempexport = $Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/ims_exports';
-    my $ims_manifest;
-    if (!-e $$tempexport) {
-        mkdir($$tempexport,0700);
-    }
-    $$tempexport .= '/'.$now;
-    if (!-e $$tempexport) {
-        mkdir($$tempexport,0700);
-    }
-    $$tempexport .= '/'.$env{'user.domain'}.'_'.$env{'user.name'};
-    if (!-e $$tempexport) {
-        mkdir($$tempexport,0700);
-    }
-    if (!-e "$$tempexport/resources") {
-        mkdir("$$tempexport/resources",0700);
-    }
-# open manifest file
-    my $manifest = '/imsmanifest.xml';
-    my $manifestfilename = $$tempexport.$manifest;
-    if ($ims_manifest = Apache::File->new('>'.$manifestfilename)) {
-        $$manifestok=1;
-        print $ims_manifest
-'<?xml version="1.0" encoding="UTF-8"?>'."\n".
-'<manifest xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"'.
-' xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2"'.
-' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'.
-' identifier="MANIFEST-'.$env{'request.course.id'}.'-'.$now.'"'.
-'  xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1imscp_v1p1.xsd'.
-'  http://www.imsglobal.org/xsd/imsmd_v1p2 imsmd_v1p2p2.xsd">'."\n".
-'  <metadata>
-    <schema></schema>
-    <imsmd:lom>
-      <imsmd:general>
-        <imsmd:identifier>'.$env{'request.course.id'}.'</imsmd:identifier>
-        <imsmd:title>
-          <imsmd:langstring xml:lang="en">'.$env{'course.'.$env{'request.course.id'}.'.description'}.'</imsmd:langstring>
-        </imsmd:title>
-      </imsmd:general>
-    </imsmd:lom>
-  </metadata>'."\n".
-'  <organizations default="ORG-'.$env{'request.course.id'}.'-'.$now.'">'."\n".
-'    <organization identifier="ORG-'.$env{'request.course.id'}.'-'.$now.'"'.
-' structure="hierarchical">'."\n".
-'      <title>'.$env{'course.'.$env{'request.course.id'}.'.description'}.'</title>';
-        if ($format eq 'plaintext') {
-            my $testbankfilename = $$tempexport.'/testbank.txt';
-            $$testbank = Apache::File->new('>'.$testbankfilename);
-        }
-    } else {
-        $$outcome .= 'An error occurred opening the IMS manifest file.<br />'
-;
-    }
-    return $ims_manifest;
-}
-
-sub build_package {
-    my ($now,$navmap,$exportitems,$discussions,$outcome,$tempexport,$copyresult,
-        $ims_manifest,$format,$testbank) = @_;
-# first iterator to look for dependencies
-    my $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);
-    my $curRes;
-    my $count = 0;
-    my $depth = 0;
-    my $lastcontainer = 0;
-    my %parent = ();
-    my @dependencies = ();
-    my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
-    my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
-    while ($curRes = $it->next()) {
-        if (ref($curRes)) {
-            $count ++;
-        }
-        if ($curRes == $it->BEGIN_MAP()) {
-            $depth++;
-            $parent{$depth} = $lastcontainer;
-        }
-        if ($curRes == $it->END_MAP()) {
-            $depth--;
-            $lastcontainer = $parent{$depth};
-        }
-        if (ref($curRes)) {
-            if ($curRes->is_sequence() || $curRes->is_page()) {
-                $lastcontainer = $count;
-            }
-            if (grep(/^$count$/,@$exportitems)) {
-                &get_dependencies($exportitems,\%parent,$depth,\@dependencies);
-            }
-        }
-    }
-# second iterator to build manifest and store resources
-    $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);
-    $depth = 0;
-    my $prevdepth;
-    $count = 0;
-    my $imsresources;
-    my $pkgdepth;
-    my $currdirpath = 'Top';
-    while ($curRes = $it->next()) {
-        if ($curRes == $it->BEGIN_MAP()) {
-            $prevdepth = $depth;
-            $depth++;
-        }
-        if ($curRes == $it->END_MAP()) {
-            $prevdepth = $depth;
-            $depth--;
-        }
-
-        if (ref($curRes)) {
-            $count ++;
-            if ((grep(/^$count$/,@$exportitems)) || (grep(/^$count$/, at dependencies))) {
-                my $symb = $curRes->symb();
-                my $isvisible = 'true';
-                my $resourceref;
-                if ($curRes->randomout()) {
-                    $isvisible = 'false';
-                }
-                unless ($curRes->is_sequence()) {
-                    $resourceref = 'identifierref="RES-'.$env{'request.course.id'}.'-'.$count.'"';
-                }
-                my $step = $prevdepth - $depth;
-                if (($step >= 0) && ($count > 1)) {
-                    while ($step >= 0) {
-                        print $ims_manifest "\n".'  </item>'."\n";
-                        $step --;
-                    }
-                }
-                $prevdepth = $depth;
-
-                my $itementry =
-              '<item identifier="ITEM-'.$env{'request.course.id'}.'-'.$count.
-              '" isvisible="'.$isvisible.'" '.$resourceref.'>'.
-              '<title>'.$curRes->title().'</title>';
-                print $ims_manifest "\n".$itementry;
-
-                if ($curRes->is_sequence()) {
-                    $currdirpath = 'Top';
-                    my $pcslist = $curRes->map_hierarchy();
-                    if ($pcslist ne '') {
-                        foreach my $pc (split(/,/,$pcslist),$curRes->map_pc()) {
-                            next if ($pc <= 1);
-                            my $res = $navmap->getByMapPc($pc);
-                            if (ref($res)) {
-                                my $encloser = $res->title();
-                                if ($encloser) {
-                                    if ($currdirpath) {
-                                        $currdirpath .= ' -> ';
-                                    }
-                                    $currdirpath .= $encloser;
-                                }
-                            }
-                        }
-                    }
-                } else {
-                    my $content_file;
-                    my @hrefs = ();
-                    &process_content($count,$curRes,$cdom,$cnum,$symb,\$content_file,\@hrefs,$copyresult,$tempexport,$format,$currdirpath,$testbank);
-                    if ($content_file) {
-                        $imsresources .= "\n".
-                     '   <resource identifier="RES-'.$env{'request.course.id'}.'-'.$count.
-                     '" type="webcontent" href="'.$content_file.'">'."\n".
-                     '       <file href="'.$content_file.'" />'."\n";
-                        foreach my $item (@hrefs) {
-                            $imsresources .=
-                     '        <file href="'.$item.'" />'."\n";
-                        }
-                        if (grep(/^$count$/,@$discussions)) {
-                            my $ressymb = $symb;
-                            my $mode;
-                            if ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) {
-                                unless ($ressymb =~ m|adm/wrapper/adm|) {
-                                    $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard';
-                                }
-                                $mode = 'board';
-                            }
-                            my %extras = (
-                                          caller => 'imsexport',
-                                          tempexport => $tempexport.'/resources',
-                                          count => $count
-                                         );
-                            my $discresult = &Apache::lonfeedback::list_discussion($mode,undef,$ressymb,\%extras);
-                        }
-                        $imsresources .= '    </resource>'."\n";
-                    }
-                }
-                $pkgdepth = $depth;
-            }
-        }
-    }
-    while ($pkgdepth > 0) {
-        print $ims_manifest "    </item>\n";
-        $pkgdepth --;
-    }
-    my $resource_text = qq|
-    </organization>
-  </organizations>
-  <resources>
-    $imsresources
-  </resources>
-</manifest>
-    |;
-    print $ims_manifest $resource_text;
-}
-
-sub get_dependencies {
-    my ($exportitems,$parent,$depth,$dependencies) = @_;
-    if ($depth > 1) {
-        if ((!grep(/^$$parent{$depth}$/,@$exportitems)) && (!grep(/^$$parent{$depth}$/,@$dependencies))) {
-            push(@{$dependencies},$$parent{$depth});
-            if ($depth > 2) {
-                &get_dependencies($exportitems,$parent,$depth-1,$dependencies);
-            }
-        }
-    }
-}
-
-sub process_content {
-    my ($count,$curRes,$cdom,$cnum,$symb,$content_file,$href,$copyresult,$tempexport,$format,$currdirpath,$testbank) = @_;
-    my $content_type;
-    my $message;
-    my @uploads = ();
-    if ($curRes->is_sequence()) {
-        $content_type = 'sequence';
-    } elsif ($curRes->is_page()) {
-        $content_type = 'page'; # need to handle individual items in pages.
-    } elsif ($symb =~ m-public/$cdom/$cnum/syllabus$-) {
-        $content_type = 'syllabus';
-        my $contents = &Apache::imsexport::templatedpage($content_type);
-        if ($contents) {
-            $$content_file = &store_template($contents,$tempexport,$count,$content_type);
-        }
-    } elsif ($symb =~ m-\.sequence___\d+___ext-) {
-        $content_type = 'external';
-        my $title = $curRes->title;
-        my $contents =  &Apache::imsexport::external($symb,$title);
-        if ($contents) {
-            $$content_file = &store_template($contents,$tempexport,$count,$content_type);
-        }
-    } elsif ($symb =~ m-adm/navmaps$-) {
-        $content_type =  'navmap';
-    } elsif ($symb =~ m-adm/[^/]+/[^/]+/(\d+)/smppg$-) {
-        $content_type = 'simplepage';
-        my $contents = &Apache::imsexport::templatedpage($content_type,$1,$count,\@uploads);
-        if ($contents) {
-            $$content_file = &store_template($contents,$tempexport,$count,$content_type);
-        }
-    } elsif ($symb =~ m-lib/templates/simpleproblem\.problem$-) {
-        $content_type = 'simpleproblem';
-        my $contents =  &Apache::imsexport::simpleproblem($symb);
-        if ($contents) {
-            $$content_file = &store_template($contents,$tempexport,$count,$content_type);
-        }
-    } elsif ($symb =~ m-lib/templates/examupload\.problem$-) {
-        $content_type = 'examupload';
-    } elsif ($symb =~ m-adm/($match_domain)/($match_username)/(\d+)/bulletinboard$-) {
-        $content_type = 'bulletinboard';
-        my $contents =  &Apache::imsexport::templatedpage($content_type,$3,$count,\@uploads,$1,$2);
-        if ($contents) {
-            $$content_file = &store_template($contents,$tempexport,$count,$content_type);
-        }
-    } elsif ($symb =~ m-adm/([^/]+)/([^/]+)/aboutme$-) {
-        $content_type = 'aboutme';
-        my $contents =  &Apache::imsexport::templatedpage($content_type,undef,$count,\@uploads,$1,$2);
-        if ($contents) {
-            $$content_file = &store_template($contents,$tempexport,$count,$content_type);
-        }
-    } elsif ($symb =~ m-\.(sequence|page)___\d+___uploaded/$cdom/$cnum/-) {
-        $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'uploaded');
-    } elsif ($symb =~ m-\.(sequence|page)___\d+___([^/]+)/([^/]+)-) {
-        my $canedit = 0;
-        if ($2 eq $env{'user.domain'} && $3 eq $env{'user.name'})  {
-            $canedit= 1;
-        }
-# only include problem code where current user is author
-        if (($format eq 'html') || ($format eq 'plaintext')) {
-            my $title = $curRes->title;
-            $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,$format,$currdirpath,$title,$testbank);
-        } elsif ($format eq 'xml') {
-            if ($canedit) {
-                $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'resource');
-            } else {
-                $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'noedit');
-            }
-        }
-    } elsif ($symb =~ m-uploaded/$cdom/$cnum-) {
-        $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'uploaded');
-    }
-    if (@uploads > 0) {
-        foreach my $item (@uploads) {
-            my $uploadmsg = '';
-            &replicate_content($cdom,$cnum,$tempexport,$item,$count,\$uploadmsg,$href,'templateupload');
-            if ($uploadmsg) {
-                $$copyresult .= $uploadmsg."\n";
-            }
-        }
-    }
-    if ($message) {
-        $$copyresult .= $message."\n";
-    }
-}
-
-sub replicate_content {
-    my ($cdom,$cnum,$tempexport,$symb,$count,$message,$href,$caller,$currdirpath,
-        $title,$testbank) = @_;
-    my ($map,$ind,$url);
-    if ($caller eq 'templateupload') {
-        $url = $symb;
-        $url =~ s#//#/#g;
-    } else {
-        ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
-    }
-    my $content;
-    my $filename;
-    my $repstatus;
-    my $content_name;
-    if ($url =~ m-/([^/]+)$-) {
-        $filename = $1;
-        if (!-e $tempexport.'/resources') {
-            mkdir($tempexport.'/resources',0700);
-        }
-        if (!-e $tempexport.'/resources/'.$count) {
-            mkdir($tempexport.'/resources/'.$count,0700);
-        }
-        my $destination = $tempexport.'/resources/'.$count.'/'.$filename;
-        my $copiedfile;
-        if ($copiedfile = Apache::File->new('>'.$destination)) {
-            my $content;
-            if ($caller eq 'resource') {
-                my $respath =  $Apache::lonnet::perlvar{'lonDocRoot'}.'/res';
-                my $filepath = &Apache::lonnet::filelocation($respath,$url);
-                $content = &Apache::lonnet::getfile($filepath);
-                if ($content eq -1) {
-                    $$message = 'Could not copy file '.$filename;
-                } else {
-                    &extract_media($url,$cdom,$cnum,\$content,$count,$tempexport,$href,$message,'resource');
-                    $repstatus = 'ok';
-                }
-            } elsif ($caller eq 'uploaded' || $caller eq 'templateupload') {
-                my $rtncode;
-                $repstatus = &Apache::lonnet::getuploaded('GET',$url,$cdom,$cnum,\$content,$rtncode);
-                if ($repstatus eq 'ok') {
-                    if ($url =~ /\.html?$/i) {
-                        &extract_media($url,$cdom,$cnum,\$content,$count,$tempexport,$href,$message,'uploaded');
-                    }
-                } else {
-                    $$message = 'Could not render '.$url.' server message - '.$rtncode."<br />\n";
-                }
-            } elsif (($caller eq 'noedit') || ($caller eq 'html') || 
-                     ($caller eq 'plaintext')) {
-# Need to render the resource without the LON-CAPA Internal header and the Post discussion footer, and then set $content equal to this.
-                my %form = (
-                             grade_symb     => $symb,
-                             grade_courseid => $cdom.'_'.$cnum,
-                             grade_domain   => $env{'user.domain'},
-                             grade_username => $env{'user.name'},
-                             grade_imsexport => 1,
-                             instructor_comments => 'hide',
-                           );
-                my $feedurl=&Apache::lonnet::clutter($url);
-                my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form);
-                if (ref($response)) {
-                    if ($response->is_success) {
-                        $content = $userview;
-                        $content =~ s/\Qonchange="javascript:setSubmittedPart('\E[^\']+\Q');"\E//g;
-                        $content =~ s/^\s*[\n\r]+$//;
-                        if ($caller eq 'plaintext') {
-                            my @lines = split(/[\n\r]+/,$content);
-                            my @tosave;
-                            my $foilcounter = 0;
-                            my @alphabet = ('a'..'z');
-                            my $mc_answer;
-                            foreach my $line (@lines) {
-                                next if ($line =~ /^\s*$/);
-                                if ($line =~ m{(|\Q<\label>\E)\Q<br />Incorrect:<label>\E}) {
-                                    $foilcounter ++;
-                                } elsif ($line =~ m{(|\Q</label>\E)\Q<br />Correct:<b><label>\E}) {
-                                    $foilcounter ++;
-                                    $mc_answer = $alphabet[$foilcounter-1];
-                                } elsif ($line !~ m{\Q</label>\E(|\Q</b>\E)\Q<br />\E}) {
-                                    $line =~ s/^(\s+|\s+)$//g;
-                                    $line =~ s{^\Q<b>\E([^<]+)\Q</b>\E$}{1};
-                                    $tosave[$foilcounter] .= $line.' ';
-                                }
-                                $content = join("\t", at tosave);
-                                if ($mc_answer) {
-                                    $content .= "\t".$mc_answer."\n";
-                                }
-                            }
-                            if (@tosave) {
-                                my $qtype;
-                                if ($mc_answer) {
-                                    $qtype = 'MC';
-                                }
-                                $content = $currdirpath."\t".$title."\t$qtype\t".join("\t", at tosave);
-                                if ($mc_answer) {
-                                    $content .= "\t".$mc_answer;
-                                } 
-                                $content .= "\n";
-                            }
-                        } else {
-                            $content = '<html><body>'.$content.'</body></html>';
-                        }
-                        if (($caller eq 'plaintext') && ($testbank)) {
-                            print $testbank $content;
-                        }
-                    } else {
-                        $content = 'Not the owner of this resource';
-                    }
-                } else {
-                    $content = 'Not the owner of this resource';
-                }
-                $repstatus = 'ok';
-            }
-            if ($repstatus eq 'ok') {
-                print $copiedfile $content;
-            }
-            close($copiedfile);
-        } else {
-            $$message = 'Could not open destination file for '.$filename."<br />\n";
-        }
-    } else {
-        $$message = 'Could not determine name of file for '.$symb."<br />\n";
-    }
-    if ($repstatus eq 'ok') {
-        $content_name = 'resources/'.$count.'/'.$filename;
-    }
-    return $content_name;
-}
-
-sub extract_media {
-    my ($url,$cdom,$cnum,$content,$count,$tempexport,$href,$message,$caller) = @_;
-    my ($dirpath,$container);
-    my %allfiles = ();
-    my %codebase = ();
-    if ($url =~ m-(.*/)([^/]+)$-) {
-        $dirpath = $1;
-        $container = $2;
-    } else {
-        $dirpath = $url;
-        $container = '';
-    }
-    &Apache::lonnet::extract_embedded_items(undef,\%allfiles,\%codebase,$content);
-    foreach my $embed_file (keys(%allfiles)) {
-        my $filename;
-        if ($embed_file =~ m#([^/]+)$#) {
-            $filename = $1;
-        } else {
-            $filename = $embed_file;
-        }
-        my $newname = 'res/'.$filename;
-        my ($rtncode,$embed_content,$repstatus);
-        my $embed_url;
-        if ($embed_file =~ m-^/-) {
-            $embed_url = $embed_file;           # points to absolute path
-        } else {
-            if ($embed_file =~ m-https?://-) {
-                next;                           # points to url
-            } else {
-                $embed_url = $dirpath.$embed_file;  # points to relative path
-            }
-        }
-        if ($caller eq 'resource') {
-            my $respath =  $Apache::lonnet::perlvar{'lonDocRoot'}.'/res';
-            my $embed_path = &Apache::lonnet::filelocation($respath,$embed_url);
-            $embed_content = &Apache::lonnet::getfile($embed_path);
-            unless ($embed_content eq -1) {
-                $repstatus = 'ok';
-            }
-        } elsif ($caller eq 'uploaded') {
-            $repstatus = &Apache::lonnet::getuploaded('GET',$embed_url,$cdom,$cnum,\$embed_content,$rtncode);
-        }
-        if ($repstatus eq 'ok') {
-            my $destination = $tempexport.'/resources/'.$count.'/res';
-            if (!-e "$destination") {
-                mkdir($destination,0755);
-            }
-            $destination .= '/'.$filename;
-            my $copiedfile;
-            if ($copiedfile = Apache::File->new('>'.$destination)) {
-                print $copiedfile $embed_content;
-                push(@{$href},'resources/'.$count.'/res/'.$filename);
-                my $attrib_regexp = '';
-                if (@{$allfiles{$embed_file}} > 1) {
-                    $attrib_regexp = join('|',@{$allfiles{$embed_file}});
-                } else {
-                    $attrib_regexp = $allfiles{$embed_file}[0];
-                }
-                $$content =~ s#($attrib_regexp\s*=\s*['"]?)\Q$embed_file\E(['"]?)#$1$newname$2#gi;
-                if ($caller eq 'resource' && $container =~ /\.(problem|library)$/) {
-                    $$content =~ s#\Q$embed_file\E#$newname#gi;
-                }
-            }
-        } else {
-            $$message .= 'replication of embedded file - '.$embed_file.' in '.$url.' failed, reason -'.$rtncode."<br />\n";
-        }
-    }
-    return;
-}
-
-sub store_template {
-    my ($contents,$tempexport,$count,$content_type) = @_;
-    if ($contents) {
-        if ($tempexport) {
-            if (!-e $tempexport.'/resources') {
-                mkdir($tempexport.'/resources',0700);
-            }
-            if (!-e $tempexport.'/resources/'.$count) {
-                mkdir($tempexport.'/resources/'.$count,0700);
-            }
-            my $destination = $tempexport.'/resources/'.$count.'/'.$content_type.'.xml';
-            my $storetemplate;
-            if ($storetemplate = Apache::File->new('>'.$destination)) {
-                print $storetemplate $contents;
-                close($storetemplate);
-            }
-            if ($content_type eq 'external') {
-                return 'resources/'.$count.'/'.$content_type.'.html';
-            } else {
-                return 'resources/'.$count.'/'.$content_type.'.xml';
-            }
-        }
-    }
-}
-
-
 sub group_import {
     my ($coursenum, $coursedom, $folder, $container, $caller, @files) = @_;
 
@@ -1567,7 +770,6 @@
 
 sub handle_edit_cmd {
     my ($coursenum,$coursedom) =@_;
-
     my ($cmd,$idx)=split('_',$env{'form.cmd'});
 
     my $ratstr = $LONCAPA::map::resources[$LONCAPA::map::order[$idx]];
@@ -2865,7 +2067,7 @@
       &dumpcourse($r);
   } elsif ($allowed && $env{'form.exportcourse'}) {
       &init_breadcrumbs('exportcourse','IMS Export');
-      &exportcourse($r);
+      &Apache::imsexport::exportcourse($r);
   } else {
 #
 # Done catching special calls
@@ -2899,6 +2101,7 @@
     my $script='';
     my $showdoc=0;
     my $addentries = {};
+    my $container;
     my $containertag;
     my $uploadtag;
 
@@ -3024,11 +2227,13 @@
 	my (@folderpath)=split('&',$env{'form.folderpath'});
 	$env{'form.foldername'}=&unescape(pop(@folderpath));
 	$env{'form.folder'}=pop(@folderpath);
+        $container='sequence';
     }
     if ($env{'form.pagepath'}) {
         my (@pagepath)=split('&',$env{'form.pagepath'});
         $env{'form.pagename'}=&unescape(pop(@pagepath));
         $env{'form.folder'}=pop(@pagepath);
+        $container='page';
         $containertag = '<input type="hidden" name="pagepath" value="" />'.
 	                '<input type="hidden" name="pagesymb" value="" />';
         $uploadtag = 
@@ -4390,22 +3595,6 @@
 
     Generate "export" button
 
-=item exportcourse()
-
-=item create_ims_store()
-
-=item build_package()
-
-=item get_dependencies()
-
-=item process_content()
-
-=item replicate_content()
-
-=item extract_media()
-
-=item store_template()
-
 =item group_import()
 
     Imports the given (name, url) resources into the course
Index: loncom/imspackages/imsexport.pm
diff -u loncom/imspackages/imsexport.pm:1.7 loncom/imspackages/imsexport.pm:1.8
--- loncom/imspackages/imsexport.pm:1.7	Fri Aug 28 17:17:25 2009
+++ loncom/imspackages/imsexport.pm	Sun Jan 29 19:51:01 2012
@@ -1,6 +1,6 @@
 # The LearningOnline Network
 #
-# $Id: imsexport.pm,v 1.7 2009/08/28 17:17:25 raeburn Exp $
+# $Id: imsexport.pm,v 1.8 2012/01/29 19:51:01 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -29,7 +29,816 @@
 
 use strict;
 use Apache::lonnet;
-use LONCAPA;
+use Apache::loncommon;
+use Apache::lonhtmlcommon;
+use Apache::lonnavmaps;
+use Apache::lonlocal;
+use Cwd;
+use LONCAPA qw(:DEFAULT :match);
+
+sub exportcourse {
+    my $r=shift;
+    my $crstype = &Apache::loncommon::course_type();
+    my %discussiontime = &Apache::lonnet::dump('discussiontimes',
+                                               $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'});
+    my $numdisc = keys(%discussiontime);
+    my $numprobs = 0;
+    my $navmap = Apache::lonnavmaps::navmap->new();
+    if (!defined($navmap)) {
+        $r->print(&Apache::loncommon::start_page('Export '.$crstype.' to IMS Package').
+                  '<h2>'.&mt('IMS Export Failed').'</h2>'.
+                  '<div class="LC_error">');
+        if ($crstype eq 'Community') {
+            $r->print(&mt('Unable to retrieve information about community contents'));
+        } else {
+            $r->print(&mt('Unable to retrieve information about course contents'));
+        }
+        $r->print('</div><a href="/adm/coursedocs">');
+        if ($crstype eq 'Community') {
+            $r->print(&mt('Return to Community Editor'));
+        } else {
+            $r->print(&mt('Return to Course Editor'));
+        }
+        $r->print('</a>');
+        &Apache::lonnet::logthis('IMS export failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
+        return;
+    }
+    my $it=$navmap->getIterator(undef,undef,undef,1,undef,undef);
+    my $curRes;
+    my $outcome;
+
+    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
+                                            ['finishexport']);
+    if ($env{'form.finishexport'}) {
+        &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
+                                            ['archive','discussion']);
+
+        my $format = $env{'form.format'};
+        my @exportitems = &Apache::loncommon::get_env_multiple('form.archive');
+        my @discussions = &Apache::loncommon::get_env_multiple('form.discussion');
+        if (@exportitems == 0 && @discussions == 0) {
+            $outcome =
+                '<p class="LC_warning">'
+               .&mt('As you did not select any content items or discussions'
+                   .' for export, an IMS package has not been created.')
+               .'</p>'
+               .'<p>'
+               .&mt('Please [_1]go back[_2] to select either content items'
+                   .' or discussions for export.'
+                       ,'<a href="javascript:history.go(-1)">'
+                       ,'</a>')
+               .'</p>';
+        } else {
+            my $now = time;
+            my %symbs;
+            my $manifestok = 0;
+            my $imsresources;
+            my $tempexport;
+            my $copyresult;
+            my $testbank;
+            my $ims_manifest = &create_ims_store($now,\$manifestok,\$outcome,\$tempexport,$format,\$testbank);
+            if ($manifestok) {
+                &build_package($now,$navmap,\@exportitems,\@discussions,\$outcome,$tempexport,\$copyresult,$ims_manifest,$format,$testbank);
+                close($ims_manifest);
+
+#Create zip file in prtspool
+                my $imszipfile = '/prtspool/'.
+                $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
+                   time.'_'.rand(1000000000).'.zip';
+                my $cwd = &Cwd::getcwd();
+                my $imszip = '/home/httpd/'.$imszipfile;
+                chdir $tempexport;
+                open(OUTPUT, "zip -r $imszip *  2> /dev/null |");
+                close(OUTPUT);
+                chdir $cwd;
+                $outcome .= '<p>'
+                           .&mt('[_1]Your IMS package[_2] is ready for download.'
+                               ,'<a href="'.$imszipfile.'">','</a>')
+                           .'</p>';
+                if ($copyresult) {
+                    $outcome .= '<p class="LC_error">'
+                               .&mt('The following errors occurred during export - [_1]'
+                                   ,$copyresult)
+                               .'</p>';
+                }
+            } else {
+                $outcome = '<p class="LC_error">'
+                          .&mt('Unfortunately you will not be able to retrieve'
+                              .' an IMS archive of your course at this time,'
+                              .' because there was a problem creating a'
+                              .' manifest file.')
+                          .'</p>'
+                          .'<p><a href="javascript:history.go(-1)">'
+                          .&mt('Go Back')
+                          .'</a></p>';
+            }
+        }
+        $r->print(&Apache::loncommon::start_page('Export '.$crstype.' to IMS Package'));
+        $r->print(&Apache::lonhtmlcommon::breadcrumbs('IMS Export'));
+        $r->print($outcome);
+        $r->print(&Apache::loncommon::end_page());
+    } else {
+        my $display='<form name="exportdoc" action="" method="post">'."\n".
+                    '<p>'.
+                    &mt('Choose which items you wish to export from your '.$crstype.'.').
+                    '</p>'.
+                    '<div class="LC_columnSection"><fieldset>'.
+                    '<legend>'.&mt('Content items').'</legend>'.
+                    '<input type="button" value="'.&mt('check all').'" '.
+                    'onclick="javascript:checkAll(document.exportdoc.archive)" />'.
+                    '  <input type="button" value="'.&mt('uncheck all').'"'.
+                    ' onclick="javascript:uncheckAll(document.exportdoc.archive)" /></fieldset>';
+        if ($numdisc > 0) {
+            $display .= '<fieldset>'.
+                        '<legend>'.&mt('Discussion posts').'</legend>'.
+                        '<input type="button" value="'.&mt('check all').'"'.
+                        ' onclick="javascript:checkAll(document.exportdoc.discussion)" />'.
+                        '  <input type="button" value="'.&mt('uncheck all').'"'.
+                        ' onclick="javascript:uncheckAll(document.exportdoc.discussion)" />'.
+                        '</fieldset>';
+        }
+        $display .= '</div>';
+        my $curRes;
+        my $depth = 0;
+        my $count = 0;
+        my $boards = 0;
+        my $startcount = 5;
+        my %parent = ();
+        my %children = ();
+        my $lastcontainer = $startcount;
+        $display .= &Apache::loncommon::start_data_table()
+                   .&Apache::loncommon::start_data_table_header_row()
+                   .'<th>'.&mt('Export content item?').'</th>';
+        if ($numdisc > 0) {
+            $display .= '<th>'.&mt('Export discussion posts?').'</th>';
+        }
+        $display .= &Apache::loncommon::end_data_table_header_row();
+        while ($curRes = $it->next()) {
+            if (ref($curRes)) {
+                $count ++;
+            }
+            if ($curRes == $it->BEGIN_MAP()) {
+                $depth++;
+                $parent{$depth} = $lastcontainer;
+            }
+            if ($curRes == $it->END_MAP()) {
+                $depth--;
+                $lastcontainer = $parent{$depth};
+            }
+            if (ref($curRes)) {
+                my $symb = $curRes->symb();
+                my $ressymb = $symb;
+                if ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) {
+                    unless ($ressymb =~ m|adm/wrapper/adm|) {
+                        $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard';
+                    }
+                }
+                my $currelem = $count+$boards+$startcount;
+                $display .= &Apache::loncommon::start_data_table_row()
+                           .'<td>'."\n"
+                           .'<input type="checkbox" name="archive" value="'.$count.'" ';
+                if (($curRes->is_sequence()) || ($curRes->is_page())) {
+                    $lastcontainer = $currelem;
+                    $display .= 'onclick="javascript:propagateCheck(this.form,'."'$currelem'".')"';
+                } elsif ($curRes->is_problem()) {
+                    $numprobs ++;
+                }
+                $display .= ' />'."\n";
+                for (my $i=0; $i<$depth; $i++) {
+                    $display .= ('<img src="/adm/lonIcons/whitespace1.gif" class="LC_docs_spacer" alt="" />' x2)."\n";
+                }
+                if ($curRes->is_sequence()) {
+                    $display .= '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" /> '."\n";
+                } elsif ($curRes->is_page()) {
+                    $display .= '<img src="/adm/lonIcons/navmap.page.open.gif" alt="" /> '."\n";
+                }
+                $children{$parent{$depth}} .= $currelem.':';
+                $display .= ' '.$curRes->title().'</td>'."\n";
+
+                # Existing discussion posts?
+                if ($discussiontime{$ressymb} > 0) {
+                    $boards ++;
+                    $display .= '<td align="right">'
+                               .'<input type="checkbox" name="discussion" value="'.$count.'" />'
+                               .'</td>'."\n";
+                } elsif ($numdisc > 0) {
+                    $display .= '<td> </td>'."\n";
+                }
+                $display .= &Apache::loncommon::end_data_table_row();
+            }
+        }
+        $display .= &Apache::loncommon::end_data_table();
+        my $numcount = $count + $boards + $startcount;
+        my $scripttag = &export_javascript($startcount,$numcount,%children);
+        $r->print(&Apache::loncommon::start_page('Export '.$crstype.' to IMS Package',
+                                                 $scripttag));
+        $r->print(&Apache::lonhtmlcommon::breadcrumbs('IMS Export'));
+        if ($numprobs > 0) {
+            $display .= '<p><span class="LC_nobreak">'.
+                        &mt('Export format for LON-CAPA problems:').
+                        '<label><input type="radio" name="format" value="xml" checked="checked" />'.
+                        ' '.&mt('XML').'</label>'.(' ' x3).
+                        '<label><input type="radio" name="format" value="html" />'.
+                        ' '.&mt('HTML').'</label>'.(' ' x3).
+                        '<label><input type="radio" name="format" value="plaintext" />'.
+                        ' '.&mt('Text').'</label></span></p>';
+        }
+        $r->print($display.
+                  '<p><input type="hidden" name="finishexport" value="1" />'.
+                  '<input type="submit" name="exportcourse" value="'.
+                  &mt('Export').'" /></p></form>');
+    }
+}
+
+sub export_javascript {
+    my ($startcount,$numitems,%children) = @_;
+    my $scripttag = <<"START";
+<script type="text/javascript">
+// <![CDATA[
+function checkAll(field) {
+    if (field.length > 0) {
+        for (i = 0; i < field.length; i++) {
+            field[i].checked = true ;
+        }
+    } else {
+        field.checked = true
+    }
+}
+
+function uncheckAll(field) {
+    if (field.length > 0) {
+        for (i = 0; i < field.length; i++) {
+            field[i].checked = false ;
+        }
+    } else {
+        field.checked = false ;
+    }
+}
+
+function propagateCheck(form,item) {
+    if (form.elements[item].checked == true) {
+        containerCheck(form,item)
+    }
+}
+
+numitems = $numitems
+var parents = new Array(numitems)
+for (var i=$startcount; i<numitems; i++) {
+    parents[i] = new Array
+}
+
+START
+
+    foreach my $container (sort { $a <=> $b } (keys(%children))) {
+        my @contents = split(/:/,$children{$container});
+        for (my $i=0; $i<@contents; $i ++) {
+            $scripttag .= 'parents['.$container.']['.$i.'] = '.$contents[$i]."\n";
+        }
+    }
+
+    $scripttag .= <<"END";
+
+function containerCheck(form,item) {
+    form.elements[item].checked = true;
+    if(Object.prototype.toString.call(parents[item]) === '[object Array]') {
+        if (parents[item].length > 0) {
+            for (var j=0; j<parents[item].length; j++) {
+                containerCheck(form,parents[item][j])
+            }
+        }
+    }
+}
+// ]]>
+</script>
+
+END
+    return $scripttag;
+}
+
+sub create_ims_store {
+    my ($now,$manifestok,$outcome,$tempexport,$format,$testbank) = @_;
+    $$tempexport = $Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/ims_exports';
+    my $ims_manifest;
+    if (!-e $$tempexport) {
+        mkdir($$tempexport,0700);
+    }
+    $$tempexport .= '/'.$now;
+    if (!-e $$tempexport) {
+        mkdir($$tempexport,0700);
+    }
+    $$tempexport .= '/'.$env{'user.domain'}.'_'.$env{'user.name'};
+    if (!-e $$tempexport) {
+        mkdir($$tempexport,0700);
+    }
+    if (!-e "$$tempexport/resources") {
+        mkdir("$$tempexport/resources",0700);
+    }
+# open manifest file
+    my $manifest = '/imsmanifest.xml';
+    my $manifestfilename = $$tempexport.$manifest;
+    if ($ims_manifest = Apache::File->new('>'.$manifestfilename)) {
+        $$manifestok=1;
+        print $ims_manifest
+'<?xml version="1.0" encoding="UTF-8"?>'."\n".
+'<manifest xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"'.
+' xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2"'.
+' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'.
+' identifier="MANIFEST-'.$env{'request.course.id'}.'-'.$now.'"'.
+'  xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1imscp_v1p1.xsd'.
+'  http://www.imsglobal.org/xsd/imsmd_v1p2 imsmd_v1p2p2.xsd">'."\n".
+'  <metadata>
+    <schema></schema>
+    <imsmd:lom>
+      <imsmd:general>
+        <imsmd:identifier>'.$env{'request.course.id'}.'</imsmd:identifier>
+        <imsmd:title>
+          <imsmd:langstring xml:lang="en">'.$env{'course.'.$env{'request.course.id'}.'.description'}.'</imsmd:langstring>
+        </imsmd:title>
+      </imsmd:general>
+    </imsmd:lom>
+  </metadata>'."\n".
+'  <organizations default="ORG-'.$env{'request.course.id'}.'-'.$now.'">'."\n".
+'    <organization identifier="ORG-'.$env{'request.course.id'}.'-'.$now.'"'.
+' structure="hierarchical">'."\n".
+'      <title>'.$env{'course.'.$env{'request.course.id'}.'.description'}.'</title>';
+        if ($format eq 'plaintext') {
+            my $testbankfilename = $$tempexport.'/testbank.txt';
+            $$testbank = Apache::File->new('>'.$testbankfilename);
+        }
+    } else {
+        $$outcome .= 'An error occurred opening the IMS manifest file.<br />'
+;
+    }
+    return $ims_manifest;
+}
+
+sub build_package {
+    my ($now,$navmap,$exportitems,$discussions,$outcome,$tempexport,$copyresult,
+        $ims_manifest,$format,$testbank) = @_;
+# first iterator to look for dependencies
+    my $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);
+    my $curRes;
+    my $count = 0;
+    my $depth = 0;
+    my $lastcontainer = 0;
+    my %parent = ();
+    my @dependencies = ();
+    my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+    my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+    while ($curRes = $it->next()) {
+        if (ref($curRes)) {
+            $count ++;
+        }
+        if ($curRes == $it->BEGIN_MAP()) {
+            $depth++;
+            $parent{$depth} = $lastcontainer;
+        }
+        if ($curRes == $it->END_MAP()) {
+            $depth--;
+            $lastcontainer = $parent{$depth};
+        }
+        if (ref($curRes)) {
+            if ($curRes->is_sequence() || $curRes->is_page()) {
+                $lastcontainer = $count;
+            }
+            if (grep(/^$count$/,@$exportitems)) {
+                &get_dependencies($exportitems,\%parent,$depth,\@dependencies);
+            }
+        }
+    }
+# second iterator to build manifest and store resources
+    $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);
+    $depth = 0;
+    my $prevdepth;
+    $count = 0;
+    my $imsresources;
+    my $pkgdepth;
+    my $currdirpath = 'Top';
+    while ($curRes = $it->next()) {
+        if ($curRes == $it->BEGIN_MAP()) {
+            $prevdepth = $depth;
+            $depth++;
+        }
+        if ($curRes == $it->END_MAP()) {
+            $prevdepth = $depth;
+            $depth--;
+        }
+
+        if (ref($curRes)) {
+            $count ++;
+            if ((grep(/^$count$/,@$exportitems)) || (grep(/^$count$/, at dependencies))) {
+                my $symb = $curRes->symb();
+                my $isvisible = 'true';
+                my $resourceref;
+                if ($curRes->randomout()) {
+                    $isvisible = 'false';
+                }
+                unless ($curRes->is_sequence()) {
+                    $resourceref = 'identifierref="RES-'.$env{'request.course.id'}.'-'.$count.'"';
+                }
+                my $step = $prevdepth - $depth;
+                if (($step >= 0) && ($count > 1)) {
+                    while ($step >= 0) {
+                        print $ims_manifest "\n".'  </item>'."\n";
+                        $step --;
+                    }
+                }
+                $prevdepth = $depth;
+
+                my $itementry =
+              '<item identifier="ITEM-'.$env{'request.course.id'}.'-'.$count.
+              '" isvisible="'.$isvisible.'" '.$resourceref.'>'.
+              '<title>'.$curRes->title().'</title>';
+                print $ims_manifest "\n".$itementry;
+
+                if ($curRes->is_sequence()) {
+                    $currdirpath = 'Top';
+                    my $pcslist = $curRes->map_hierarchy();
+                    if ($pcslist ne '') {
+                        foreach my $pc (split(/,/,$pcslist),$curRes->map_pc()) {
+                            next if ($pc <= 1);
+                            my $res = $navmap->getByMapPc($pc);
+                            if (ref($res)) {
+                                my $encloser = $res->title();
+                                if ($encloser) {
+                                    if ($currdirpath) {
+                                        $currdirpath .= ' -> ';
+                                    }
+                                    $currdirpath .= $encloser;
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    my $content_file;
+                    my @hrefs = ();
+                    &process_content($count,$curRes,$cdom,$cnum,$symb,\$content_file,\@hrefs,$copyresult,$tempexport,$format,$currdirpath,$testbank);
+                    if ($content_file) {
+                        $imsresources .= "\n".
+                     '   <resource identifier="RES-'.$env{'request.course.id'}.'-'.$count.
+                     '" type="webcontent" href="'.$content_file.'">'."\n".
+                     '       <file href="'.$content_file.'" />'."\n";
+                        foreach my $item (@hrefs) {
+                            $imsresources .=
+                     '        <file href="'.$item.'" />'."\n";
+                        }
+                        if (grep(/^$count$/,@$discussions)) {
+                            my $ressymb = $symb;
+                            my $mode;
+                            if ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) {
+                                unless ($ressymb =~ m|adm/wrapper/adm|) {
+                                    $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard';
+                                }
+                                $mode = 'board';
+                            }
+                            my %extras = (
+                                          caller => 'imsexport',
+                                          tempexport => $tempexport.'/resources',
+                                          count => $count
+                                         );
+                            my $discresult = &Apache::lonfeedback::list_discussion($mode,undef,$ressymb,\%extras);
+                        }
+                        $imsresources .= '    </resource>'."\n";
+                    }
+                }
+                $pkgdepth = $depth;
+            }
+        }
+    }
+    while ($pkgdepth > 0) {
+        print $ims_manifest "    </item>\n";
+        $pkgdepth --;
+    }
+    my $resource_text = qq|
+    </organization>
+  </organizations>
+  <resources>
+    $imsresources
+  </resources>
+</manifest>
+    |;
+    print $ims_manifest $resource_text;
+}
+
+sub get_dependencies {
+    my ($exportitems,$parent,$depth,$dependencies) = @_;
+    if ($depth > 1) {
+        if ((!grep(/^$$parent{$depth}$/,@$exportitems)) && (!grep(/^$$parent{$depth}$/,@$dependencies))) {
+            push(@{$dependencies},$$parent{$depth});
+            if ($depth > 2) {
+                &get_dependencies($exportitems,$parent,$depth-1,$dependencies);
+            }
+        }
+    }
+}
+
+sub process_content {
+    my ($count,$curRes,$cdom,$cnum,$symb,$content_file,$href,$copyresult,$tempexport,$format,$currdirpath,$testbank) = @_;
+    my $content_type;
+    my $message;
+    my @uploads = ();
+    if ($curRes->is_sequence()) {
+        $content_type = 'sequence';
+    } elsif ($curRes->is_page()) {
+        $content_type = 'page'; # need to handle individual items in pages.
+    } elsif ($symb =~ m-public/$cdom/$cnum/syllabus$-) {
+        $content_type = 'syllabus';
+        my $contents = &templatedpage($content_type);
+        if ($contents) {
+            $$content_file = &store_template($contents,$tempexport,$count,$content_type);
+        }
+    } elsif ($symb =~ m-\.sequence___\d+___ext-) {
+        $content_type = 'external';
+        my $title = $curRes->title;
+        my $contents =  &external($symb,$title);
+        if ($contents) {
+            $$content_file = &store_template($contents,$tempexport,$count,$content_type);
+        }
+    } elsif ($symb =~ m-adm/navmaps$-) {
+        $content_type =  'navmap';
+    } elsif ($symb =~ m-adm/[^/]+/[^/]+/(\d+)/smppg$-) {
+        $content_type = 'simplepage';
+        my $contents = &templatedpage($content_type,$1,$count,\@uploads);
+        if ($contents) {
+            $$content_file = &store_template($contents,$tempexport,$count,$content_type);
+        }
+    } elsif ($symb =~ m-lib/templates/simpleproblem\.problem$-) {
+        $content_type = 'simpleproblem';
+        my $contents =  &simpleproblem($symb);
+        if ($contents) {
+            $$content_file = &store_template($contents,$tempexport,$count,$content_type);
+        }
+    } elsif ($symb =~ m-lib/templates/examupload\.problem$-) {
+        $content_type = 'examupload';
+    } elsif ($symb =~ m-adm/($match_domain)/($match_username)/(\d+)/bulletinboard$-) {
+        $content_type = 'bulletinboard';
+        my $contents =  &templatedpage($content_type,$3,$count,\@uploads,$1,$2);
+        if ($contents) {
+            $$content_file = &store_template($contents,$tempexport,$count,$content_type);
+        }
+    } elsif ($symb =~ m-adm/([^/]+)/([^/]+)/aboutme$-) {
+        $content_type = 'aboutme';
+        my $contents =  &templatedpage($content_type,undef,$count,\@uploads,$1,$2);
+        if ($contents) {
+            $$content_file = &store_template($contents,$tempexport,$count,$content_type);
+        }
+    } elsif ($symb =~ m-\.(sequence|page)___\d+___uploaded/$cdom/$cnum/-) {
+        $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'uploaded');
+    } elsif ($symb =~ m-\.(sequence|page)___\d+___([^/]+)/([^/]+)-) {
+        my $canedit = 0;
+        if ($2 eq $env{'user.domain'} && $3 eq $env{'user.name'})  {
+            $canedit= 1;
+        }
+# only include problem code where current user is author
+        if (($format eq 'html') || ($format eq 'plaintext')) {
+            my $title = $curRes->title;
+            $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,$format,$currdirpath,$title,$testbank);
+        } elsif ($format eq 'xml') {
+            if ($canedit) {
+                $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'resource');
+            } else {
+                $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'noedit');
+            }
+        }
+    } elsif ($symb =~ m-uploaded/$cdom/$cnum-) {
+        $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'uploaded');
+    }
+    if (@uploads > 0) {
+        foreach my $item (@uploads) {
+            my $uploadmsg = '';
+            &replicate_content($cdom,$cnum,$tempexport,$item,$count,\$uploadmsg,$href,'templateupload');
+            if ($uploadmsg) {
+                $$copyresult .= $uploadmsg."\n";
+            }
+        }
+    }
+    if ($message) {
+        $$copyresult .= $message."\n";
+    }
+}
+
+sub replicate_content {
+    my ($cdom,$cnum,$tempexport,$symb,$count,$message,$href,$caller,$currdirpath,
+        $title,$testbank) = @_;
+    my ($map,$ind,$url);
+    if ($caller eq 'templateupload') {
+        $url = $symb;
+        $url =~ s#//#/#g;
+    } else {
+        ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
+    }
+    my $content;
+    my $filename;
+    my $repstatus;
+    my $content_name;
+    if ($url =~ m-/([^/]+)$-) {
+        $filename = $1;
+        if (!-e $tempexport.'/resources') {
+            mkdir($tempexport.'/resources',0700);
+        }
+        if (!-e $tempexport.'/resources/'.$count) {
+            mkdir($tempexport.'/resources/'.$count,0700);
+        }
+        my $destination = $tempexport.'/resources/'.$count.'/'.$filename;
+        my $copiedfile;
+        if ($copiedfile = Apache::File->new('>'.$destination)) {
+            my $content;
+            if ($caller eq 'resource') {
+                my $respath =  $Apache::lonnet::perlvar{'lonDocRoot'}.'/res';
+                my $filepath = &Apache::lonnet::filelocation($respath,$url);
+                $content = &Apache::lonnet::getfile($filepath);
+                if ($content eq -1) {
+                    $$message = 'Could not copy file '.$filename;
+                } else {
+                    &extract_media($url,$cdom,$cnum,\$content,$count,$tempexport,$href,$message,'resource');
+                    $repstatus = 'ok';
+                }
+            } elsif ($caller eq 'uploaded' || $caller eq 'templateupload') {
+                my $rtncode;
+                $repstatus = &Apache::lonnet::getuploaded('GET',$url,$cdom,$cnum,\$content,$rtncode);
+                if ($repstatus eq 'ok') {
+                    if ($url =~ /\.html?$/i) {
+                        &extract_media($url,$cdom,$cnum,\$content,$count,$tempexport,$href,$message,'uploaded');
+                    }
+                } else {
+                    $$message = 'Could not render '.$url.' server message - '.$rtncode."<br />\n";
+                }
+            } elsif (($caller eq 'noedit') || ($caller eq 'html') ||
+                     ($caller eq 'plaintext')) {
+# Need to render the resource without the LON-CAPA Internal header and the Post discussion footer, and then set $content equal to this.
+                my %form = (
+                             grade_symb     => $symb,
+                             grade_courseid => $cdom.'_'.$cnum,
+                             grade_domain   => $env{'user.domain'},
+                             grade_username => $env{'user.name'},
+                             grade_imsexport => 1,
+                             instructor_comments => 'hide',
+                           );
+                my $feedurl=&Apache::lonnet::clutter($url);
+                my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form);
+                if (ref($response)) {
+                    if ($response->is_success) {
+                        $content = $userview;
+                        $content =~ s/\Qonchange="javascript:setSubmittedPart('\E[^\']+\Q');"\E//g;
+                        $content =~ s/^\s*[\n\r]+$//;
+                        if ($caller eq 'plaintext') {
+                            my @lines = split(/[\n\r]+/,$content);
+                            my @tosave;
+                            my $foilcounter = 0;
+                            my @alphabet = ('a'..'z');
+                            my $mc_answer;
+                            foreach my $line (@lines) {
+                                next if ($line =~ /^\s*$/);
+                                if ($line =~ m{(|\Q<\label>\E)\Q<br />Incorrect:<label>\E}) {
+                                    $foilcounter ++;
+                                } elsif ($line =~ m{(|\Q</label>\E)\Q<br />Correct:<b><label>\E}) {
+                                    $foilcounter ++;
+                                    $mc_answer = $alphabet[$foilcounter-1];
+                                } elsif ($line !~ m{\Q</label>\E(|\Q</b>\E)\Q<br />\E}) {
+                                    $line =~ s/^(\s+|\s+)$//g;
+                                    $line =~ s{^\Q<b>\E([^<]+)\Q</b>\E$}{1};
+                                    $tosave[$foilcounter] .= $line.' ';
+                                }
+                                $content = join("\t", at tosave);
+                                if ($mc_answer) {
+                                    $content .= "\t".$mc_answer."\n";
+                                }
+                            }
+                            if (@tosave) {
+                                my $qtype;
+                                if ($mc_answer) {
+                                    $qtype = 'MC';
+                                }
+                                $content = $currdirpath."\t".$title."\t$qtype\t".join("\t", at tosave);
+                                if ($mc_answer) {
+                                    $content .= "\t".$mc_answer;
+                                }
+                                $content .= "\n";
+                            }
+                        } else {
+                            $content = '<html><body>'.$content.'</body></html>';
+                        }
+                        if (($caller eq 'plaintext') && ($testbank)) {
+                            print $testbank $content;
+                        }
+                    } else {
+                        $content = 'Not the owner of this resource';
+                    }
+                } else {
+                    $content = 'Not the owner of this resource';
+                }
+                $repstatus = 'ok';
+            }
+            if ($repstatus eq 'ok') {
+                print $copiedfile $content;
+            }
+            close($copiedfile);
+        } else {
+            $$message = 'Could not open destination file for '.$filename."<br />\n";
+        }
+    } else {
+        $$message = 'Could not determine name of file for '.$symb."<br />\n";
+    }
+    if ($repstatus eq 'ok') {
+        $content_name = 'resources/'.$count.'/'.$filename;
+    }
+    return $content_name;
+}
+
+sub extract_media {
+    my ($url,$cdom,$cnum,$content,$count,$tempexport,$href,$message,$caller) = @_;
+    my ($dirpath,$container);
+    my %allfiles = ();
+    my %codebase = ();
+    if ($url =~ m-(.*/)([^/]+)$-) {
+        $dirpath = $1;
+        $container = $2;
+    } else {
+        $dirpath = $url;
+        $container = '';
+    }
+    &Apache::lonnet::extract_embedded_items(undef,\%allfiles,\%codebase,$content);
+    foreach my $embed_file (keys(%allfiles)) {
+        my $filename;
+        if ($embed_file =~ m#([^/]+)$#) {
+            $filename = $1;
+        } else {
+            $filename = $embed_file;
+        }
+        my $newname = 'res/'.$filename;
+        my ($rtncode,$embed_content,$repstatus);
+        my $embed_url;
+        if ($embed_file =~ m-^/-) {
+            $embed_url = $embed_file;           # points to absolute path
+        } else {
+            if ($embed_file =~ m-https?://-) {
+                next;                           # points to url
+            } else {
+                $embed_url = $dirpath.$embed_file;  # points to relative path
+            }
+        }
+        if ($caller eq 'resource') {
+            my $respath =  $Apache::lonnet::perlvar{'lonDocRoot'}.'/res';
+            my $embed_path = &Apache::lonnet::filelocation($respath,$embed_url);
+            $embed_content = &Apache::lonnet::getfile($embed_path);
+            unless ($embed_content eq -1) {
+                $repstatus = 'ok';
+            }
+        } elsif ($caller eq 'uploaded') {
+            $repstatus = &Apache::lonnet::getuploaded('GET',$embed_url,$cdom,$cnum,\$embed_content,$rtncode);
+        }
+        if ($repstatus eq 'ok') {
+            my $destination = $tempexport.'/resources/'.$count.'/res';
+            if (!-e "$destination") {
+                mkdir($destination,0755);
+            }
+            $destination .= '/'.$filename;
+            my $copiedfile;
+            if ($copiedfile = Apache::File->new('>'.$destination)) {
+                print $copiedfile $embed_content;
+                push(@{$href},'resources/'.$count.'/res/'.$filename);
+                my $attrib_regexp = '';
+                if (@{$allfiles{$embed_file}} > 1) {
+                    $attrib_regexp = join('|',@{$allfiles{$embed_file}});
+                } else {
+                    $attrib_regexp = $allfiles{$embed_file}[0];
+                }
+                $$content =~ s#($attrib_regexp\s*=\s*['"]?)\Q$embed_file\E(['"]?)#$1$newname$2#gi;
+                if ($caller eq 'resource' && $container =~ /\.(problem|library)$/) {
+                    $$content =~ s#\Q$embed_file\E#$newname#gi;
+                }
+            }
+        } else {
+            $$message .= 'replication of embedded file - '.$embed_file.' in '.$url.' failed, reason -'.$rtncode."<br />\n";
+        }
+    }
+    return;
+}
+
+sub store_template {
+    my ($contents,$tempexport,$count,$content_type) = @_;
+    if ($contents) {
+        if ($tempexport) {
+            if (!-e $tempexport.'/resources') {
+                mkdir($tempexport.'/resources',0700);
+            }
+            if (!-e $tempexport.'/resources/'.$count) {
+                mkdir($tempexport.'/resources/'.$count,0700);
+            }
+            my $destination = $tempexport.'/resources/'.$count.'/'.$content_type.'.xml';
+            my $storetemplate;
+            if ($storetemplate = Apache::File->new('>'.$destination)) {
+                print $storetemplate $contents;
+                close($storetemplate);
+            }
+            if ($content_type eq 'external') {
+                return 'resources/'.$count.'/'.$content_type.'.html';
+            } else {
+                return 'resources/'.$count.'/'.$content_type.'.xml';
+            }
+        }
+    }
+}
 
 sub simpleproblem  {
     my ($symb) = @_;
@@ -248,3 +1057,49 @@
 }
 
 1;
+
+__END__
+
+=head1 NAME
+
+Apache::imsexport.pm
+
+=head1 SYNOPSIS
+
+This is part of the LearningOnline Network with CAPA project
+described at http://www.lon-capa.org.
+
+=head1 SUBROUTINES
+
+=over
+
+=item exportcourse()
+
+=item export_javascript()
+
+=item create_ims_store()
+
+=item build_package()
+
+=item get_dependencies()
+
+=item process_content()
+
+=item replicate_content()
+
+=item extract_media()
+
+=item store_template()
+
+=item simpleproblem()
+
+=item evaloptionhash()
+
+=item external()
+
+=item templatedpage()
+
+=back
+
+=cut
+


More information about the LON-CAPA-cvs mailing list