[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