[LON-CAPA-cvs] cvs: doc /loncapafiles loncapafiles.lpml loncom loncapa_apache.conf loncom/interface loncommon.pm loncom/publisher lonpubdisplay.pm lonpublisher.pm
raeburn
raeburn at source.lon-capa.org
Thu Jul 31 11:15:38 EDT 2025
raeburn Thu Jul 31 15:15:38 2025 EDT
Added files:
/loncom/publisher lonpubdisplay.pm
Modified files:
/loncom/publisher lonpublisher.pm
/loncom/interface loncommon.pm
/loncom loncapa_apache.conf
/doc/loncapafiles loncapafiles.lpml
Log:
- Move handler and some routines in lonpublisher.pm to lonpubdisplay.pm
so lonpublisher.pm no longer needs Apache::Constants to facilitate calling
lonpublisher::batchpublish() outside of Apache context.
- Replace use of Apache::File with standard open()
- Copies of &url() and &display() in loncfile.pm added as &cfile_url()
and &cfile_display() in loncommon.pm, so lonpublisher.pm no longer needs
loncfile.pm (which needs Apache::Constants).
-------------- next part --------------
Index: loncom/publisher/lonpublisher.pm
diff -u loncom/publisher/lonpublisher.pm:1.309 loncom/publisher/lonpublisher.pm:1.310
--- loncom/publisher/lonpublisher.pm:1.309 Wed Jul 30 05:00:06 2025
+++ loncom/publisher/lonpublisher.pm Thu Jul 31 15:15:36 2025
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Publication Handler
#
-# $Id: lonpublisher.pm,v 1.309 2025/07/30 05:00:06 raeburn Exp $
+# $Id: lonpublisher.pm,v 1.310 2025/07/31 15:15:36 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -47,22 +47,12 @@
=head1 NAME
-lonpublisher - LON-CAPA publishing handler
+Apache::lonpublisher
=head1 SYNOPSIS
-B<lonpublisher> is used by B<mod_perl> inside B<Apache>. This is the
-invocation by F<loncapa_apache.conf>:
-
- <Location /adm/publish>
- PerlAccessHandler Apache::lonacc
- SetHandler perl-script
- PerlHandler Apache::lonpublisher
- ErrorDocument 403 /adm/login
- ErrorDocument 404 /adm/notfound.html
- ErrorDocument 406 /adm/unauthorized.html
- ErrorDocument 500 /adm/errorhandler
- </Location>
+ Utilities for publishing resources
+ Provides subroutines called by lonpubdisplay.pm
=head1 OVERVIEW
@@ -112,34 +102,21 @@
# ------------------------------------------------- modules used by this module
use strict;
-use Apache::File;
use File::Copy;
-use Apache::Constants qw(:common :http :methods);
use HTML::LCParser;
use HTML::Entities;
use Encode::Encoder;
-use Apache::lonxml;
use DBI;
use Apache::lonnet;
use Apache::loncommon();
use Apache::lonhtmlcommon;
use Apache::lonmysql;
use Apache::lonlocal;
-use Apache::loncfile;
use LONCAPA::lonmetadata;
use Apache::lonmsg;
-use vars qw(%metadatafields %metadatakeys %addid $readit);
use LONCAPA qw(:DEFAULT :match);
-
-my $docroot;
-
-my $cuname;
-my $cudom;
-my $registered_cleanup;
-my $modified_urls;
-
-my $lock;
+use vars qw(%metadatafields %metadatakeys %addid $readit $cuname $cudom $modified_urls $lock);
=pod
@@ -262,44 +239,28 @@
unless (-e $fn) {
print($logfile 'No file '.$fn."\n");
return '<p class="LC_warning">'
- .&mt('No file: [_1]',&Apache::loncfile::display($fn))
+ .&mt('No file: [_1]',
+ &Apache::loncommon::cfile_display($fn))
.'</p>';
}
print($logfile 'Processing '.$fn."\n");
my $metastring;
{
- my $metafh=Apache::File->new($fn);
- $metastring=join('',<$metafh>);
+ if (open(my $metafh,'<',$fn)) {
+ $metastring=join('',<$metafh>);
+ close($metafh);
+ }
}
&metaeval($metastring,$prefix);
return '<p class="LC_info">'
- .&mt('Processed file: [_1]',&Apache::loncfile::display($fn))
+ .&mt('Processed file: [_1]',
+ &Apache::loncommon::cfile_display($fn))
.'</p>';
}
#########################################
#########################################
-sub coursedependencies {
- my $url=&Apache::lonnet::declutter(shift);
- $url=~s/\.meta$//;
- my ($adomain,$aauthor)=($url=~ m{^($match_domain)/($match_username)/});
- my $regexp=quotemeta($url);
- $regexp='___'.$regexp.'___course';
- my %evaldata=&Apache::lonnet::dump('nohist_resevaldata',$adomain,
- $aauthor,$regexp);
- my %courses=();
- foreach my $item (keys(%evaldata)) {
- if ($item=~/^([a-zA-Z0-9]+_[a-zA-Z0-9]+)___.+___course$/) {
- $courses{$1}=1;
- }
- }
- return %courses;
-}
-#########################################
-#########################################
-
-
=pod
=item Form-field-generating subroutines.
@@ -589,8 +550,7 @@
}
}
closedir(DIR);
- my $sh;
- if ( $sh=Apache::File->new("$target.subscription") ) {
+ if (open(my $sh,'<',"$target.subscription")) {
while (my $subline=<$sh>) {
if ($subline =~ /^($match_lonid):/) {
if ($1 ne $Apache::lonnet::perlvar{'lonHostID'}) {
@@ -598,6 +558,7 @@
}
}
}
+ close($sh);
}
return @subscribed;
}
@@ -723,8 +684,10 @@
my %allow;
my $content;
{
- my $org=Apache::File->new($source);
- $content=join('',<$org>);
+ if (open(my $org,'<',$source)) {
+ $content=join('',<$org>);
+ close($org);
+ }
}
my ($needsfixup,$maxid,$maxindex,$duplicateids, at duplicatedids)=
@@ -1120,8 +1083,9 @@
my $allmeta='';
my $content='';
my %allow=();
+ my $docroot = $Apache::lonnet::perlvar{'lonDocRoot'};
- unless ($logfile=Apache::File->new('>>'.$source.'.log')) {
+ unless (open($logfile,'>>',$source.'.log')) {
return ('<span class="LC_error">'.&mt('No write permission to user directory, FAIL').'</span>',1);
}
print $logfile
@@ -1136,6 +1100,7 @@
print $logfile "Copied original file to ".$copyfile."\n";
} else {
print $logfile "Unable to write backup ".$copyfile.':'.$!."\n";
+ close($logfile);
return ("<span class=\"LC_error\">".&mt("Failed to write backup copy, [_1], FAIL",$1)."</span>",1);
}
# ------------------------------------------------------------- IDs and indices
@@ -1143,7 +1108,7 @@
my ($outstring,$error);
($outstring,$error,%allow)=&fix_ids_and_indices($logfile,$source,
$target);
- if ($error) { return ($outstring,$error); }
+ if ($error) { close($logfile); return ($outstring,$error); }
# ------------------------------------------------------------ Construct Allows
my $outdep=''; # Collect dependencies output data
@@ -1200,13 +1165,15 @@
{
my $org;
- unless ($org=Apache::File->new('>'.$source)) {
+ unless (open($org,'>',$source)) {
print $logfile "No write permit to $source\n";
+ close($logfile);
return ('<span class="LC_error">'.&mt('No write permission to').
' '.$source.
', '.&mt('FAIL').'</span>',1);
}
print($org $outstring);
+ close($org);
}
$content=$outstring;
@@ -1217,7 +1184,6 @@
if ($env{'request.course.id'}) {
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
- my $docroot = $Apache::lonnet::perlvar{'lonDocRoot'};
if ($source =~ m{^\Q$docroot/priv/$cdom/$cnum/\E}) {
$courseauthor = $cnum.':'.$cdom;
$crsaurights = "/res/$cdom/$cnum/default.rights";
@@ -1400,7 +1366,8 @@
.'</p>'
.'<p><input type="submit" value="'
.&mt('Finalize Publication')
- .'" /> <a href="'.&Apache::loncfile::url($source).'">'.&mt('Cancel').'</a></p>';
+ .'" /> <a href="'.&Apache::loncommon::cfile_url($source).'">'
+ .&mt('Cancel').'</a></p>';
}
$intr_scrout.=&Apache::lonhtmlcommon::start_pick_box();
$intr_scrout.=
@@ -1623,17 +1590,20 @@
.'" /></p>'
.'</form>';
}
+ close($logfile);
return($scrout,0);
}
sub getnokey {
my ($includedir) = @_;
my $nokey={};
- my $fh=Apache::File->new($includedir.'/un_keyword.tab');
- while (<$fh>) {
- my $word=$_;
- chomp($word);
- $nokey->{$word}=1;
+ if (open(my $fh,'<',$includedir.'/un_keyword.tab')) {
+ while (<$fh>) {
+ my $word=$_;
+ chomp($word);
+ $nokey->{$word}=1;
+ }
+ close($fh);
}
return $nokey;
}
@@ -1691,6 +1661,8 @@
my ($r,$source,$target,$style,$distarget,$batch,$usebuffer)=@_;
$source=~s/\/+/\//g;
$target=~s/\/+/\//g;
+
+ my $docroot = $Apache::lonnet::perlvar{'lonDocRoot'};
#
# Unless trying to get rid of something, check name validity
#
@@ -1744,7 +1716,7 @@
#
$distarget=~s/\/+/\//g;
my $logfile;
- unless ($logfile=Apache::File->new('>>'.$source.'.log')) {
+ unless (open($logfile,'>>',$source.'.log')) {
$output = '<span class="LC_error">'.
&mt('No write permission to user directory, FAIL').'</span>';
if ($usebuffer) {
@@ -1861,6 +1833,7 @@
unless ($file=~/\.rights$/) {
$output .= '<span class="LC_error">'.&mt('No valid custom distribution rights file specified, FAIL').
'</span>';
+ close($logfile);
if ($usebuffer) {
if (wantarray) {
return ($output,0);
@@ -1876,9 +1849,10 @@
{
print $logfile "\nWrite metadata file for ".$source;
my $mfh;
- unless ($mfh=Apache::File->new('>'.$source.'.meta')) {
+ unless (open($mfh,'>',$source.'.meta')) {
$output .= '<span class="LC_error">'.&mt('Could not write metadata, FAIL').
'</span>';
+ close($logfile);
if ($usebuffer) {
if (wantarray) {
return ($output,0);
@@ -1908,6 +1882,7 @@
}
}
+ close($mfh);
$output .= '<p>'.&mt('Wrote Metadata').'</p>';
unless ($usebuffer) {
$r->print($output);
@@ -1952,9 +1927,9 @@
my $srcf=$2;
my $srct=$3;
my $srcd=$1;
- my $docroot = $Apache::lonnet::perlvar{'lonDocRoot'};
unless ($srcd=~/^\Q$docroot\E\/res/) {
print $logfile "\nPANIC: Target dir is ".$srcd;
+ close($logfile);
$output .=
"<span class=\"LC_error\">".&mt('Invalid target directory, FAIL')."</span>";
if ($usebuffer) {
@@ -1999,6 +1974,7 @@
}
} else {
print $logfile "Unable to write ".$copyfile.':'.$!."\n";
+ close($logfile);
$output .= &Apache::lonhtmlcommon::confirm_success(&mt('Failed to copy old target').", $!",1);
if ($usebuffer) {
if (wantarray) {
@@ -2026,6 +2002,7 @@
} else {
print $logfile "Unable to write metadata ".$copyfile.':'.$!."\n";
if (-e $target.'.meta') {
+ close($logfile);
$output .= &Apache::lonhtmlcommon::confirm_success(
&mt('Failed to write old metadata copy').", $!",1);
if ($usebuffer) {
@@ -2081,6 +2058,7 @@
}
} else {
print $logfile "\nUnable to write ".$copyfile.':'.$!."\n";
+ close($logfile);
$output .= &Apache::lonhtmlcommon::confirm_success(
&mt('Failed to copy source').", $!",1);
if ($usebuffer) {
@@ -2110,6 +2088,7 @@
}
} else {
print $logfile "\nUnable to write metadata ".$copyfile.':'.$!."\n";
+ close($logfile);
$output .= &Apache::lonhtmlcommon::confirm_success(
&mt('Failed to write metadata copy').", $!",1);
if ($usebuffer) {
@@ -2129,7 +2108,6 @@
# ------------------------------------------------------------- Trigger updates
push(@{$modified_urls},[$target,$source]);
- ¬ify_in_cleanup($r);
# ---------------------------------------------------------- Clear local caches
my $thisdistarget=$target;
@@ -2139,7 +2117,7 @@
&Apache::lonnet::declutter($thisdistarget));
# ------------------------------------------------------------- Everything done
- $logfile->close();
+ close($logfile);
$output .= '<p class="LC_success">'.&mt('Done').'</p>';
unless ($usebuffer) {
$r->print($output);
@@ -2149,7 +2127,7 @@
# ------------------------------------------------ Provide link to new resource
unless ($batch) {
- my $thissrc=&Apache::loncfile::url($source);
+ my $thissrc=&Apache::loncommon::cfile_url($source);
my $thissrcdir=$thissrc;
$thissrcdir=~s/\/[^\/]+$/\//;
@@ -2185,56 +2163,6 @@
}
}
-sub notify_in_cleanup {
- my ($r) = @_;
- unless ($registered_cleanup) {
- my $handlers = $r->get_handlers('PerlCleanupHandler');
- $r->set_handlers('PerlCleanupHandler' => [\¬ify,@{$handlers}]);
- $registered_cleanup=1;
- }
-}
-
-# =============================================================== Notifications
-sub notify {
-# --------------------------------------------------- Send update notifications
- if (ref($modified_urls) eq 'ARRAY') {
- foreach my $targetsource (@{$modified_urls}){
- my ($target,$source)=@{$targetsource};
- my $logfile=Apache::File->new('>>'.$source.'.log');
- print $logfile "\nCleanup phase: Notifications\n";
- my @subscribed=&get_subscribed_hosts($target);
- foreach my $subhost (@subscribed) {
- print $logfile "\nNotifying host ".$subhost.':';
- my $reply=&Apache::lonnet::critical('update:'.$target,$subhost);
- print $logfile $reply;
- }
-# ---------------------------------------- Send update notifications, meta only
- my @subscribedmeta=&get_subscribed_hosts("$target.meta");
- foreach my $subhost (@subscribedmeta) {
- print $logfile "\nNotifying host for metadata only ".$subhost.':';
- my $reply=&Apache::lonnet::critical('update:'.$target.'.meta',
- $subhost);
- print $logfile $reply;
- }
-# --------------------------------------------------- Notify subscribed courses
- my %courses=&coursedependencies($target);
- my $now=time;
- foreach my $course (keys(%courses)) {
- print $logfile "\nNotifying course ".$course.':';
- my ($cdom,$cname)=split(/\_/,$course);
- my $reply=&Apache::lonnet::cput
- ('versionupdate',{$target => $now},$cdom,$cname);
- print $logfile $reply;
- }
- print $logfile "\n============ Done ============\n";
- $logfile->close();
- }
- $modified_urls = [];
- }
- if ($lock) { &Apache::lonnet::remove_lock($lock); }
- return OK;
-}
-
#########################################
sub batchpublish {
@@ -2244,7 +2172,12 @@
$srcfile=~s/\/+/\//g;
$targetfile=~s/\/+/\//g;
- my $docroot=$r->dir_config('lonDocRoot');
+ my $docroot;
+ if ($usebuffer) {
+ $docroot=$Apache::lonnet::perlvar{'lonDocRoot'};
+ } else {
+ $docroot=$r->dir_config('lonDocRoot');
+ }
my $thisdistarget=$targetfile;
$thisdistarget=~s/^\Q$docroot\E//;
@@ -2270,7 +2203,8 @@
my $thisembstyle=&Apache::loncommon::fileembstyle($thistype);
my $output = '<h2>'
- .&mt('Publishing [_1]',&Apache::loncfile::display($srcfile))
+ .&mt('Publishing [_1]',
+ &Apache::loncommon::cfile_display($srcfile))
.'</h2>';
unless ($usebuffer) {
$r->print($output);
@@ -2374,9 +2308,6 @@
my %commonaccess;
map { $commonaccess{$_} = 1; } &Apache::loncommon::get_env_multiple('form.commonaccess');
unless ($lock) { $lock=&Apache::lonnet::set_lock(&mt('Publishing [_1]',$fn)); }
- if ($lock) {
- ¬ify_in_cleanup($r);
- }
# actually publish things
opendir(DIR,$fn);
my @files=sort(readdir(DIR));
@@ -2478,341 +2409,6 @@
}
}
-#########################################
-# publish a default.meta file
-
-sub defaultmetapublish {
- my ($r,$fn,$cuname,$cudom)=@_;
- unless (-e $fn) {
- return HTTP_NOT_FOUND;
- }
- my $target=$fn;
- $target=~s{^\Q$Apache::lonnet::perlvar{'lonDocRoot'}\E/priv/}{$Apache::lonnet::perlvar{'lonDocRoot'}/res/};
-
-
- &Apache::loncommon::content_type($r,'text/html');
- $r->send_http_header;
-
- $r->print(&Apache::loncommon::start_page('Metadata Publication'));
-
-# ---------------------------------------------------------------- Write Source
- my $copyfile=$target;
-
- my @parts=split(/\//,$copyfile);
- my $path="/$parts[1]/$parts[2]/$parts[3]/$parts[4]";
-
- my $count;
- for ($count=5;$count<$#parts;$count++) {
- $path.="/$parts[$count]";
- if ((-e $path)!=1) {
- mkdir($path,0777);
- $r->print('<p>'
- .&mt('Created directory [_1]'
- ,'<span class="LC_filename">'.$parts[$count].'</span>')
- .'</p>'
- );
- }
- }
-
- if (copy($fn,$copyfile)) {
- $r->print('<p>'.&mt('Copied source file').'</p>');
- } else {
- $r->print('<span class="LC_error">'.
- &mt('Failed to copy source').", $!, ".&mt('FAIL').
- '</span>');
- $r->print(&Apache::loncommon::end_page());
- return OK;
- }
-
-# --------------------------------------------------- Send update notifications
-
- my @subscribed=&get_subscribed_hosts($target);
- foreach my $subhost (@subscribed) {
- $r->print('<p>'.&mt('Notifying host').' '.$subhost.':');$r->rflush;
- my $reply=&Apache::lonnet::critical('update:'.$target,$subhost);
- $r->print($reply.'</p><br />');$r->rflush;
- }
-# ------------------------------------------------------------------- Link back
- $r->print('<a href="'.&Apache::loncfile::url($fn).'">'.&mt('Back to Metadata').'</a>');
- $r->print(&Apache::loncommon::end_page());
- return OK;
-}
-#########################################
-
-=pod
-
-=item B<handler>
-
-A basic outline of the handler subroutine follows.
-
-=over 4
-
-=item *
-
-Get query string for limited number of parameters.
-
-=item *
-
-Check filename.
-
-=item *
-
-File is there and owned, init lookup tables.
-
-=item *
-
-Start page output.
-
-=item *
-
-Evaluate individual file, and then output information.
-
-=item *
-
-Publishing from $thisfn to $thistarget with $thisembstyle.
-
-=back
-
-=cut
-
-#########################################
-#########################################
-sub handler {
- my $r=shift;
-
- if ($r->header_only) {
- &Apache::loncommon::content_type($r,'text/html');
- $r->send_http_header;
- return OK;
- }
-
-# Get query string for limited number of parameters
-
- &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
- ['filename']);
-
-# -------------------------------------- Flag and buffer for registered cleanup
- $registered_cleanup=0;
- @{$modified_urls}=();
-# -------------------------------------------------------------- Check filename
-
- my $fn=&unescape($env{'form.filename'});
- ($cuname,$cudom)=&Apache::lonnet::constructaccess($fn);
-# ----------------------------------------------------- Do we have permissions?
- unless (($cuname) && ($cudom)) {
- $r->log_reason($env{'user.name'}.' at '.$env{'user.domain'}.
- ' trying to publish file '.$env{'form.filename'}.
- ' - not authorized',
- $r->filename);
- return HTTP_NOT_ACCEPTABLE;
- }
-# ----------------------------------------------------------------- Get docroot
- $docroot=$r->dir_config('lonDocRoot');
-
-
-# special publication: default.meta file
- if ($fn=~/\/default.meta$/) {
- return &defaultmetapublish($r,$docroot.$fn,$cuname,$cudom);
- }
- $fn=~s/\.meta$//;
-
-# sanity test on the filename
-
- unless ($fn) {
- $r->log_reason($cuname.' at '.$cudom.
- ' trying to publish empty filename', $r->filename);
- return HTTP_NOT_FOUND;
- }
-
- unless (-e $docroot.$fn) {
- $r->log_reason($cuname.' at '.$cudom.
- ' trying to publish non-existing file '.
- $env{'form.filename'}.' ('.$fn.')',
- $r->filename);
- return HTTP_NOT_FOUND;
- }
-
-# --------------------------------- File is there and owned, start page output
-
- &Apache::loncommon::content_type($r,'text/html');
- $r->send_http_header;
-
- # Breadcrumbs
- &Apache::lonhtmlcommon::clear_breadcrumbs();
- my $crumbtext = 'Authoring Space';
- my $crumbhref = &Apache::loncommon::authorspace($fn);
- my $crsauthor;
- if ($env{'request.course.id'}) {
- my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
- my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
- if ($crumbhref eq "/priv/$cdom/$cnum/") {
- $crumbtext = 'Course Authoring Space';
- $crsauthor = 1;
- }
- }
- &Apache::lonhtmlcommon::add_breadcrumb({
- 'text' => $crumbtext,
- 'href' => $crumbhref,
- });
- &Apache::lonhtmlcommon::add_breadcrumb({
- 'text' => 'Resource Publication',
- 'href' => '',
- });
-
- my $js='<script type="text/javascript">'.
- &Apache::loncommon::browser_and_searcher_javascript().
- '</script>';
- my $startargs = {};
- if ($fn=~/\/$/) {
- unless ($env{'form.phase'} eq 'two') {
- $startargs->{'add_entries'} = { onload => 'javascript:setDefaultAccess();' };
- $js .= <<"END";
-<script type="text/javascript">
-// <![CDATA[
-function showHideAccess(caller,div) {
- if (document.getElementById(div)) {
- if (caller.checked) {
- document.getElementById(div).style.display='inline-block';
- } else {
- document.getElementById(div).style.display='none';
- }
- }
-}
-
-function showHideCustom(caller,divid) {
- if (document.getElementById(divid)) {
- if (caller.options[caller.selectedIndex].value == 'custom') {
- document.getElementById(divid).style.display="inline-block";
- } else {
- document.getElementById(divid).style.display="none";
- }
- }
-}
-function setDefaultAccess() {
- var chkids = Array('LC_commondist','LC_commonsource');
- for (var i=0; i<chkids.length; i++) {
- if (document.getElementById(chkids[i])) {
- document.getElementById(chkids[i]).checked = false;
- }
- if (document.getElementById(chkids[i]+'select')) {
- document.getElementById(chkids[i]+'select').selectedIndex = 0;
- }
- if (document.getElementById(chkids[i]+'div')) {
- document.getElementById(chkids[i]+'div').style.display = 'none';
- }
- }
-}
-// ]]>
-</script>
-
-END
- }
- }
- $r->print(&Apache::loncommon::start_page('Resource Publication',$js,$startargs)
- .&Apache::lonhtmlcommon::breadcrumbs()
- .&Apache::loncommon::head_subbox(
- &Apache::loncommon::CSTR_pageheader($docroot.$fn))
- );
-
- my $thisdisfn=&HTML::Entities::encode($fn,'<>&"');
- my $thistarget=$fn;
- $thistarget=~s/^\/priv\//\/res\//;
- my $thisdistarget=&HTML::Entities::encode($thistarget,'<>&"');
- my $nokeyref = &getnokey($r->dir_config('lonIncludes'));
-
- if ($fn=~/\/$/) {
-# -------------------------------------------------------- This is a directory
- &publishdirectory($r,$docroot.$fn,$thisdisfn,$nokeyref,$crsauthor);
- $r->print(
- '<br /><br />'.
- &Apache::lonhtmlcommon::actionbox([
- '<a href="'.$thisdisfn.'">'.&mt('Return to Directory').'</a>']));
- } else {
-# ---------------------- Evaluate individual file, and then output information.
- $fn=~/\.(\w+)$/;
- my $thistype=$1;
- my $thisembstyle=&Apache::loncommon::fileembstyle($thistype);
- if ($thistype eq 'page') { $thisembstyle = 'rat'; }
-
- $r->print('<h2>'
- .&mt('Publishing [_1]'
- ,'<span class="LC_filename">'.$thisdisfn.'</span>')
- .'</h2>'
- );
-
- $r->print('<h3>'.&mt('Resource Details').'</h3>');
-
- $r->print(&Apache::lonhtmlcommon::start_pick_box());
-
- $r->print(&Apache::lonhtmlcommon::row_title(&mt('Type'))
- .&Apache::loncommon::filedescription($thistype)
- .&Apache::lonhtmlcommon::row_closure()
- );
-
- $r->print(&Apache::lonhtmlcommon::row_title(&mt('Link to Resource'))
- .'<tt>'
- );
- $r->print(<<ENDCAPTION);
-<a href='javascript:void(window.open("$thisdisfn","cat","height=300,width=500,scrollbars=1,resizable=1,menubar=0,location=1"))'>
-$thisdisfn</a>
-ENDCAPTION
- $r->print('</tt>'
- .&Apache::lonhtmlcommon::row_closure()
- );
-
- $r->print(&Apache::lonhtmlcommon::row_title(&mt('Target'))
- .'<tt>'.$thisdistarget.'</tt>'
- );
- if (($cuname ne $env{'user.name'})||($cudom ne $env{'user.domain'})) {
- $r->print(&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title(&mt('Co-Author'))
- .'<span class="LC_warning">'
- .&Apache::loncommon::plainname($cuname,$cudom) .' ('.$cuname.':'.$cudom.')'
- .'</span>'
- );
- }
-
- if (&Apache::loncommon::fileembstyle($thistype) eq 'ssi') {
- $r->print(&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title(&mt('Diffs')));
- $r->print(<<ENDDIFF);
-<a href='javascript:void(window.open("/adm/diff?filename=$thisdisfn&versiontwo=priv","cat","height=300,width=500,scrollbars=1,resizable=1,menubar=0,location=1"))'>
-ENDDIFF
- $r->print(&mt('Diffs with Current Version').'</a>');
- }
-
- $r->print(&Apache::lonhtmlcommon::row_closure(1)
- .&Apache::lonhtmlcommon::end_pick_box()
- );
-
-# ---------------------- Publishing from $fn to $thistarget with $thisembstyle.
-
- unless ($env{'form.phase'} eq 'two') {
-# ---------------------------------------------------------- Parse for problems
- my ($warningcount,$errorcount);
- if ($thisembstyle eq 'ssi') {
- ($warningcount,$errorcount)=&checkonthis($r,$fn);
- }
- unless ($errorcount) {
- my ($outstring,$error)=
- &publish($docroot.$fn,$docroot.$thistarget,$thisembstyle,undef,$nokeyref);
- $r->print($outstring);
- } else {
- $r->print('<h3 class="LC_error">'.
- &mt('The document contains errors and cannot be published.').
- '</h3>');
- }
- } else {
- my ($output,$error) = &phasetwo($r,$docroot.$fn,$docroot.$thistarget,
- $thisembstyle,$thisdistarget);
- $r->print($output);
- }
- }
- $r->print(&Apache::loncommon::end_page());
-
- return OK;
-}
-
BEGIN {
# ----------------------------------- Read addid.tab
@@ -2821,9 +2417,10 @@
{
my $tabdir = $Apache::lonnet::perlvar{'lonTabDir'};
- my $fh=Apache::File->new($tabdir.'/addid.tab');
- while (<$fh>=~/(\w+)\s+(\w+)/) {
- $addid{$1}=$2;
+ if (open(my $fh,'<',$tabdir.'/addid.tab')) {
+ while (<$fh>=~/(\w+)\s+(\w+)/) {
+ $addid{$1}=$2;
+ }
}
}
}
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1478 loncom/interface/loncommon.pm:1.1479
--- loncom/interface/loncommon.pm:1.1478 Sat Jun 28 14:34:46 2025
+++ loncom/interface/loncommon.pm Thu Jul 31 15:15:37 2025
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common routines
#
-# $Id: loncommon.pm,v 1.1478 2025/06/28 14:34:46 raeburn Exp $
+# $Id: loncommon.pm,v 1.1479 2025/07/31 15:15:37 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -6817,6 +6817,27 @@
return %editors;
}
+sub cfile_url {
+ my ($fn,$context) = @_;
+ my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
+ $fn=~ s/^\Q$londocroot\E//;
+ $fn=~s{/\./}{/}g;
+ if ($context eq 'js') {
+ &js_escape(\$fn);
+ } else {
+ $fn=&HTML::Entities::encode($fn,'\'<>"&');
+ }
+ return $fn;
+}
+
+sub cfile_display {
+ my $fn=shift;
+ my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
+ $fn=~s/^\Q$londocroot\E//;
+ $fn=~s{/\./}{/}g;
+ return '<span class="LC_filename">'.$fn.'</span>';
+}
+
###############################################
###############################################
Index: loncom/loncapa_apache.conf
diff -u loncom/loncapa_apache.conf:1.286 loncom/loncapa_apache.conf:1.287
--- loncom/loncapa_apache.conf:1.286 Mon Jan 8 02:23:45 2024
+++ loncom/loncapa_apache.conf Thu Jul 31 15:15:37 2025
@@ -2,7 +2,7 @@
## loncapa_apache.conf -- Apache HTTP LON-CAPA configuration file
##
-# $Id: loncapa_apache.conf,v 1.286 2024/01/08 02:23:45 raeburn Exp $
+# $Id: loncapa_apache.conf,v 1.287 2025/07/31 15:15:37 raeburn Exp $
#
# LON-CAPA Section (extensions to httpd.conf daemon configuration)
@@ -1149,7 +1149,7 @@
Require valid-user
PerlAuthzHandler Apache::lonacc
SetHandler perl-script
-PerlHandler Apache::lonpublisher
+PerlHandler Apache::lonpubdisplay
ErrorDocument 403 /adm/login
ErrorDocument 404 /adm/notfound.html
ErrorDocument 406 /adm/unauthorized
Index: doc/loncapafiles/loncapafiles.lpml
diff -u doc/loncapafiles/loncapafiles.lpml:1.1077 doc/loncapafiles/loncapafiles.lpml:1.1078
--- doc/loncapafiles/loncapafiles.lpml:1.1077 Sun Jun 15 23:49:47 2025
+++ doc/loncapafiles/loncapafiles.lpml Thu Jul 31 15:15:38 2025
@@ -2,7 +2,7 @@
"http://lpml.sourceforge.net/DTD/lpml.dtd">
<!-- loncapafiles.lpml -->
-<!-- $Id: loncapafiles.lpml,v 1.1077 2025/06/15 23:49:47 raeburn Exp $ -->
+<!-- $Id: loncapafiles.lpml,v 1.1078 2025/07/31 15:15:38 raeburn Exp $ -->
<!--
@@ -6028,11 +6028,23 @@
</dependencies>
</file>
<file>
+<source>loncom/publisher/lonpubdisplay.pm</source>
+<target dist='default'>home/httpd/lib/perl/Apache/lonpubdisplay.pm</target>
+<categoryname>handler</categoryname>
+<description>
+Handler for publishing a LON-CAPA educational resource complete with metadata
+(authorship, language, copyright, creation date, etc). Uses subroutines and
+package variables in lonpublisher.pm
+</description>
+<status>works/unverified</status>
+</file>
+<file>
<source>loncom/publisher/lonpublisher.pm</source>
<target dist='default'>home/httpd/lib/perl/Apache/lonpublisher.pm</target>
<categoryname>handler</categoryname>
<description>
-Publishes an LON-CAPA educational resource complete with metadata
+Subroutines and package variables used by lonpubdisplay.pm to publish
+a LON-CAPA educational resource complete with metadata
(authorship, language, copyright, creation date, etc).
</description>
<status>works/unverified</status>
Index: loncom/publisher/lonpubdisplay.pm
+++ loncom/publisher/lonpubdisplay.pm
# The LearningOnline Network with CAPA
# Publication Handler
#
# $Id: lonpubdisplay.pm,v 1.1 2025/07/31 15:15:36 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
###
=pod
=head1 NAME
lonpubdisplay - LON-CAPA publishing handler
=head1 SYNOPSIS
B<lonpubdisplay> is used by B<mod_perl> inside B<Apache>. This is the
invocation by F<loncapa_apache.conf>:
<Location /adm/publish>
PerlAccessHandler Apache::lonacc
SetHandler perl-script
PerlHandler Apache::lonpubdisplay
ErrorDocument 403 /adm/login
ErrorDocument 404 /adm/notfound.html
ErrorDocument 406 /adm/unauthorized.html
ErrorDocument 500 /adm/errorhandler
</Location>
=head1 OVERVIEW
Authors can only write-access the C</priv/domain/authorname/> space.
They can copy resources into the resource area through the
publication step, and move them back through a recover step.
Authors do not have direct write-access to their resource space.
=head1 DESCRIPTION
B<lonpubdisplay>
=head2 SUBROUTINES
=cut
######################################################################
######################################################################
package Apache::lonpubdisplay;
# ------------------------------------------------- modules used by this module
use strict;
use File::Copy;
use HTML::Entities;
use Apache::Constants qw(:common :http :methods);
use Apache::lonnet;
use Apache::loncommon();
use Apache::lonhtmlcommon;
use Apache::lonpublisher;
use Apache::loncfile;
use Apache::lonlocal;
use LONCAPA qw(:DEFAULT :match);
my $registered_cleanup;
#########################################
=pod
=item B<handler>
A basic outline of the handler subroutine follows.
=over 4
=item *
Get query string for limited number of parameters.
=item *
Check filename.
=item *
File is there and owned, init lookup tables.
=item *
Start page output.
=item *
Evaluate individual file, and then output information.
=item *
Publishing from $thisfn to $thistarget with $thisembstyle.
=back
=cut
#########################################
#########################################
sub coursedependencies {
my $url=&Apache::lonnet::declutter(shift);
$url=~s/\.meta$//;
my ($adomain,$aauthor)=($url=~ m{^($match_domain)/($match_username)/});
my $regexp=quotemeta($url);
$regexp='___'.$regexp.'___course';
my %evaldata=&Apache::lonnet::dump('nohist_resevaldata',$adomain,
$aauthor,$regexp);
my %courses=();
foreach my $item (keys(%evaldata)) {
if ($item=~/^([a-zA-Z0-9]+_[a-zA-Z0-9]+)___.+___course$/) {
$courses{$1}=1;
}
}
return %courses;
}
sub notify_in_cleanup {
my ($r) = @_;
unless ($registered_cleanup) {
my $handlers = $r->get_handlers('PerlCleanupHandler');
$r->set_handlers('PerlCleanupHandler' => [\¬ify,@{$handlers}]);
$registered_cleanup=1;
}
}
# =============================================================== Notifications
sub notify {
# --------------------------------------------------- Send update notifications
if (ref($Apache::lonpublisher::modified_urls) eq 'ARRAY') {
foreach my $targetsource (@{$Apache::lonpublisher::modified_urls}){
my ($target,$source)=@{$targetsource};
my ($logfile,$canlog);
if (open($logfile,'>>',$source.'.log')) {
$canlog = 1;
}
print $logfile "\nCleanup phase: Notifications\n" if ($canlog);
my @subscribed=&Apache::lonpublisher::get_subscribed_hosts($target);
foreach my $subhost (@subscribed) {
print $logfile "\nNotifying host ".$subhost.':' if ($canlog);
my $reply=&Apache::lonnet::critical('update:'.$target,$subhost);
print $logfile $reply if ($canlog);
}
# ---------------------------------------- Send update notifications, meta only
my @subscribedmeta=&Apache::lonpublisher::get_subscribed_hosts("$target.meta");
foreach my $subhost (@subscribedmeta) {
print $logfile "\nNotifying host for metadata only ".$subhost.':' if ($canlog);
my $reply=&Apache::lonnet::critical('update:'.$target.'.meta',
$subhost);
print $logfile $reply if ($canlog);
}
# --------------------------------------------------- Notify subscribed courses
my %courses=&coursedependencies($target);
my $now=time;
foreach my $course (keys(%courses)) {
print $logfile "\nNotifying course ".$course.':' if ($canlog);
my ($cdom,$cname)=split(/\_/,$course);
my $reply=&Apache::lonnet::cput
('versionupdate',{$target => $now},$cdom,$cname);
print $logfile $reply if ($canlog);
}
if ($canlog) {
print $logfile "\n============ Done ============\n";
close($logfile);
}
}
$Apache::lonpublisher::modified_urls = [];
}
if ($Apache::lonpublisher::lock) { &Apache::lonnet::remove_lock($Apache::lonpublisher::lock); }
return OK;
}
#########################################
# publish a default.meta file
sub defaultmetapublish {
my ($r,$fn,$cuname,$cudom)=@_;
unless (-e $fn) {
return HTTP_NOT_FOUND;
}
my $target=$fn;
$target=~s/^\Q$Apache::lonnet::perlvar{'lonDocRoot'}\E\/priv\//\Q$Apache::lonnet::perlvar{'lonDocRoot'}\E\/res\//;
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
$r->print(&Apache::loncommon::start_page('Metadata Publication'));
# ---------------------------------------------------------------- Write Source
my $copyfile=$target;
my @parts=split(/\//,$copyfile);
my $path="/$parts[1]/$parts[2]/$parts[3]/$parts[4]";
my $count;
for ($count=5;$count<$#parts;$count++) {
$path.="/$parts[$count]";
if ((-e $path)!=1) {
mkdir($path,0777);
$r->print('<p>'
.&mt('Created directory [_1]'
,'<span class="LC_filename">'.$parts[$count].'</span>')
.'</p>'
);
}
}
if (copy($fn,$copyfile)) {
$r->print('<p>'.&mt('Copied source file').'</p>');
} else {
$r->print("<span class=\"LC_error\">".
&mt('Failed to copy source').", $!, ".&mt('FAIL').
"</span>");
$r->print(&Apache::loncommon::end_page());
return OK;
}
# --------------------------------------------------- Send update notifications
my @subscribed=&Apache::lonpublisher::get_subscribed_hosts($target);
foreach my $subhost (@subscribed) {
$r->print('<p>'.&mt('Notifying host').' '.$subhost.':');$r->rflush;
my $reply=&Apache::lonnet::critical('update:'.$target,$subhost);
$r->print($reply.'</p><br />');$r->rflush;
}
# ------------------------------------------------------------------- Link back
$r->print("<a href='".&Apache::loncfile::display($fn)."'>".&mt('Back to Metadata').'</a>');
$r->print(&Apache::loncommon::end_page());
return OK;
}
sub reset_globals {
$Apache::lonpublisher::cuname = '';
$Apache::lonpublisher::cudom = '';
%Apache::lonpublisher::metadatafields = ();
%Apache::lonpublisher::metadatakeys = ();
@{$Apache::lonpublisher::modified_urls} = ();
}
#########################################
#########################################
sub handler {
my $r=shift;
if ($r->header_only) {
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
return OK;
}
# Initialize globals in Apache::lonpublisher
&reset_globals();
# Get query string for limited number of parameters
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
['filename']);
# -------------------------------------- Flag and buffer for registered cleanup
$registered_cleanup=0;
@{$Apache::lonpublisher::modified_urls}=();
# -------------------------------------------------------------- Check filename
my $fn=&unescape($env{'form.filename'});
my ($cuname,$cudom) =
&Apache::lonnet::constructaccess($fn);
# ----------------------------------------------------- Do we have permissions?
unless (($cuname) && ($cudom)) {
$r->log_reason($env{'user.name'}.' at '.$env{'user.domain'}.
' trying to publish file '.$env{'form.filename'}.
' - not authorized',
$r->filename);
return HTTP_NOT_ACCEPTABLE;
}
# ----------------------------------------------------------------- Get docroot
my $docroot=$r->dir_config('lonDocRoot');
# special publication: default.meta file
if ($fn=~/\/default.meta$/) {
return &defaultmetapublish($r,$fn,$cuname,$cudom);
}
# set values for cuname and cudom globals in Apache::lonpublisher
$Apache::lonpublisher::cuname = $cuname;
$Apache::lonpublisher::cudom = $cudom;
$fn=~s/\.meta$//;
# sanity test on the filename
unless ($fn) {
$r->log_reason($cuname.' at '.$cudom.
' trying to publish empty filename', $r->filename);
&reset_globals();
return HTTP_NOT_FOUND;
}
unless (-e $docroot.$fn) {
$r->log_reason($cuname.' at '.$cudom.
' trying to publish non-existing file '.
$env{'form.filename'}.' ('.$fn.')',
$r->filename);
&reset_globals();
return HTTP_NOT_FOUND;
}
# --------------------------------- File is there and owned, start page output
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
# Breadcrumbs
&Apache::lonhtmlcommon::clear_breadcrumbs();
my $crumbtext = 'Authoring Space';
my $crumbhref = &Apache::loncommon::authorspace($fn);
my $crsauthor;
if ($env{'request.course.id'}) {
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
if ($crumbhref eq "/priv/$cdom/$cnum/") {
$crumbtext = 'Course Authoring Space';
$crsauthor = 1;
}
}
&Apache::lonhtmlcommon::add_breadcrumb({
'text' => $crumbtext,
'href' => $crumbhref,
});
&Apache::lonhtmlcommon::add_breadcrumb({
'text' => 'Resource Publication',
'href' => '',
});
my $js='<script type="text/javascript">'.
&Apache::loncommon::browser_and_searcher_javascript().
'</script>';
my $startargs = {};
if ($fn=~/\/$/) {
unless ($env{'form.phase'} eq 'two') {
$startargs->{'add_entries'} = { onload => 'javascript:setDefaultAccess();' };
$js .= <<"END";
<script type="text/javascript">
// <![CDATA[
function showHideAccess(caller,div) {
if (document.getElementById(div)) {
if (caller.checked) {
document.getElementById(div).style.display='inline-block';
} else {
document.getElementById(div).style.display='none';
}
}
}
function showHideCustom(caller,divid) {
if (document.getElementById(divid)) {
if (caller.options[caller.selectedIndex].value == 'custom') {
document.getElementById(divid).style.display="inline-block";
} else {
document.getElementById(divid).style.display="none";
}
}
}
function setDefaultAccess() {
var chkids = Array('LC_commondist','LC_commonsource');
for (var i=0; i<chkids.length; i++) {
if (document.getElementById(chkids[i])) {
document.getElementById(chkids[i]).checked = false;
}
if (document.getElementById(chkids[i]+'select')) {
document.getElementById(chkids[i]+'select').selectedIndex = 0;
}
if (document.getElementById(chkids[i]+'div')) {
document.getElementById(chkids[i]+'div').style.display = 'none';
}
}
}
// ]]>
</script>
END
}
}
$r->print(&Apache::loncommon::start_page('Resource Publication',$js,$startargs)
.&Apache::lonhtmlcommon::breadcrumbs()
.&Apache::loncommon::head_subbox(
&Apache::loncommon::CSTR_pageheader($docroot.$fn))
);
my $thisdisfn=&HTML::Entities::encode($fn,'<>&"');
my $thistarget=$fn;
$thistarget=~s/^\/priv\//\/res\//;
my $thisdistarget=&HTML::Entities::encode($thistarget,'<>&"');
my $nokeyref = &Apache::lonpublisher::getnokey($r->dir_config('lonIncludes'));
if ($fn=~/\/$/) {
# -------------------------------------------------------- This is a directory
&Apache::lonpublisher::publishdirectory($r,$docroot.$fn,$thisdisfn,$nokeyref,$crsauthor);
if ($Apache::lonpublisher::lock) {
¬ify_in_cleanup($r);
}
$r->print(
'<br /><br />'.
&Apache::lonhtmlcommon::actionbox([
'<a href="'.$thisdisfn.'">'.&mt('Return to Directory').'</a>']));
} else {
# ---------------------- Evaluate individual file, and then output information.
$fn=~/\.(\w+)$/;
my $thistype=$1;
my $thisembstyle=&Apache::loncommon::fileembstyle($thistype);
if ($thistype eq 'page') { $thisembstyle = 'rat'; }
$r->print('<h2>'
.&mt('Publishing [_1]'
,'<span class="LC_filename">'.$thisdisfn.'</span>')
.'</h2>'
);
$r->print('<h3>'.&mt('Resource Details').'</h3>');
$r->print(&Apache::lonhtmlcommon::start_pick_box());
$r->print(&Apache::lonhtmlcommon::row_title(&mt('Type'))
.&Apache::loncommon::filedescription($thistype)
.&Apache::lonhtmlcommon::row_closure()
);
$r->print(&Apache::lonhtmlcommon::row_title(&mt('Link to Resource'))
.'<tt>'
);
$r->print(<<ENDCAPTION);
<a href='javascript:void(window.open("$thisdisfn","cat","height=300,width=500,scrollbars=1,resizable=1,menubar=0,location=1"))'>
$thisdisfn</a>
ENDCAPTION
$r->print('</tt>'
.&Apache::lonhtmlcommon::row_closure()
);
$r->print(&Apache::lonhtmlcommon::row_title(&mt('Target'))
.'<tt>'.$thisdistarget.'</tt>'
);
if (($cuname ne $env{'user.name'})||($cudom ne $env{'user.domain'})) {
$r->print(&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_title(&mt('Co-Author'))
.'<span class="LC_warning">'
.&Apache::loncommon::plainname($cuname,$cudom) .' ('.$cuname.':'.$cudom.')'
.'</span>'
);
}
if (&Apache::loncommon::fileembstyle($thistype) eq 'ssi') {
$r->print(&Apache::lonhtmlcommon::row_closure()
.&Apache::lonhtmlcommon::row_title(&mt('Diffs')));
$r->print(<<ENDDIFF);
<a href='javascript:void(window.open("/adm/diff?filename=$thisdisfn&versiontwo=priv","cat","height=300,width=500,scrollbars=1,resizable=1,menubar=0,location=1"))'>
ENDDIFF
$r->print(&mt('Diffs with Current Version').'</a>');
}
$r->print(&Apache::lonhtmlcommon::row_closure(1)
.&Apache::lonhtmlcommon::end_pick_box()
);
# ---------------------- Publishing from $fn to $thistarget with $thisembstyle.
unless ($env{'form.phase'} eq 'two') {
# ---------------------------------------------------------- Parse for problems
my ($warningcount,$errorcount);
if ($thisembstyle eq 'ssi') {
($warningcount,$errorcount)=&Apache::lonpublisher::checkonthis($r,$fn);
}
unless ($errorcount) {
my ($outstring,$error)=
&Apache::lonpublisher::publish($docroot.$fn,$docroot.$thistarget,
$thisembstyle,undef,$nokeyref);
$r->print($outstring);
} else {
$r->print('<h3 class="LC_error">'.
&mt('The document contains errors and cannot be published.').
'</h3>');
}
} else {
my ($output,$error) =
&Apache::lonpublisher::phasetwo($r,$docroot.$fn,$docroot.$thistarget,
$thisembstyle,$thisdistarget);
$r->print($output);
# ------------------------------------------------------------- Trigger updates
if (@{$Apache::lonpublisher::modified_urls}) {
¬ify_in_cleanup($r);
}
}
}
$r->print(&Apache::loncommon::end_page());
&reset_globals();
return OK;
}
BEGIN {
# ----------------------------------- Read addid.tab
unless ($Apache::lonpublisher::readit) {
%Apache::lonpublisher::addid=();
{
my $tabdir = $Apache::lonnet::perlvar{'lonTabDir'};
if (open(my $fh,'<',$tabdir.'/addid.tab')) {
while (<$fh>=~/(\w+)\s+(\w+)/) {
$Apache::lonpublisher::addid{$1}=$2;
}
close($fh);
}
}
}
$Apache::lonpublisher::readit=1;
}
1;
More information about the LON-CAPA-cvs
mailing list