VersionTag rollback moved to Fork

This commit is contained in:
Paul Driver 2010-10-06 08:51:27 -07:00
parent 895ce37917
commit 04fa1ca794
8 changed files with 241 additions and 105 deletions

View file

@ -837,7 +837,7 @@ sub fixUrlFromParent {
#-------------------------------------------------------------------
=head2 forkWithProgressTree ($args)
=head2 forkWithStatusPage ($args)
Kicks off a WebGUI::Fork running $method with $args (from the args hashref)
and redirects to a ProgressTree status page to show the progress. The
@ -851,6 +851,10 @@ The name of the WebGUI::Asset method to call
The arguments to pass that method (see WebGUI::Fork)
=head3 plugin
The WebGUI::Operation::Fork plugin to render (e.g. ProgressTree)
=head3 title
An key in Asset's i18n hash for the title of the rendered console page
@ -861,7 +865,7 @@ The full url to redirect to after the fork has finished.
=cut
sub forkWithProgressTree {
sub forkWithStatusPage {
my ( $self, $args ) = @_;
my $session = $self->session;
@ -874,7 +878,7 @@ sub forkWithProgressTree {
my $method = $session->form->get('proceed') || 'manageTrash';
my $i18n = WebGUI::International->new( $session, 'Asset' );
my $pairs = $process->contentPairs(
'ProgressTree', {
$args->{plugin}, {
title => $i18n->get( $args->{title} ),
icon => 'assets',
proceed => $args->{redirect} || '',
@ -882,7 +886,7 @@ sub forkWithProgressTree {
);
$session->http->setRedirect( $self->getUrl($pairs) );
return 'redirect';
} ## end sub forkWithProgressTree
} ## end sub forkWithStatusPage
#-------------------------------------------------------------------

View file

@ -400,7 +400,8 @@ sub www_copy {
}
$args{assetId} = $self->getId;
$self->forkWithProgressTree({
$self->forkWithStatusPage({
plugin => 'ProgressTree',
title => 'Copy Assets',
redirect => $redir,
method => 'copyInFork',
@ -727,7 +728,8 @@ sub www_pasteList {
my $form = $session->form;
return $session->privilege->insufficient() unless $self->canEdit && $session->form->validToken;
$self->forkWithProgressTree( {
$self->forkWithStatusPage( {
plugin => 'ProgressTree',
title => 'Paste Assets',
redirect => $self->getUrl(
$form->get('proceed') eq 'manageAssets'

View file

@ -1015,7 +1015,8 @@ sub www_exportStatus {
my @vars = qw(
index depth userId extrasUploadsAction rootUrlAction exportUrl
);
$self->forkWithProgressTree({
$self->forkWithStatusPage({
plugin => 'ProgressTree',
title => 'Page Export Status',
method => 'exportInFork',
groupId => 13,

View file

@ -387,7 +387,8 @@ sub www_delete {
if ($self->getId eq $asset->getId) {
$asset = $self->getParent;
}
$self->forkWithProgressTree({
$self->forkWithStatusPage({
plugin => 'ProgressTree',
title => 'Delete Assets',
redirect => $asset->getUrl,
method => 'trashInFork',
@ -448,7 +449,8 @@ sub www_deleteList {
my $form = $session->form;
return $session->privilege->insufficient() unless $session->form->validToken;
my $method = $form->get('proceed') || 'manageTrash';
$self->forkWithProgressTree({
$self->forkWithStatusPage({
plugin => 'ProgressTree',
title => 'Delete Assets',
redirect => $self->getUrl("func=$method"),
method => 'trashInFork',
@ -566,7 +568,8 @@ sub www_purgeList {
return $session->privilege->insufficient() unless $session->form->validToken;
my $method = $form->get('proceed') || 'manageTrash';
$method .= ';systemTrash=1' if $form->get('systemTrash');
$self->forkWithProgressTree({
$self->forkWithStatusPage({
plugin => 'ProgressTree',
title => 'purge',
redirect => $self->getUrl("func=$method"),
method => 'purgeInFork',

View file

@ -355,7 +355,7 @@ Signals the fork that it should report its next status, then polls at a
configurable, fractional interval (default: .1 seconds) waiting for the fork
to claim that its status has been updated. Returns the updated status. See
setWait() for a way to change the interval (or disable the waiting procedure
entirely).
entirely). We will only wait for a maximum of 100 intervals.
=cut
@ -363,7 +363,8 @@ sub getStatus {
my $self = shift;
if ( my $interval = $self->{interval} ) {
$self->set( { latch => 1 } );
while (1) {
my $maxWait;
while ($maxWait++ < 100) {
sleep $interval;
my ( $finished, $latch ) = $self->get( 'finished', 'latch' );
last if $finished || !$latch;

View file

@ -0,0 +1,126 @@
package WebGUI::Fork::ProgressBar;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2009 Plain Black Corporation.
-------------------------------------------------------------------
Please read the legal notices (docs/legal.txt) and the license
(docs/license.txt) that came with this distribution before using
this software.
-------------------------------------------------------------------
http://www.plainblack.com info@plainblack.com
-------------------------------------------------------------------
=cut
use strict;
use warnings;
=head1 NAME
WebGUI::Fork::ProgressBar
=head1 DESCRIPTION
Renders an admin console page that polls ::Status to draw a simple progress
bar along with some kind of message.
=head1 SUBROUTINES
These subroutines are available from this package:
=cut
use Template;
use HTML::Entities;
use JSON;
my $template = <<'TEMPLATE';
<p id='message'></p>
<div id='meter'></div>
<p>Time elapsed: <span id='elapsed'></span> seconds.</p>
<script>
(function (params) {
var bar = new YAHOO.WebGUI.Fork.ProgressBar();
YAHOO.util.Event.onDOMReady(function () {
bar.render('meter');
YAHOO.WebGUI.Fork.poll({
url : params.statusUrl,
draw : function (data) {
var status = YAHOO.lang.JSON.parse(data.status);
bar.update(status.finished, status.total);
document.getElementById('message').innerHTML = status.message;
document.getElementById('elapsed').innerHTML = data.elapsed;
},
finish : function() {
YAHOO.WebGUI.Fork.redirect(params.redirect);
},
error : function (msg) {
alert(msg);
}
});
});
}([% params %]));
</script>
TEMPLATE
#-------------------------------------------------------------------
=head2 handler ( process )
See WebGUI::Operation::Fork.
=cut
sub handler { renderBar( shift, $template ) }
#-------------------------------------------------------------------
=head2 renderBar ( process, template )
Renders $template, passing a "params" variable to it that is JSON of a
statusUrl to poll and a page to redirect to. Includes WebGUI.Fork.redirect,
poll, and ProgressBar js and CSS (as well as all their YUI dependancies), and
puts the whole template inside an adminConsole rendered based off some form
parameters.
=cut
sub renderBar {
my ( $process, $template ) = @_;
my $session = $process->session;
my $url = $session->url;
my $form = $session->form;
my $style = $session->style;
my $tt = Template->new;
my %vars = (
params => JSON::encode_json( {
statusUrl => $url->page( $process->contentPairs('Status') ),
redirect => scalar $form->get('proceed'),
}
),
);
$tt->process( \$template, \%vars, \my $content ) or die $tt->error;
my $console = WebGUI::AdminConsole->new( $session, $form->get('icon') );
$style->setLink( $url->extras("Fork/ProgressBar.css"), { rel => 'stylesheet' } );
$style->setScript( $url->extras("$_.js") )
for ( (
map {"yui/build/$_"}
qw(
yahoo/yahoo-min
dom/dom-min
json/json-min
event/event-min
connection/connection_core-min
)
),
'Fork/ProgressBar',
'Fork/poll',
'Fork/redirect'
);
return $console->render( $content, encode_entities( $form->get('title') ) );
} ## end sub renderBar
1;

View file

@ -35,42 +35,18 @@ These subroutines are available from this package:
use Template;
use HTML::Entities;
use JSON;
use WebGUI::Fork::ProgressBar;
my $template = <<'TEMPLATE';
<p>
<div id='meter'>
<div id='meter-bar'>
<div id='meter-text'></div>
</div>
</div>
<div id='meter'></div>
Current asset: <span id='focus'></span>
(<span id='finished'></span>/<span id='total'></span>).<br />
<span id='elapsed'></span> seconds elapsed.
<ul id='tree'></ul>
[% MACRO inc(file) BLOCK %]<script src="$extras/$file"></script>[% END %]
[% MACRO yui(file) BLOCK %][% inc("yui/build/$file") %][% END %]
[% yui("yahoo/yahoo-min.js") %]
[% yui("json/json-min.js") %]
[% yui("event/event-min.js") %]
[% yui("connection/connection_core-min.js") %]
[% inc("underscore/underscore-min.js") %]
<script>
(function (params) {
var JSON = YAHOO.lang.JSON, statusUrl = params.statusUrl;
var bar = new YAHOO.WebGUI.Fork.ProgressBar();
function finish() {
var redir = params.redirect;
if (redir) {
setTimeout(function() {
// The idea here is to only allow local redirects
var loc = window.location;
loc.href = loc.protocol + '//' + loc.host + redir;
}, 1000);
}
}
function error(msg) {
alert(msg);
}
function setHtml(id, html) {
document.getElementById(id).innerHTML = html;
}
@ -82,18 +58,18 @@ Current asset: <span id='focus'></span>
total += 1;
txt = asset.url;
if (asset.focus) {
li.className += 'focus';
focus = asset.url;
if (asset.success) {
li.className = 'success';
finished += 1;
}
else if (asset.failure) {
li.className = 'failure';
txt += ' (' + asset.failure + ')';
finished += 1;
}
else if (asset.success) {
li.className = 'success';
finished += 1;
if (asset.focus) {
li.className += 'focus';
focus = asset.url;
}
li.appendChild(document.createTextNode(txt));
if (notes = asset.notes) {
@ -117,55 +93,31 @@ Current asset: <span id='focus'></span>
_.each(JSON.parse(data.status), function (root) {
recurse(root, tree);
});
pct = Math.floor((finished/total)*100) + '%';
setHtml('meter-text', pct);
document.getElementById('meter-bar').style.width = pct;
bar.update(finished, total);
setHtml('total', total);
setHtml('finished', finished);
setHtml('focus', focus || 'nothing');
setHtml('elapsed', data.elapsed);
}
function fetch() {
var callback = {
success: function (o) {
var data, status;
if (o.status != 200) {
error("Server returned bad response");
return;
}
data = JSON.parse(o.responseText);
if (data.error) {
error(data.error);
}
else if (data.finished) {
draw(data);
finish();
}
else {
draw(data);
setTimeout(fetch, 1000);
}
YAHOO.util.Event.onDOMReady(function () {
bar.render('meter');
YAHOO.WebGUI.Fork.poll({
url : params.statusUrl,
draw : draw,
finish : function () {
YAHOO.WebGUI.Fork.redirect(params.redirect);
},
failure: function (o) {
error("Could not communicate with server");
error : function (msg) {
alert(msg)
}
};
YAHOO.util.Connect.asyncRequest('GET', statusUrl, callback, null);
}
YAHOO.util.Event.onDOMReady(fetch);
});
});
}([% params %]));
</script>
TEMPLATE
my $stylesheet = <<'STYLESHEET';
<style>
#meter { border: thin solid black; position: relative }
#meter-bar { background-color: lime; font-size: 18pt;
height: 20pt; line-height: 20pt }
#meter-text { position: absolute; top: 0; left: 0; width: 100%;
text-align: center }
#tree li { color: black }
#tree li.focus { color: cyan }
#tree li.failure { color: red }
@ -184,22 +136,11 @@ See WebGUI::Operation::Fork.
sub handler {
my $process = shift;
my $session = $process->session;
my $style = $session->style;
my $url = $session->url;
my $form = $session->form;
my $tt = Template->new( { INTERPOLATE => 1 } );
my %vars = (
params => JSON::encode_json( {
statusUrl => $url->page( $process->contentPairs('Status') ),
redirect => scalar $form->get('proceed'),
}
),
extras => $url->extras,
);
$tt->process( \$template, \%vars, \my $content ) or die $tt->error;
my $console = WebGUI::AdminConsole->new( $session, $form->get('icon') );
$session->style->setRawHeadTags($stylesheet);
return $console->render( $content, encode_entities( $form->get('title') ) );
} ## end sub handler
$style->setRawHeadTags($stylesheet);
$style->setScript($url->extras('underscore/underscore-min.js'));
WebGUI::Fork::ProgressBar::renderBar($process, $template);
}
1;

View file

@ -21,6 +21,9 @@ use WebGUI::International;
use WebGUI::VersionTag;
use WebGUI::HTMLForm;
use WebGUI::Paginator;
use WebGUI::Fork;
use Monkey::Patch;
use JSON;
=head1 NAME
@ -137,6 +140,50 @@ sub getVersionTagOptions {
return %tag;
}
#----------------------------------------------------------------------------
=head2 rollbackInFork ($process, $tagId)
WebGUI::Fork method called by www_rollbackVersionTag
=cut
sub rollbackInFork {
my ( $process, $tagId ) = @_;
my $session = $process->session;
my $tag = WebGUI::VersionTag->new( $session, $tagId );
my %status = (
finished => 0,
total => $process->session->db->quickScalar( 'SELECT count(*) FROM assetData WHERE tagId = ?', [$tagId] ),
message => '',
);
my $update = sub {
$process->update( sub { JSON::encode_json( \%status ) } );
};
my $patch = Monkey::Patch::patch_class(
'WebGUI::Asset',
'purgeRevision',
sub {
my $purgeRevision = shift;
my $self = shift;
$self->$purgeRevision(@_);
$status{finished}++;
$update->();
}
);
$tag->rollback( {
outputSub => sub {
$status{message} = shift;
$update->();
}
}
);
# need to get at least one of these in for the degenerate case of no
# revisions in tag
$update->();
} ## end sub rollbackInFork
#-------------------------------------------------------------------
=head2 www_approveVersionTag ( session )
@ -853,16 +900,27 @@ sub www_rollbackVersionTag {
return $session->privilege->adminOnly() unless canView($session);
my $tagId = $session->form->process("tagId");
return $session->privilege->vitalComponent() if ($tagId eq "pbversion0000000000001");
my $pb = WebGUI::ProgressBar->new($session);
my $i18n = WebGUI::International->new($session, 'VersionTag');
$pb->start($i18n->get('rollback version tag'), $session->url->extras('adminConsole/versionTags.gif'));
if ($tagId) {
my $tag = WebGUI::VersionTag->new($session, $tagId);
$tag->rollback({ outputSub => sub { $pb->update(@_) }, }) if defined $tag;
}
my $process = WebGUI::Fork->start(
$session, 'WebGUI::Operation::VersionTag', 'rollbackInFork', $tagId
);
my $i18n = WebGUI::International->new($session, 'VersionTag');
my $method = $session->form->process("proceed");
$method = $method eq "manageCommittedVersions" ? $method : 'manageVersions';
$pb->finish(WebGUI::Asset->getDefault($session)->getUrl('op='.$method));
my $redir = WebGUI::Asset->getDefault($session)->getUrl("op=$method");
$session->http->setRedirect(
$session->url->page(
$process->contentPairs(
'ProgressBar', {
icon => 'versions',
title => $i18n->get('rollback version tag'),
proceed => $redir,
}
)
)
);
return 'redirect';
}