Tree view buttons now work. Changed progress bar helpers to use fork. Added forkId option to AssetHelpers. Added updateAsset service to Admin.

This commit is contained in:
Doug Bell 2011-03-03 19:25:20 -06:00
parent 399aa5368b
commit b27bc19e4d
14 changed files with 757 additions and 277 deletions

View file

@ -24,12 +24,12 @@ Admin Plugins do the administrative tasks.
use Moose;
use JSON qw( from_json to_json );
use namespace::autoclean;
use Scalar::Util;
use Search::QueryParser;
use WebGUI::Pluggable;
use WebGUI::Macro;
use WebGUI::Search;
use WebGUI::Fork;
has 'session' => (
is => 'ro',
@ -740,6 +740,55 @@ sub www_searchAssets {
return to_json( $assetInfo );
}
#----------------------------------------------------------------------------
=head2 www_updateAsset( )
Update an asset. The assetId is given in a query parameter. The updated
properties are given as a JSON string in the POST body.
The actual update will happen in a forked process, due to rank being a long
update.
=cut
sub www_updateAsset {
my ( $self ) = @_;
my $session = $self->session;
my $assetId = $session->form->get( 'assetId' );
my $asset = eval { WebGUI::Asset->newById( $session, $assetId ); };
if ( $@ || !$asset ) {
return to_json( { error => "Could not find asset" } );
}
my $props = eval { JSON->new->decode( $session->request->raw_body ); };
if ( $@ ) {
return to_json( { error => "Unable to decode JSON body" } );
}
my $fork = WebGUI::Fork->start(
$session, __PACKAGE__, 'updateAsset', { assetId => $assetId, properties => $props },
);
return to_json( { forkId => $fork->getId } );
}
sub updateAsset {
my ( $process, $args ) = @_;
my $session = $process->session;
my $props = $args->{properties};
my $assetId = $args->{assetId};
my $asset = WebGUI::Asset->newById( $session, $assetId );
# Update rank specially
if ( my $rank = delete $props->{rank} ) {
$asset->setRank( $rank );
}
# Update other properties
# TODO: Do we add a revision? or do they request a revision?
}
#----------------------------------------------------------------------
=head2 www_view ( session )
@ -783,6 +832,7 @@ sub www_view {
$style->setCss( $url->extras('yui/build/container/assets/skins/sam/container.css'));
$style->setCss( $url->extras('yui/build/autocomplete/assets/skins/sam/autocomplete.css'));
$style->setCss( $url->extras('yui/build/menu/assets/skins/sam/menu.css'));
$style->setCss( $url->extras('yui/build/progressbar/assets/skins/sam/progressbar.css') );
$style->setCss( $url->extras('admin/admin.css'));
$style->setScript($url->extras('yui/build/yahoo-dom-event/yahoo-dom-event.js'));
$style->setScript($url->extras('yui/build/utilities/utilities.js'));
@ -799,7 +849,9 @@ sub www_view {
$style->setScript($url->extras('yui/build/button/button-min.js'));
$style->setScript($url->extras('yui/build/autocomplete/autocomplete-min.js'));
$style->setScript( $url->extras( 'yui/build/json/json-min.js' ) );
$style->setScript( $url->extras( 'yui/build/progressbar/progressbar-min.js' ) );
$style->setScript( $url->extras( 'yui-webgui/build/i18n/i18n.js' ) );
$style->setScript( $url->extras( 'Fork/poll.js' ) );
$style->setScript($url->extras('admin/admin.js'));
# Use the template in our __DATA__ block

View file

@ -1208,6 +1208,10 @@ sub getHelpers {
className => 'WebGUI::AssetHelper::CreateShortcut',
label => 'Create Shortcut',
},
duplicate => {
className => 'WebGUI::AssetHelper::Duplicate',
label => 'Duplicate',
},
cut => {
className => 'WebGUI::AssetHelper::Cut',
label => 'Cut',
@ -1232,6 +1236,10 @@ sub getHelpers {
className => 'WebGUI::AssetHelper::Lock',
label => 'Lock',
},
delete => {
className => 'WebGUI::AssetHelper::Delete',
label => 'Delete',
},
};
# Merge additional helpers for this class from config

View file

@ -51,59 +51,6 @@ sub canPaste {
return $class->validParent($self->session);
}
#-------------------------------------------------------------------
=head2 copyInFork ( $process, $args )
WebGUI::Fork method called by www_copy
=cut
sub copyInFork {
my ($process, $args) = @_;
my $session = $process->session;
my $asset = WebGUI::Asset->newById($session, $args->{assetId});
my @pedigree = ('self');
my $childrenOnly = 0;
if ($args->{childrenOnly}) {
$childrenOnly = 1;
push @pedigree, 'children';
}
else {
push @pedigree, 'descendants';
}
my $ids = $asset->getLineage(\@pedigree);
my $tree = WebGUI::ProgressTree->new($session, $ids);
$process->update(sub { $tree->json });
my $patch = Monkey::Patch::patch_class(
'WebGUI::Asset', 'duplicate', sub {
my $duplicate = shift;
my $self = shift;
my $id = $self->getId;
$tree->focus($id);
my $asset = eval { $self->$duplicate(@_) };
my $e = $@;
if ($e) {
$tree->note($id, $e);
$tree->failure($id, 'Died');
}
else {
$tree->success($id);
}
$process->update(sub { $tree->json });
die $e if $e;
return $asset;
}
);
my $newAsset = $asset->duplicateBranch($childrenOnly, 'clipboard');
$newAsset->update({ title => $newAsset->getTitle . ' (copy)'});
if ($args->{commit}) {
my $tag = WebGUI::VersionTag->getWorking($session);
$tag->requestCommit();
}
}
#-------------------------------------------------------------------
=head2 cut ( )

View file

@ -94,6 +94,11 @@ A URL. Will open a tab in the Admin Console. Anything returned by the URL will
A URL. Puts new content into the View tab from the requested URL.
=head4 forkId
The ID for a WebGUI::Fork process. The Admin Console can then open a progress
dialog to poll for the progress of the forked process.
=head4 scriptFile
Loads the requested JavaScript file, referenced by URL.

View file

@ -3,6 +3,7 @@ package WebGUI::AssetHelper::Copy;
use strict;
use Class::C3;
use base qw/WebGUI::AssetHelper/;
use Scalar::Util qw( blessed );
=head1 LEGAL
@ -34,69 +35,54 @@ These methods are available from this class:
=head2 process ( $asset )
Open a progress dialog for the copy operation
Fork the copy operation
=cut
sub process {
my ($self, $asset) = @_;
my $session = $self->session;
# Should we autocommit?
my $commit = $session->setting->get('versionTagMode') eq 'autoCommit';
# Fork the copy. Forking makes sure it won't get interrupted
my $fork = WebGUI::Fork->start(
$session, blessed( $self ), 'copy', { assetId => $asset->getId, commit => $commit },
);
return {
openDialog => '?op=assetHelper;helperId=' . $self->id . ';method=copy;assetId=' . $asset->getId,
forkId => $fork->getId,
};
}
#----------------------------------------------------------------------------
#-------------------------------------------------------------------
=head2 www_copy ( $asset )
=head2 copy ( $process, $args )
Perform the copy operation, showing the progress.
Perform the copy stuff in a forked process
=cut
sub www_copy {
my ( $self, $asset ) = @_;
my $session = $asset->session;
my $i18n = WebGUI::International->new($session, 'Asset');
sub copy {
my ($process, $args) = @_;
my $session = $process->session;
my $asset = WebGUI::Asset->newById($session, $args->{assetId});
my $tree = WebGUI::ProgressTree->new($session, [ $asset->getId ] );
$process->update(sub { $tree->json });
my $newAsset = $asset->duplicate({ state => "clipboard" });
return $session->response->stream( sub {
my ( $session ) = @_;
my $pb = WebGUI::ProgressBar->new($session);
my @stack;
# If we aren't committing, add to a tag
if ( !$args->{commit} ) {
$newAsset->update({
status => "pending",
tagId => WebGUI::VersionTag->getWorking( $session )->getId,
});
}
$newAsset->update({ title => $newAsset->getTitle . ' (copy)'});
return $pb->run(
admin => 1,
total => 2,
title => $i18n->get('Copy Assets'),
icon => $session->url->extras('adminConsole/assets.gif'),
code => sub {
my $bar = shift;
my $newAsset = $asset->duplicate;
$bar->update($i18n->get('cut'));
my $title = sprintf("%s (%s)", $asset->getTitle, $i18n->get('copy'));
$newAsset->update({ title => $title });
$newAsset->cut;
my $result = WebGUI::VersionTag->autoCommitWorkingIfEnabled(
$session, {
allowComments => 1,
returnUrl => $asset->getUrl,
}
);
if ( $result eq 'redirect' ) {
return $asset->getUrl;
}
return { message => 'Your asset is now copied!' };
},
wrap => {
'WebGUI::Asset::duplicate' => sub {
my ($bar, $original, $asset, @args) = @_;
my $name = join '/', @stack, $asset->getTitle;
$bar->update($name);
return $asset->$original(@args);
},
}
);
} );
$tree->success($asset->getId);
$process->update(sub { $tree->json });
}
1;

View file

@ -3,6 +3,8 @@ package WebGUI::AssetHelper::Cut;
use strict;
use Class::C3;
use base qw/WebGUI::AssetHelper/;
use Scalar::Util qw( blessed );
use Monkey::Patch;
=head1 LEGAL
@ -51,58 +53,47 @@ sub process {
return { error => $i18n->get('41'), };
}
# Fork the cut. Forking makes sure it won't get interrupted
my $fork = WebGUI::Fork->start(
$session, blessed( $self ), 'cut', { assetId => $asset->getId },
);
return {
openDialog => '?op=assetHelper;helperId=' . $self->id . ';method=cut;assetId=' . $asset->getId,
forkId => $fork->getId,
};
}
#----------------------------------------------------------------------------
=head2 www_cut ( $asset )
=head2 cut ( process, args )
Show the progress bar while cutting the asset.
Handle the actual cutting in the forked process.
=cut
sub www_cut {
my ( $self, $asset ) = @_;
my $session = $asset->session;
my $i18n = WebGUI::International->new($session, 'Asset');
sub cut {
my ( $process, $args ) = @_;
my $asset = WebGUI::Asset->newById( $process->session, $args->{assetId} );
return $session->response->stream( sub {
my ( $session ) = @_;
my $pb = WebGUI::ProgressBar->new($session);
my @stack;
# All the Assets we need to work on
my $assetIds = $asset->getLineage( ['self','descendants'] );
return $pb->run(
admin => 1,
title => $i18n->get('Copy Assets'),
icon => $session->url->extras('adminConsole/assets.gif'),
code => sub {
my $bar = shift;
$bar->update( "Preparing... (i18n)" );
$bar->total( $asset->getDescendantCount + 2 );
$bar->update( "Cutting... (i18n)" );
my $success = $asset->cut();
if (! $success) {
return { error => $i18n->get('41', 'WebGUI'), };
}
return { message => "Your asset is cut!" };
},
wrap => {
'WebGUI::Asset::getLineageIterator' => sub {
my ($bar, $orig, $asset, @args) = @_;
$bar->update("Updating descendants... (i18n)");
return $asset->$orig(@args);
},
'WebGUI::Asset::updateHistory' => sub {
my ( $bar, $orig, $asset, @args ) = @_;
$bar->update( "Updating " . $asset->getTitle );
return $asset->$orig(@args);
},
},
);
} );
# Build a tree and update process status
my $tree = WebGUI::ProgressTree->new( $process->session, $assetIds );
$process->update( sub { $tree->json } );
# Monkeypatch a sub to get a status update
my $patch = Monkey::Patch::patch_class(
'WebGUI::Asset', 'updateHistory', sub {
my ( $orig, $self, @args ) = @_;
$tree->success( $self->assetId );
$process->update( sub { $tree->json } );
$self->$orig( @args );
}
);
# Do the actual work
$asset->cut;
}
1;

View file

@ -0,0 +1,107 @@
package WebGUI::AssetHelper::Delete;
use strict;
use Class::C3;
use base qw/WebGUI::AssetHelper/;
use Scalar::Util qw( blessed );
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Deleteright 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
-------------------------------------------------------------------
=head1 NAME
Package WebGUI::AssetHelper::Delete
=head1 DESCRIPTION
Delete an Asset, and all descendants
=head1 METHODS
These methods are available from this class:
=cut
#-------------------------------------------------------------------
=head2 process ( $asset )
Fork the Delete operation
=cut
sub process {
my ($self, $asset) = @_;
my $session = $self->session;
my $i18n = WebGUI::International->new($session, 'WebGUI');
if (! $asset->canEdit) {
return { error => $i18n->get('38'), };
}
elsif ( $asset->get('isSystem') ) {
return { error => $i18n->get('41'), };
}
# Fork the Delete. Forking makes sure it won't get interrupted
my $fork = WebGUI::Fork->start(
$session, blessed( $self ), 'delete', { assetId => $asset->getId, },
);
return {
forkId => $fork->getId,
};
}
#-------------------------------------------------------------------
=head2 delete ( $process, $args )
Perform the delete stuff in a forked process
=cut
sub delete {
my ($process, $args) = @_;
my $session = $process->session;
my $asset = WebGUI::Asset->newById($session, $args->{assetId});
# Prepare a tree with all the ids
my $ids =
$asset->getLineage(
[ 'self', 'descendants' ], {
statesToInclude => [qw(published clipboard clipboard-limbo trash trash-limbo)],
statusToInclude => [qw(approved archived pending)],
}
);
my $tree = WebGUI::ProgressTree->new( $session, $ids );
$process->update(sub { $tree->json });
# Patch a sub to get a status update
my $patch = Monkey::Patch::patch_class(
'WebGUI::Asset',
'setState',
sub {
my ( $setState, $self, $state ) = @_;
my $id = $self->getId;
$tree->focus($id);
my $ret = $self->$setState($state);
$tree->success($id);
$process->update(sub { $tree->json });
return $ret;
}
);
# Do the dirty deed, cheap
$asset->trash;
}
1;

View file

@ -0,0 +1,88 @@
package WebGUI::AssetHelper::Duplicate;
use strict;
use Class::C3;
use base qw/WebGUI::AssetHelper/;
use Scalar::Util qw( blessed );
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Duplicateright 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
-------------------------------------------------------------------
=head1 NAME
Package WebGUI::AssetHelper::Duplicate
=head1 DESCRIPTION
Duplicate an Asset, with no children.
=head1 METHODS
These methods are available from this class:
=cut
#-------------------------------------------------------------------
=head2 process ( $asset )
Fork the duplicate operation
=cut
sub process {
my ($self, $asset) = @_;
my $session = $self->session;
# Should we autocommit?
my $commit = $session->setting->get('versionTagMode') eq 'autoCommit';
# Fork the Duplicate. Forking makes sure it won't get interrupted
my $fork = WebGUI::Fork->start(
$session, blessed( $self ), 'duplicate', { assetId => $asset->getId, commit => $commit },
);
return {
forkId => $fork->getId,
};
}
#-------------------------------------------------------------------
=head2 duplicate ( $process, $args )
Perform the duplicate stuff in a forked process
=cut
sub duplicate {
my ($process, $args) = @_;
my $session = $process->session;
my $asset = WebGUI::Asset->newById($session, $args->{assetId});
my $tree = WebGUI::ProgressTree->new($session, [ $asset->getId ] );
$process->update(sub { $tree->json });
my $newAsset = $asset->duplicate;
# If we aren't committing, add to a tag
if ( !$args->{commit} ) {
$newAsset->update({
status => "pending",
tagId => WebGUI::VersionTag->getWorking( $session )->getId,
});
}
$newAsset->update({ title => $newAsset->getTitle . ' (Duplicate)'});
$tree->success($asset->getId);
$process->update(sub { $tree->json });
}
1;

View file

@ -363,51 +363,6 @@ sub trash {
return 1;
}
#-------------------------------------------------------------------
=head2 trashInFork
WebGUI::Fork method called by www_deleteList and www_delete to move assets
into the trash.
=cut
sub trashInFork {
my ( $process, $list ) = @_;
my $session = $process->session;
my @roots = grep { $_->canEdit && $_->canEditIfLocked }
map {
eval { WebGUI::Asset->newPending( $session, $_ ) }
} @$list;
my @ids = map {
my $list = $_->getLineage(
[ 'self', 'descendants' ], {
statesToInclude => [qw(published clipboard clipboard-limbo trash trash-limbo)],
statusToInclude => [qw(approved archived pending)],
}
);
@$list;
} @roots;
my $tree = WebGUI::ProgressTree->new( $session, \@ids );
$process->update(sub { $tree->json });
my $patch = Monkey::Patch::patch_class(
'WebGUI::Asset',
'setState',
sub {
my ( $setState, $self, $state ) = @_;
my $id = $self->getId;
$tree->focus($id);
my $ret = $self->$setState($state);
$tree->success($id);
$process->update(sub { $tree->json });
return $ret;
}
);
$_->trash() for @roots;
} ## end sub trashInFork
require WebGUI::Workflow::Activity::DeleteExportedFiles;
sub _invokeWorkflowOnExportedFiles {
my $self = shift;
@ -435,63 +390,6 @@ sub _invokeWorkflowOnExportedFiles {
#-------------------------------------------------------------------
=head2 www_delete
Moves self to trash in fork, redirects to Container or Parent if canEdit.
Otherwise returns AdminConsole rendered insufficient privilege.
=cut
sub www_delete {
my $self = shift;
return $self->session->privilege->insufficient() unless ($self->canEdit && $self->canEditIfLocked);
return $self->session->privilege->vitalComponent() if $self->get('isSystem');
return $self->session->privilege->vitalComponent() if ($self->getId ~~ [$self->session->setting->get("defaultPage"), $self->session->setting->get("notFoundPage")]);
$self->trash;
my $asset = $self->getContainer;
if ($self->getId eq $asset->getId) {
$asset = $self->getParent;
}
$self->forkWithStatusPage({
plugin => 'ProgressTree',
title => 'Delete Assets',
redirect => $asset->getUrl,
method => 'trashInFork',
args => [ $self->getId ],
}
);
}
#-------------------------------------------------------------------
=head2 www_deleteList
Checks to see if a valid CSRF token was received. If not, then it returns insufficient privilege.
Moves list of assets to trash, checking each to see if the user canEdit,
and canEditIfLocked. Returns the user to manageTrash, or to the screen set
by the form variable C<proceeed>.
=cut
sub www_deleteList {
my $self = shift;
my $session = $self->session;
my $form = $session->form;
return $session->privilege->insufficient() unless $session->form->validToken;
my $method = $form->get('proceed') || 'manageTrash';
$self->forkWithStatusPage({
plugin => 'ProgressTree',
title => 'Delete Assets',
redirect => $self->getUrl("func=$method"),
method => 'trashInFork',
args => [ $form->get('assetId') ],
}
);
} ## end sub www_deleteList
#-------------------------------------------------------------------
=head2 www_manageTrash ( )
Returns an AdminConsole to deal with assets in the Trash. If user isn't in the Turn On Admin group, renders an insufficient privilege page.

View file

@ -30,12 +30,13 @@ my $session = WebGUI::Test->session;
#----------------------------------------------------------------------------
# Tests
plan tests => 3; # Increment this number for each test you create
plan tests => 2; # Increment this number for each test you create
#----------------------------------------------------------------------------
# put your tests here
my $output;
$session->setting->set( "versionTagMode" => "autoCommit" );
my $helper = WebGUI::AssetHelper::Copy->new( id => 'copy', session => $session );
my $home = WebGUI::Asset->getDefault($session);
my $root = WebGUI::Asset->getRoot($session);
@ -46,19 +47,14 @@ my $root = WebGUI::Asset->getRoot($session);
cmp_deeply(
$output,
{
openDialog => all(
re('helperId=copy'),
re('method=copy'),
re('assetId=' . $home->getId ),
),
forkId => re('[a-zA-Z0-9_-]{22}'),
},
'AssetHelper/Copy opens a dialog for the copy method'
'AssetHelper/Copy forks a process'
);
}
my $mech = WebGUI::Test::Mechanize->new( config => WebGUI::Test->file );
$mech->get_ok( '/?op=assetHelper;helperId=copy;method=copy;assetId=' . $home->getId );
WebGUI::Test->waitForAllForks;
$session->cache->clear;
my $clippies = $root->getLineage(["descendants"], {statesToInclude => [qw{clipboard clipboard-limbo}], returnObjects => 1,});
is @{ $clippies }, 1, '... only copied 1 asset to the clipboard, no children';
addToCleanup(@{ $clippies });

View file

@ -59,14 +59,12 @@ $output = $helper->process($safe_page);
cmp_deeply(
$output,
{
openDialog => all( re('method=cut'), re('assetId=' . $safe_page->getId) ),
forkId => re(qr/[a-zA-Z0-9_-]{22}/),
},
'AssetHelper/Cut opens a dialog'
'AssetHelper/Cut forks a process'
);
my $mech = WebGUI::Test::Mechanize->new( config => WebGUI::Test->file );
$mech->get_ok( $output->{ openDialog } );
$mech->content_lacks( 'error', "Cut succeeded" );
WebGUI::Test->waitForAllForks;
$session->cache->clear;
$safe_page = WebGUI::Asset->newById( $session, $safe_page->assetId );

77
t/AssetHelper/Delete.t Normal file
View file

@ -0,0 +1,77 @@
# vim:syntax=perl
#-------------------------------------------------------------------
# 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
#------------------------------------------------------------------
# Write a little about what this script tests.
#
#
use strict;
use Test::More;
use Test::Deep;
use WebGUI::Test; # Must use this before any other WebGUI modules
use WebGUI::Session;
use WebGUI::Asset;
use WebGUI::AssetHelper::Delete;
use WebGUI::Test::Mechanize;
#----------------------------------------------------------------------------
# Init
my $session = WebGUI::Test->session;
#----------------------------------------------------------------------------
# Tests
my $output;
my $helper = WebGUI::AssetHelper::Delete->new( id => 'Delete', session => $session );
my $import = WebGUI::Asset->getImportNode($session);
$session->user({userId => 1});
$output = $helper->process($import);
cmp_deeply(
$output,
{
error => re('You do not have sufficient privileges'),
},
'AssetHelper/Delete checks for editing privileges'
);
$session->user({userId => 3});
$output = $helper->process($import);
cmp_deeply(
$output,
{
error => re('vital component'),
},
'AssetHelper/Delete checks for system pages'
);
my $safe_page = $import->getFirstChild;
$output = $helper->process($safe_page);
cmp_deeply(
$output,
{
forkId => re(qr/[a-zA-Z0-9_-]{22}/),
},
'AssetHelper/Delete forks a process'
);
WebGUI::Test->waitForAllForks;
$session->cache->clear;
$safe_page = WebGUI::Asset->newById( $session, $safe_page->assetId );
is $safe_page->state, 'trash', '... and the asset was really Deleted';
$safe_page->restore;
done_testing();
#vim:ft=perl

61
t/AssetHelper/Duplicate.t Normal file
View file

@ -0,0 +1,61 @@
# vim:syntax=perl
#-------------------------------------------------------------------
# WebGUI is Duplicateright 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
#------------------------------------------------------------------
# Write a little about what this script tests.
#
#
use strict;
use Test::More;
use Test::Deep;
use WebGUI::Test; # Must use this before any other WebGUI modules
use WebGUI::Session;
use WebGUI::Asset;
use WebGUI::AssetHelper::Duplicate;
use WebGUI::Test::Mechanize;
#----------------------------------------------------------------------------
# Init
my $session = WebGUI::Test->session;
#----------------------------------------------------------------------------
# Tests
plan tests => 2; # Increment this number for each test you create
#----------------------------------------------------------------------------
# put your tests here
my $output;
$session->setting->set( "versionTagMode" => "autoCommit" );
my $helper = WebGUI::AssetHelper::Duplicate->new( id => 'duplicate', session => $session );
my $root = WebGUI::Test->asset;
my $test = $root->addChild( { className => 'WebGUI::Asset::Snippet' } );
{
$output = $helper->process($test);
cmp_deeply(
$output,
{
forkId => re('[a-zA-Z0-9_-]{22}'),
},
'AssetHelper/Duplicate forks a process'
);
}
WebGUI::Test->waitForAllForks;
$session->cache->clear;
my $children = $root->getLineage(["children"]);
is @{ $children }, 2, '... created a new asset';
#vim:ft=perl

View file

@ -533,7 +533,7 @@ WebGUI.Admin.prototype.requestUpdateCurrentVersionTag
};
/**
* requestHelper( helperClass, assetId )
* requestHelper( helperId, assetId )
* Request the Asset Helper for the given assetId
*/
WebGUI.Admin.prototype.requestHelper
@ -561,6 +561,7 @@ WebGUI.Admin.prototype.requestHelper
* openDialog : Open a dialog with the given URL
* openTab : Open a tab with the given URL
* redirect : Redirect the View pane to the given URL
* forkId : The Helper forked a process, use the ID to get the status
* scriptFile : Load a JS file
* scriptFunc : Run a JS function. Used with scriptFile
* scriptArgs : Arguments to scriptFunc. Used with scriptFile
@ -582,6 +583,9 @@ WebGUI.Admin.prototype.processPlugin
else if ( resp.error ) {
this.showInfoMessage( resp.error );
}
else if ( resp.forkId ) {
// Do nothing right now
}
else {
alert( "Unknown plugin response: " + YAHOO.lang.JSON.stringify(resp) );
}
@ -1376,11 +1380,15 @@ WebGUI.Admin.AssetTable.prototype.formatLockedBy
WebGUI.Admin.AssetTable.prototype.formatRank
= function ( elCell, oRecord, oColumn, orderNumber ) {
var rank = oRecord.getData("lineage").match(/[1-9][0-9]{0,5}$/);
elCell.innerHTML = '<input type="text" id="' + oRecord.getData("assetId") + '_rank" '
+ 'name="' + oRecord.getData("assetId") + '_rank" '
+ 'value="' + rank + '" size="3" '
+ '/>';
// TODO: Add onchange handler to select row
var input = document.createElement( 'input' );
input.type = "text";
input.id = oRecord.getData("assetId") + '_rank';
input.name = input.id;
input.size = 3;
input.value = rank;
YAHOO.util.Event.addListener( input, "change", function(){ this.selectRow(elCell); }, this, true );
elCell.appendChild( input );
};
/**
@ -1640,7 +1648,7 @@ WebGUI.Admin.Tree
this.btnDelete = new YAHOO.widget.Button( "treeDelete", {
type : "button",
label : window.admin.i18n.get('Asset','delete'),
onclick : { fn: this.trash, scope: this }
onclick : { fn: this.delete, scope: this }
} );
this.btnCut = new YAHOO.widget.Button( "treeCut", {
@ -1672,23 +1680,281 @@ WebGUI.Admin.Tree
YAHOO.lang.extend( WebGUI.Admin.Tree, WebGUI.Admin.AssetTable );
/**
* update( e )
* Update the selected assets' rank
* runHelperForSelected( helperId )
* Run the named asset helper for each selected asset
* Show the status of the task in a dialog box
*/
WebGUI.Admin.Tree.prototype.runHelperForSelected
= function ( helperId, title ) {
var self = this;
var assetIds = this.getSelected();
// Open the dialog with two progress bars
var dialog = new YAHOO.widget.Panel( 'adminModalDialog', {
"width" : '350px',
fixedcenter : true,
constraintoviewport : true,
underlay : "shadow",
close : true,
visible : true,
draggable : false
} );
dialog.setHeader( title );
dialog.setBody(
'<div id="pbQueue"></div><div id="pbQueueStatus">0 / ' + assetIds.length + '</div>'
+ '<div id="pbTask"></div><div id="pbTaskStatus"></div>'
);
dialog.render( document.body );
this.treeDialog = dialog;
var pbQueueBar = new YAHOO.widget.ProgressBar({
minValue : 0,
value : 0,
maxValue : assetIds.length,
width: '300px',
height: '30px',
anim: true
});
pbQueueBar.render( 'pbQueue' );
pbQueueBar.get('anim').duration = 0.5;
pbQueueBar.get('anim').method = YAHOO.util.Easing.easeOut;
var pbQueueStatus = document.getElementById( 'pbQueueStatus' );
var pbTaskBar = new YAHOO.widget.ProgressBar({
minValue : 0,
value : 0,
maxValue : 1,
width: '300px',
height: '30px',
anim: true
});
pbTaskBar.render( 'pbTask' );
pbTaskBar.get('anim').duration = 0.5;
pbTaskBar.get('anim').method = YAHOO.util.Easing.easeOut;
// Clean up when we're done
var finish = function () {
dialog.destroy();
dialog = null;
self.admin.requestUpdateClipboard();
self.admin.requestUpdateCurrentVersionTag();
self.goto( self.admin.currentAssetDef.url );
};
// Build a function to call the helper for the next asset
var callHelper = function( assetIds ) {
var assetId = assetIds.shift();
var callback = {
success : function (o) {
var resp = YAHOO.lang.JSON.parse( o.responseText );
if ( resp.error ) {
this.admin.processPlugin( resp );
finish();
}
else if ( resp.forkId ) {
// Wait until the helper is done, then call the next
YAHOO.WebGUI.Fork.poll({
url : '?op=fork;pid=' + resp.forkId,
draw : function(data) {
pbTaskBar.set( 'maxValue', data.total );
pbTaskBar.set( 'value', data.finished );
},
finish : function(){
pbQueueBar.set( 'value', pbQueueBar.get('value') + 1 );
pbQueueStatus.innerHTML = pbQueueBar.get('value') + ' / ' + pbQueueBar.get('maxValue');
if ( assetIds.length > 0 ) {
callHelper( assetIds );
}
else {
// We're all done now!
finish();
}
},
});
}
else {
// Just go to the next one
if ( assetIds.length > 0 ) {
callHelper( assetIds );
}
else {
finish();
}
}
},
failure : function (o) {
},
scope: this
};
var url = '?op=admin;method=processAssetHelper;helperId=' + helperId + ';assetId=' + assetId;
var ajax = YAHOO.util.Connect.asyncRequest( 'GET', url, callback );
};
// Start the queue
callHelper( assetIds );
};
/**
* cut( e )
* Run the cut assethelper for the selected assets
*/
WebGUI.Admin.Tree.prototype.cut
= function ( e ) {
this.runHelperForSelected( "cut", "Cut" );
};
/**
* copy( e )
* Run the Copy assethelper for the selected assets
*/
WebGUI.Admin.Tree.prototype.copy
= function ( e ) {
this.runHelperForSelected( "copy", "Copy" );
};
/**
* shortcut( e )
* Run the shortcut assethelper for the selected assets
*/
WebGUI.Admin.Tree.prototype.shortcut
= function ( e ) {
this.runHelperForSelected( "shortcut", "Create Shortcut" );
};
/**
* Run the duplicate assethelper for the selected assets
*/
WebGUI.Admin.Tree.prototype.duplicate
= function ( e ) {
this.runHelperForSelected( "duplicate", "Duplicate" );
};
/**
* Run the delete assetHelper for the selected assets
*/
WebGUI.Admin.Tree.prototype.delete
= function ( e ) {
this.runHelperForSelected( "delete", "Delete" );
};
/**
* Update the selected assets' ranks
*/
WebGUI.Admin.Tree.prototype.update
= function ( e ) {
// Get the new ranks
var assetIds = this.getSelected();
var payload = {}; // Request data payload
for ( var i = 0; i < assetIds.length; i++ ) {
var assetId = assetIds[i];
payload[ assetId ] = {
rank : document.getElementById( assetId + "_rank" ).value
};
}
var self = this;
var assetIds = this.getSelected();
// Send the request
// Open the dialog with two progress bars
var dialog = new YAHOO.widget.Panel( 'adminModalDialog', {
"width" : '350px',
fixedcenter : true,
constraintoviewport : true,
underlay : "shadow",
close : true,
visible : true,
draggable : false
} );
dialog.setHeader( "Updating" );
dialog.setBody(
'<div id="pbQueue"></div><div id="pbQueueStatus">0 / ' + assetIds.length + '</div>'
+ '<div id="pbTask"></div><div id="pbTaskStatus"></div>'
);
dialog.render( document.body );
this.treeDialog = dialog;
var pbQueueBar = new YAHOO.widget.ProgressBar({
minValue : 0,
value : 0,
maxValue : assetIds.length,
width: '300px',
height: '30px',
anim: true
});
pbQueueBar.render( 'pbQueue' );
pbQueueBar.get('anim').duration = 0.5;
pbQueueBar.get('anim').method = YAHOO.util.Easing.easeOut;
var pbQueueStatus = document.getElementById( 'pbQueueStatus' );
var pbTaskBar = new YAHOO.widget.ProgressBar({
minValue : 0,
value : 0,
maxValue : 1,
width: '300px',
height: '30px',
anim: true
});
pbTaskBar.render( 'pbTask' );
pbTaskBar.get('anim').duration = 0.5;
pbTaskBar.get('anim').method = YAHOO.util.Easing.easeOut;
// Clean up when we're done
var finish = function () {
dialog.destroy();
dialog = null;
self.admin.requestUpdateClipboard();
self.admin.requestUpdateCurrentVersionTag();
self.goto( self.admin.currentAssetDef.url );
};
// Build a function to call the helper for the next asset
var callUpdate = function( assetIds ) {
var assetId = assetIds.shift();
var callback = {
success : function (o) {
var resp = YAHOO.lang.JSON.parse( o.responseText );
if ( resp.error ) {
this.admin.processPlugin( resp );
finish();
}
else if ( resp.forkId ) {
// Wait until the helper is done, then call the next
YAHOO.WebGUI.Fork.poll({
url : '?op=fork;pid=' + resp.forkId,
draw : function(data) {
pbTaskBar.set( 'maxValue', data.total );
pbTaskBar.set( 'value', data.finished );
},
finish : function(){
pbQueueBar.set( 'value', pbQueueBar.get('value') + 1 );
pbQueueStatus.innerHTML = pbQueueBar.get('value') + ' / ' + pbQueueBar.get('maxValue');
if ( assetIds.length > 0 ) {
callHelper( assetIds );
}
else {
// We're all done now!
finish();
}
},
});
}
else if ( assetIds.length > 0 ) {
callUpdate( assetIds );
}
else {
finish();
}
},
failure : function (o) {
},
scope : this
};
var payload = YAHOO.lang.JSON.stringify({
"rank" : document.getElementById( assetId + "_rank" ).value
});
YAHOO.util.Connect.asyncRequest( "POST", "?op=admin;method=updateAsset;assetId=" + assetId, callback, payload );
};
callUpdate( assetIds );
};
/**