Skip to content

Commit

Permalink
Item14547: more enhancements
Browse files Browse the repository at this point in the history
- docu
- new redirect param
- allow to export old revisions
- only rewrite links part of the publish set
  • Loading branch information
MichaelDaum committed Jan 25, 2018
1 parent 2efd93b commit 088e876
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 82 deletions.
45 changes: 38 additions & 7 deletions data/System/ExportPlugin.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,44 @@
%META:TOPICINFO{author="ProjectContributor" date="1263951431" format="1.1" reprev="1.1" version="1"}%
%META:TOPICINFO{author="ProjectContributor" comment="" date="1516888080" format="1.1" version="1"}%
---+!! %TOPIC%
%FORMFIELD{"Description"}%

%TOC%

---++ Usage

Use =./rest /ExportPlugin/html= to generate an HTML export, =./rest /ExportPlugin/pdf= for a PDF export

These handlers can either be called by the browser or on the command line. Note that an export might take
a considerable amount of time to be performed, i.e. when specifying =forceupdate=on=. A browser request
might likely time out then without while the process keeps running on the server side until finished.

| *Parameters* | *Description* | *Default* |
| topics | comma separated list of topics to be published; each list item can be of the format =<web>.<topic>=<rev>=, where =web= and =rev= is optional | current topic |
| debug | boolean | off |
| web | web to be exported | current web |
| webs | set of webs to be exported | current web |
| includeweb | regex of webs to be exported | |
| excludeweb | regex of webs not to be exported | |
| include | regex of topics to be exported | |
| exclude | regex of topics not to be exported | |
| forceupdate | boolean to skip checking for already existant exports; export is incremental otherwise updating things that changed since the last call | off |
| limit | maximum number of topics to be exported | all |
| redirect | boolean flag to redirect the browser to the newly created asset | off |
| skin, cover, etc | any other url parameter is forwarded to the generated page | |

---++ Examples

%BUTTON{"Export to PDF"
icon="fa-file-pdf-o"
href="%SCRIPTURLPATH{"rest"}%/ExportPlugin/pdf?topic=%WEB%.%TOPIC%&redirect=on&cover=print.nat"
}%

%BUTTON{"Export to HTML"
icon="fa-file-o"
href="%SCRIPTURLPATH{"rest"}%/ExportPlugin/html?topic=%WEB%.%TOPIC%&redirect=on&cover=print.nat"
}%


---++ Installation Instructions

%$INSTALL_INSTRUCTIONS%
Expand All @@ -19,11 +50,11 @@

%META:FORM{name="PackageForm"}%
%META:FIELD{name="Author" title="Author" value="Michael Daum"}%
%META:FIELD{name="Copyright" title="Copyright" value="© 2017 Michael Daum http://michaeldaumconsulting.com"}%
%META:FIELD{name="Version" title="Version" value="%25$VERSION%25"}%
%META:FIELD{name="Release" title="Release" value="%25$RELEASE%25"}%
%META:FIELD{name="Description" title="Description" value="%25$SHORTDESCRIPTION%25"}%
%META:FIELD{name="Home" title="Home" value="Foswiki:Extensions/%TOPIC%"}%
%META:FIELD{name="Repository" title="Repository" value="https://github.com/foswiki/%25TOPIC%25"}%
%META:FIELD{name="Copyright" title="Copyright" value="© 2017-2018 Michael Daum http://michaeldaumconsulting.com"}%
%META:FIELD{name="License" title="License" value="[[http://www.gnu.org/licenses/gpl.html][GPL (Gnu General Public License)]]"}%
%META:FIELD{name="Release" title="Release" value="%$RELEASE%"}%
%META:FIELD{name="Repository" title="Repository" value="https://github.com/foswiki/%TOPIC%"}%
%META:FIELD{name="Support" title="Support" value="Foswiki:Support/%TOPIC%"}%
%META:FIELD{name="Version" title="Version" value="%$VERSION%"}%
%META:FIELD{name="Home" title="Home" value="Foswiki:Extensions/%25TOPIC%25"}%
%META:FIELD{name="Support" title="Support" value="Foswiki:Support/%25TOPIC%25"}%
6 changes: 3 additions & 3 deletions lib/Foswiki/Plugins/ExportPlugin.pm
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Plugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/
#
# ExportPlugin is Copyright (C) 2017 Michael Daum http://michaeldaumconsulting.com
# ExportPlugin is Copyright (C) 2017-2018 Michael Daum http://michaeldaumconsulting.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
Expand All @@ -21,8 +21,8 @@ use warnings;
use Foswiki::Func ();
use Foswiki::Contrib::JsonRpcContrib ();

our $VERSION = '0.03';
our $RELEASE = '01 Dec 2017';
our $VERSION = '0.04';
our $RELEASE = '25 Jan 2018';
our $SHORTDESCRIPTION = 'Export wiki content in various formats';
our $NO_PREFS_IN_TOPIC = 1;

Expand Down
140 changes: 100 additions & 40 deletions lib/Foswiki/Plugins/ExportPlugin/Exporter.pm
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Plugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/
#
# ExportPlugin is Copyright (C) 2017 Michael Daum http://michaeldaumconsulting.com
# ExportPlugin is Copyright (C) 2017-2018 Michael Daum http://michaeldaumconsulting.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
Expand Down Expand Up @@ -179,9 +179,14 @@ sub export {
}
}


#$this->writeDebug("exporting took ".$this->getElapsedTime($this->{startTime}));

if (Foswiki::Func::isTrue($this->param("redirect"), 0)) {
$this->writeDebug("redirecting to $result");
my $request = Foswiki::Func::getRequestObject();
Foswiki::Func::redirectCgiQuery($request, $result);
}

return $result;
}

Expand All @@ -195,69 +200,70 @@ sub exportTopics {
@$topics = grep {/$include/} @$topics if defined $include;
@$topics = grep {!/$exclude/} @$topics if defined $exclude;

@$topics = grep {
Foswiki::Func::topicExists($web, $_) ? 1: $this->writeWarning("woops, topic $web.$_ does not exist") && 0;
} @$topics;

my $i = 0;
my $limit = $this->param("limit") || 0;
if ($limit) {
@$topics = splice(@$topics, 0, $limit);
}

my $publishSet = $this->publishSet($web, $topics);

my $len = scalar(@$topics);
$this->writeDebug("exporting $len topic(s)");

# capture main session running the rest handler
my $mainSession = $Foswiki::Plugins::SESSION;

foreach my $topic (@$topics) {
foreach my $item (@$publishSet) {
$i++ ;
my ($thisWeb, $thisTopic) = Foswiki::Func::normalizeWebTopicName($web ,$topic);

my $src = $Foswiki::cfg{DataDir}.'/'.$thisWeb.'/'.$thisTopic.'.txt';
my $dst = $this->getTargetPath($thisWeb, $thisTopic);
my $src = $Foswiki::cfg{DataDir}.'/'.$item->{web}.'/'.$item->{topic}.'.txt';
my $dst = $this->getTargetPath($item->{web}, $item->{topic}, $item->{rev});

unless ($forceUpdate) {
my $mtimeSrc = (stat $src)[9] || 0;
my $mtimeDst = (stat $dst)[9] || 0;

if ($mtimeSrc < $mtimeDst) {
$this->writeDebug("skipping $thisWeb.$thisTopic ... did not change");
$this->writeDebug("skipping $item->{web}.$item->{topic} ... did not change");
next;
}
}

unless (Foswiki::Func::topicExists($thisWeb, $thisTopic)) {
$this->writeWarning("$thisWeb.$thisTopic does not exist ... skipping");
unless (Foswiki::Func::topicExists($item->{web}, $item->{topic})) {
$this->writeWarning("$item->{web}.$item->{topic} does not exist ... skipping");
next;
}

# pushTopicContext does not suffice. we need a new Foswiki session for every topic
# Foswiki::Func::pushTopicContext($thisWeb, $thisTopic);
# Foswiki::Func::pushTopicContext($item->{web}, $item->{topic});

my $request = Foswiki::Request->new();

# forward params
foreach my $key ($this->param_list) {
next if $key eq 'topic';
next if $key =~ /^(web|topic|rev|redirect|forceupdate|include|exclude|includeweb|excludeweb|limit|debug|redirect)$/;
my $val = $this->param($key);
$request->param($key, $val);
}
$request->param("topic", $thisWeb.'.'.$thisTopic);
$request->param("topic", $item->{web}.'.'.$item->{topic});
$request->param("rev", $item->{rev}) if $item->{rev};

my $wikiName = Foswiki::Func::getWikiName();
my $loginName = Foswiki::Func::wikiToUserName($wikiName);
my $session = Foswiki->new($loginName, $request, {
static => 1,
});

# patch internal session
$Foswiki::Plugins::SESSION = $session;

$this->writeDebug("$i/$len: exporting $thisWeb.$thisTopic to $dst");
$this->exportTopic($thisWeb, $thisTopic);
$this->writeDebug("$i/$len: exporting $item->{web}.$item->{topic}, rev=$item->{rev} to $dst");
$this->exportTopic($item->{web}, $item->{topic}, $item->{rev});

$session->finish();

# revert to main session
$Foswiki::Plugins::SESSION = $mainSession;

last if $limit && $i > $limit;
Expand All @@ -266,38 +272,61 @@ sub exportTopics {
# restore main session context;
$Foswiki::Plugins::SESSION = $mainSession;

return $this->postProcess($web, $topics);
return $this->postProcess();
}

sub postProcess {
sub publishSet {
my ($this, $web, $topics) = @_;

my $topic;
if (defined $topics && @$topics) {
$topic = shift @$topics;
if ($topics) {
$this->{_publishSet} = [];
foreach my $topic (@$topics) {
my $rev;
if ($topic =~ /^(.*?)(?:=(\d+))?$/) {
$topic = $1;
$rev = $2;
}
$rev ||= 0;
my ($thisWeb, $thisTopic) = Foswiki::Func::normalizeWebTopicName($web ,$topic);
$thisWeb =~ s/\//\./g;
push @{$this->{_publishSet}}, {
web => $thisWeb,
topic => $thisTopic,
rev => $rev
};
}
}
return $this->getTargetUrl($web, $topic);

return $this->{_publishSet};
}

sub postProcess {
my ($this) = @_;

my $item = @{$this->publishSet()}[0];

return $this->getTargetUrl($item->{web}, $item->{topic}, $item->{rev});
}

sub exportTopic {
my ($this, $web, $topic) = @_;
my ($this, $web, $topic, $rev) = @_;

# not using a die()
$this->writeWarning("exportTopic not implemented");
}

sub getTargetPath {
my ($this, $web, $topic) = @_;
my ($this, $web, $topic, $rev, $name) = @_;

# not using a die()
$this->writeWarning("getTargetPath not implemented");
}

sub getTargetUrl {
my ($this, $web, $topic) = @_;
my ($this, $web, $topic, $rev, $name) = @_;

# not using a die()
$this->writeWarning("getTargetUrl not implemented");
$this->writeWarning("getTargetUrl not implemented $this");
}

sub extractExportableAreas {
Expand Down Expand Up @@ -389,11 +418,6 @@ sub renderHTML {
my $pub = Foswiki::Func::getPubUrlPath();
my $request = Foswiki::Func::getRequestObject();
my $host = $session->{urlHost} || $request->header('Host') || 'localhost';
my $viewUrl = $session->getScriptUrl(1, "view");
my $viewUrlPath = $viewUrl;
$viewUrlPath =~ s/^$host//g;

#$this->writeDebug("host=$host, viewUrl=$viewUrl, viewUrlPath=$viewUrlPath");

# remove non-macros and leftovers
$result =~ s/%(?:REVISIONS|REVTITLE|REVARG|QUERYPARAMSTRING)%//g;
Expand All @@ -403,24 +427,58 @@ sub renderHTML {
$result =~ s!(['"\(])($Foswiki::cfg{DefaultUrlHost}|https?://$host)?$pub/(.*?)(\1|\))!$1.$this->copyAsset($3).$4!ge;

# rewrite view links
my $htmlPrefix = $this->{htmlUrl};
$htmlPrefix .= '/' unless $htmlPrefix =~ /\/$/;
$result =~ s!href=(["'])(?:$viewUrl|$viewUrlPath)/($Foswiki::regex{webNameRegex}(?:\.|/)[[:upper:]]+[[:alnum:]]*)(\?.*?)?\1!'href='.$1.$htmlPrefix.$2.'.html'.($3||'').$1!ge;
$result = $this->rewriteViewLinks($result);

# convert absolute to relative urls
$result =~ s/$host//g;

# fix anchors
$result =~ s!href=(["'])\?.*?#!href=$1#!g;

# replace <base.../> tag
$result =~ s/^<base[^>]+>.*?<\/base>.*$//im;
$result =~ s/^base[^>]+\/>.*$//im;
$result =~ s/<head>/<head>\n<base href="$this->{baseUrl}" \/>/;
# remove <base.../> tag
$result =~ s/<\!\-\-\[if IE\]><\/base><!\[endif\]\-\->//i;
$result =~ s/<base[^>]+>.*?<\/base>//i;
$result =~ s/<base[^>]+\/?>//i;
$result =~ s/<\/base>//i;

return $result;
}

sub rewriteViewLinks {
my ($this, $html) = @_;

my $session = $Foswiki::Plugins::SESSION;
my $request = Foswiki::Func::getRequestObject();
my $host = $session->{urlHost} || $request->header('Host') || 'localhost';
my $viewUrl = $session->getScriptUrl(1, "view");
my $viewUrlPath = $viewUrl;
$viewUrlPath =~ s/^$host//g;

#$this->writeDebug("host=$host, viewUrl=$viewUrl, viewUrlPath=$viewUrlPath");

our %topics;
foreach my $item (@{$this->publishSet}) {
$topics{"$item->{web}.$item->{topic}"} = 1;
}
#print STDERR "converging topics ".join(", ", keys %topics)."\n";

sub _doit {
my ($this, $all, $quote, $web, $topic, $params) = @_;

return $all unless $topics{"$web.$topic"};

#print STDERR "rewriting web=$web, topic=$topic\n";

my $url = $this->getTargetUrl($web, $topic);
$url ||= '?'.$params if $params;
return 'href='.$quote.$url.$quote;
}

$html =~ s!(href=(["'])(?:$viewUrl|$viewUrlPath)/($Foswiki::regex{webNameRegex})(?:\.|/)([[:upper:]]+[[:alnum:]]*)(\?.*?)?\2)!_doit($this, $1, $2, $3, $4, $5)!ge;

return $html;
}

sub copyAsset {
my ($this, $assetName) = @_;

Expand Down Expand Up @@ -451,6 +509,8 @@ sub copyAsset {
$url = $this->{assetsUrl}.'/'.$path.'/'.$file;
#$url = $path.'/'.$file;

#print STDERR "assetName=$assetName, src=$src, dst=$dst\n";

if (-r $src) {

unless (-d $newPath) {
Expand Down
Loading

0 comments on commit 088e876

Please sign in to comment.