--- loncom/publisher/lonpublisher.pm 2000/11/30 10:11:47 1.4 +++ loncom/publisher/lonpublisher.pm 2001/01/04 16:21:46 1.16 @@ -5,17 +5,110 @@ # # 05/29/00,05/30,10/11 Gerd Kortemeyer) # -# 11/28,11/29,11/30 Gerd Kortemeyer +# 11/28,11/29,11/30,12/01,12/02,12/04,12/23 Gerd Kortemeyer package Apache::lonpublisher; use strict; use Apache::File; +use File::Copy; use Apache::Constants qw(:common :http :methods); use HTML::TokeParser; use Apache::lonxml; +use Apache::structuretags; +use Apache::inputtags; +use Apache::response; my %addid; +my %nokey; +my %language; +my %cprtag; + +my %metadatafields; +my %metadatakeys; + +my $docroot; + +# ----------------------------------------------- Evaluate string with metadata + +sub metaeval { + my $metastring=shift; + + my $parser=HTML::TokeParser->new(\$metastring); + my $token; + while ($token=$parser->get_token) { + if ($token->[0] eq 'S') { + my $entry=$token->[1]; + my $unikey=$entry; + if (defined($token->[2]->{'part'})) { + $unikey.='_'.$token->[2]->{'part'}; + } + if (defined($token->[2]->{'name'})) { + $unikey.='_'.$token->[2]->{'name'}; + } + map { + $metadatafields{$unikey.'.'.$_}=$token->[2]->{$_}; + if ($metadatakeys{$unikey}) { + $metadatakeys{$unikey}.=','.$_; + } else { + $metadatakeys{$unikey}=$_; + } + } @{$token->[3]}; + if ($metadatafields{$unikey}) { + my $newentry=$parser->get_text('/'.$entry); + unless ($metadatafields{$unikey}=~/$newentry/) { + $metadatafields{$unikey}.=', '.$newentry; + } + } else { + $metadatafields{$unikey}=$parser->get_text('/'.$entry); + } + } + } +} + +# -------------------------------------------------------- Read a metadata file + +sub metaread { + my ($logfile,$fn)=@_; + unless (-e $fn) { + print $logfile 'No file '.$fn."\n"; + return '
No file: '.$fn.''; + } + print $logfile 'Processing '.$fn."\n"; + my $metastring; + { + my $metafh=Apache::File->new($fn); + $metastring=join('',<$metafh>); + } + &metaeval($metastring); + return '
Processed file: '.$fn.''; +} + +# --------------------------------------------------------- Various form fields + +sub textfield { + my ($title,$name,$value)=@_; + return "\n

$title:
". + ''; +} + +sub hiddenfield { + my ($name,$value)=@_; + return "\n".''; +} + +sub selectbox { + my ($title,$name,$value,%options)=@_; + my $selout="\n

$title:
".''; +} + +# -------------------------------------------------------- Publication Step One sub publish { @@ -24,26 +117,22 @@ sub publish { my $scrout=''; unless ($logfile=Apache::File->new('>>'.$source.'.log')) { - return 'No write permission to user directory, FAIL'; + return + 'No write permission to user directory, FAIL'; } print $logfile -"\n\n================== Publish ".localtime()." =================\n"; +"\n\n================= Publish ".localtime()." Phase One ================\n"; if (($style eq 'ssi') || ($style eq 'rat')) { # ------------------------------------------------------- This needs processing # ----------------------------------------------------------------- Backup Copy my $copyfile=$source.'.save'; - { - my $org=Apache::File->new($source); - my $cop=Apache::File->new('>'.$copyfile); - while (my $line=<$org>) { print $cop $line; } - } - if (-e $copyfile) { + if (copy($source,$copyfile)) { print $logfile "Copied original file to ".$copyfile."\n"; } else { - print $logfile "Unable to write backup ".$copyfile."\n"; - return "Failed to write backup copy, FAIL"; + print $logfile "Unable to write backup ".$copyfile.':'.$!."\n"; + return "Failed to write backup copy, $!,FAIL"; } # ------------------------------------------------------------- IDs and indices @@ -130,7 +219,8 @@ sub publish { my $org; unless ($org=Apache::File->new('>'.$source)) { print $logfile "No write permit to $source\n"; - return "No write permission to $source, FAIL"; + return + "No write permission to $source, FAIL"; } print $org $outstring; } @@ -141,14 +231,380 @@ sub publish { } else { print $logfile "Does not need ID and/or index fixup\n"; } + +# --------------------------------------------- Initial step done, now metadata + +# ---------------------------------------- Storage for metadata keys and fields + + %metadatafields=(); + %metadatakeys=(); + + my %oldparmstores=(); + +# ------------------------------------------------ First, check out environment + unless (-e $source.'.meta') { + $metadatafields{'author'}=$ENV{'environment.firstname'}.' '. + $ENV{'environment.middlename'}.' '. + $ENV{'environment.lastname'}.' '. + $ENV{'environment.generation'}; + $metadatafields{'author'}=~s/\s+/ /g; + $metadatafields{'author'}=~s/\s+$//; + $metadatafields{'owner'}=$ENV{'user.name'}.'@'.$ENV{'user.domain'}; + +# ------------------------------------------------ Check out directory hierachy + + my $thisdisfn=$source; + $thisdisfn=~s/^\/home\/$ENV{'user.name'}\///; + + my @urlparts=split(/\//,$thisdisfn); + $#urlparts--; + + my $currentpath='/home/'.$ENV{'user.name'}.'/'; + + map { + $currentpath.=$_.'/'; + $scrout.=&metaread($logfile,$currentpath.'default.meta'); + } @urlparts; + +# ------------------- Clear out parameters and stores (there should not be any) + + map { + if (($_=~/^parameter/) || ($_=~/^stores/)) { + delete $metadatafields{$_}; + } + } keys %metadatafields; + + } else { +# ---------------------- Read previous metafile, remember parameters and stores + + $scrout.=&metaread($logfile,$source.'.meta'); + + map { + if (($_=~/^parameter/) || ($_=~/^stores/)) { + $oldparmstores{$_}=1; + delete $metadatafields{$_}; + } + } keys %metadatafields; + + } + # -------------------------------------------------- Parse content for metadata - my $allmeta=Apache::lonxml::xmlparse('meta',$content); + my $allmeta=Apache::lonxml::xmlparse('meta',$content); + &metaeval($allmeta); + +# ---------------- Find and document discrepancies in the parameters and stores + + my $chparms=''; + map { + if (($_=~/^parameter/) || ($_=~/^stores/)) { + unless ($_=~/\.\w+$/) { + unless ($oldparmstores{$_}) { + print $logfile 'New: '.$_."\n"; + $chparms.=$_.' '; + } + } + } + } sort keys %metadatafields; + if ($chparms) { + $scrout.='

New parameters or stored values: '. + $chparms; + } + + my $chparms=''; + map { + if (($_=~/^parameter/) || ($_=~/^stores/)) { + unless (($metadatafields{$_.'.name'}) || ($_=~/\.\w+$/)) { + print $logfile 'Obsolete: '.$_."\n"; + $chparms.=$_.' '; + } + } + } sort keys %oldparmstores; + if ($chparms) { + $scrout.='

Obsolete parameters or stored values: '. + $chparms; + } + +# ------------------------------------------------------- Now have all metadata + + $scrout.= + '

'. + &hiddenfield('phase','two'). + &hiddenfield('filename',$ENV{'form.filename'}). + &hiddenfield('allmeta',&Apache::lonnet::escape($allmeta)). + &textfield('Title','title',$metadatafields{'title'}). + &textfield('Author(s)','author',$metadatafields{'author'}). + &textfield('Subject','subject',$metadatafields{'subject'}); + +# --------------------------------------------------- Scan content for keywords + + my $keywordout='

Keywords:
'; + my $colcount=0; - $scrout=$allmeta; + { + my $textonly=$content; + $textonly=~s/\//g; + $textonly=~s/\[^\<]+\<\/m\>//g; + $textonly=~s/\<[^\>]*\>//g; + $textonly=~tr/A-Z/a-z/; + $textonly=~s/[\$\&][a-z]\w*//g; + $textonly=~s/[^a-z\s]//g; + + my %keywords=(); + map { + unless ($nokey{$_}) { + $keywords{$_}=1; + } + } ($textonly=~m/(\w+)/g); + + map { + $keywords{$_}=1; + } split(/\W+/,$metadatafields{'keywords'}); + + map { + $keywordout.='\n"; + $colcount=0; + } + $colcount++; + } sort keys %keywords; + $keywordout.='
'; + if ($colcount>10) { + $keywordout.="
'; + + } + + $scrout.=$keywordout; + + $scrout.=&textfield('Additional Keywords','addkey',''); + + $scrout.=&textfield('Notes','notes',$metadatafields{'notes'}); + + $scrout.= + '

Abstract:
'; + + $source=~/\.(\w+)$/; + + $scrout.=&hiddenfield('mime',$1); + + $scrout.=&selectbox('Language','language', + $metadatafields{'language'},%language); + + unless ($metadatafields{'creationdate'}) { + $metadatafields{'creationdate'}=time; + } + $scrout.=&hiddenfield('creationdate',$metadatafields{'creationdate'}); + + $scrout.=&hiddenfield('lastrevisiondate',time); + + + $scrout.=&textfield('Publisher/Owner','owner', + $metadatafields{'owner'}); + + $scrout.=&selectbox('Copyright/Distribution','copyright', + $metadatafields{'copyright'},%cprtag); } - return $scrout; + return $scrout. + '

'; +} + +# -------------------------------------------------------- Publication Step Two + +sub phasetwo { + + my ($source,$target,$style)=@_; + my $logfile; + my $scrout=''; + + unless ($logfile=Apache::File->new('>>'.$source.'.log')) { + return + 'No write permission to user directory, FAIL'; + } + print $logfile +"\n================= Publish ".localtime()." Phase Two ================\n"; + + %metadatafields=(); + %metadatakeys=(); + + &metaeval(&Apache::lonnet::unescape($ENV{'form.allmeta'})); + + $metadatafields{'title'}=$ENV{'form.title'}; + $metadatafields{'author'}=$ENV{'form.author'}; + $metadatafields{'subject'}=$ENV{'form.subject'}; + $metadatafields{'notes'}=$ENV{'form.notes'}; + $metadatafields{'abstract'}=$ENV{'form.abstract'}; + $metadatafields{'mime'}=$ENV{'form.mime'}; + $metadatafields{'language'}=$ENV{'form.language'}; + $metadatafields{'creationdate'}=$ENV{'form.creationdate'}; + $metadatafields{'lastrevisiondate'}=$ENV{'form.lastrevisiondate'}; + $metadatafields{'owner'}=$ENV{'form.owner'}; + $metadatafields{'copyright'}=$ENV{'form.copyright'}; + + my $allkeywords=$ENV{'form.addkey'}; + map { + if ($_=~/^form\.key\.(\w+)/) { + $allkeywords.=','.$1; + } + } keys %ENV; + $allkeywords=~s/\W+/\,/; + $allkeywords=~s/^\,//; + $metadatafields{'keywords'}=$allkeywords; + + { + print $logfile "\nWrite metadata file for ".$source; + my $mfh; + unless ($mfh=Apache::File->new('>'.$source.'.meta')) { + return + 'Could not write metadata, FAIL'; + } + map { + unless ($_=~/\./) { + my $unikey=$_; + $unikey=~/^([A-Za-z]+)/; + my $tag=$1; + $tag=~tr/A-Z/a-z/; + print $mfh "\n\<$tag"; + map { + my $value=$metadatafields{$unikey.'.'.$_}; + $value=~s/\"/\'\'/g; + print $mfh ' '.$_.'="'.$value.'"'; + } split(/\,/,$metadatakeys{$unikey}); + print $mfh '>'.$metadatafields{$unikey}.''; + } + } sort keys %metadatafields; + $scrout.='

Wrote Metadata'; + print $logfile "\nWrote metadata"; + } + +# ----------------------------------------------------------- Copy old versions + +if (-e $target) { + my $filename; + my $maxversion=0; + $target=~/(.*)\/([^\/]+)\.(\w+)$/; + my $srcf=$2; + my $srct=$3; + my $srcd=$1; + unless ($srcd=~/^\/home\/httpd\/html\/res/) { + print $logfile "\nPANIC: Target dir is ".$srcd; + return "Invalid target directory, FAIL"; + } + opendir(DIR,$srcd); + while ($filename=readdir(DIR)) { + if ($filename=~/$srcf\.(\d+)\.$srct$/) { + $maxversion=($1>$maxversion)?$1:$maxversion; + } + } + closedir(DIR); + $maxversion++; + $scrout.='

Creating old version '.$maxversion; + print $logfile "\nCreating old version ".$maxversion; + + my $copyfile=$srcd.'/'.$srcf.'.'.$maxversion.'.'.$srct; + + if (copy($target,$copyfile)) { + print $logfile "Copied old target to ".$copyfile."\n"; + $scrout.='

Copied old target file'; + } else { + print $logfile "Unable to write ".$copyfile.':'.$!."\n"; + return "Failed to copy old target, $!, FAIL"; + } + +# --------------------------------------------------------------- Copy Metadata + + $copyfile=$copyfile.'.meta'; + + if (copy($target.'.meta',$copyfile)) { + print $logfile "Copied old target metadata to ".$copyfile."\n"; + $scrout.='

Copied old metadata'; + } else { + print $logfile "Unable to write metadata ".$copyfile.':'.$!."\n"; + if (-e $target.'.meta') { + return + "Failed to write old metadata copy, $!, FAIL"; + } + } + + +} else { + $scrout.='

Initial version'; + print $logfile "\nInitial version"; +} + +# ---------------------------------------------------------------- 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) { + print $logfile "\nCreating directory ".$path; + $scrout.='

Created directory '.$parts[$count]; + mkdir($path,0777); + } + } + + if (copy($source,$copyfile)) { + print $logfile "Copied original source to ".$copyfile."\n"; + $scrout.='

Copied source file'; + } else { + print $logfile "Unable to write ".$copyfile.':'.$!."\n"; + return "Failed to copy source, $!, FAIL"; + } + +# --------------------------------------------------------------- Copy Metadata + + $copyfile=$copyfile.'.meta'; + + if (copy($source.'.meta',$copyfile)) { + print $logfile "Copied original metadata to ".$copyfile."\n"; + $scrout.='

Copied metadata'; + } else { + print $logfile "Unable to write metadata ".$copyfile.':'.$!."\n"; + return + "Failed to write metadata copy, $!, FAIL"; + } + +# --------------------------------------------------- Send update notifications + +{ + + my $filename; + + $target=~/(.*)\/([^\/]+)$/; + my $srcf=$2; + opendir(DIR,$1); + while ($filename=readdir(DIR)) { + if ($filename=~/$srcf\.(\w+)$/) { + my $subhost=$1; + if ($subhost ne 'meta') { + $scrout.='

Notifying host '.$subhost.':'; + print $logfile "\nNotifying host '.$subhost.':'"; + my $reply=&Apache::lonnet::critical('update:'.$target,$subhost); + $scrout.=$reply; + print $logfile $reply; + } + } + } + closedir(DIR); + +} + +# ------------------------------------------------ Provide link to new resource + + my $thisdistarget=$target; + $thisdistarget=~s/^$docroot//; + + return $scrout. + '

View Target'; } # ================================================================ Main Handler @@ -162,6 +618,7 @@ sub handler { return OK; } +unless ($ENV{'form.pubdir'}) { # -------------------------------------------------------------- Check filename my $fn=$ENV{'form.filename'}; @@ -183,7 +640,7 @@ sub handler { $fn=~s/^http\:\/\/[^\/]+\/\~(\w+)/\/home\/$1\/public_html/; my $targetdir=''; - my $docroot=$r->dir_config('lonDocRoot'); + $docroot=$r->dir_config('lonDocRoot'); if ($1 ne $ENV{'user.name'}) { $r->log_reason($ENV{'user.name'}.' at '.$ENV{'user.domain'}. ' trying to publish unowned file '.$ENV{'form.filename'}. @@ -203,6 +660,8 @@ sub handler { return HTTP_NOT_FOUND; } +unless ($ENV{'form.phase'} eq 'two') { + # --------------------------------- File is there and owned, init lookup tables %addid=(); @@ -213,13 +672,48 @@ sub handler { $addid{$1}=$2; } } + + %nokey=(); + + { + my $fh=Apache::File->new($r->dir_config('lonIncludes').'/un_keyword.tab'); + map { + my $word=$_; + chomp($word); + $nokey{$word}=1; + } <$fh>; + } + + %language=(); + + { + my $fh=Apache::File->new($r->dir_config('lonTabDir').'/language.tab'); + map { + $_=~/(\w+)\s+([\w\s\-]+)/; + $language{$1}=$2; + } <$fh>; + } + + %cprtag=(); + + { + my $fh=Apache::File->new($r->dir_config('lonIncludes').'/copyright.tab'); + map { + $_=~/(\w+)\s+([\w\s\-]+)/; + $cprtag{$1}=$2; + } <$fh>; + } + +} + # ----------------------------------------------------------- Start page output $r->content_type('text/html'); $r->send_http_header; $r->print('LON-CAPA Publishing'); - $r->print(''); + $r->print( + ''); my $thisfn=$fn; # ------------------------------------------------------------- Individual file @@ -242,15 +736,66 @@ sub handler { $r->print('

Publishing '. &Apache::lonnet::filedescription($thistype).' '. $thisdisfn.'

Target: '.$thisdistarget.'

'); - + # ------------ We are publishing from $thisfn to $thistarget with $thisembstyle - $r->print('Result: '.&publish($thisfn,$thistarget,$thisembstyle)); - - } + unless ($ENV{'form.phase'} eq 'two') { + $r->print('


'.&publish($thisfn,$thistarget,$thisembstyle)); + } else { + $r->print('
'.&phasetwo($thisfn,$thistarget,$thisembstyle)); + } + } $r->print(''); +} else { + my $fn=$ENV{'form.filename'}; + + $fn=~s/\/[^\/]+$//; + my $thisprefix=$fn; + $thisprefix=~s/\/\~/\/priv\//; + + $fn=~s/^http\:\/\/[^\/]+\/\~(\w+)/\/home\/$1\/public_html/; + + unless ($fn) { + $r->log_reason($ENV{'user.name'}.' at '.$ENV{'user.domain'}. + ' trying to publish empty directory', $r->filename); + return HTTP_NOT_FOUND; + } + +# ----------------------------------------------------------- Start page output + + $r->content_type('text/html'); + $r->send_http_header; + + $r->print('LON-CAPA Publishing Directory'); + $r->print( + ''); + + my $thisdisfn=$fn; + $thisdisfn=~s/^\/home\/$ENV{'user.name'}\/public_html\///; + + $r->print('

Publishing directory '.$thisdisfn.'

'); + my $i=0; + $r->print(''); + + $r->print(''); + +} return OK; }