package WebGUI::Operation::Workflow; #------------------------------------------------------------------- # WebGUI is Copyright 2001-2006 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 #------------------------------------------------------------------- use strict; use Tie::IxHash; use WebGUI::AdminConsole; use WebGUI::HTMLForm; use WebGUI::International; use WebGUI::Workflow; use WebGUI::Workflow::Activity; use WebGUI::Workflow::Instance; use WebGUI::Utility; use POE::Component::IKC::ClientLite; use JSON 'jsonToObj'; =head1 NAME Package WebGUI::Operations::Workflow =head1 DESCRIPTION Operation handler for managing workflows. =cut #------------------------------------------------------------------- =head2 www_addWorkflow ( ) Allows the user to choose the type of workflow that's going to be created. =cut sub www_addWorkflow { my $session = shift; return $session->privilege->insufficient() unless ($session->user->isInGroup("pbgroup000000000000015")); my $i18n = WebGUI::International->new($session, "Workflow"); my $f = WebGUI::HTMLForm->new($session); $f->submit; $f->hidden( name=>"op", value=>"addWorkflowSave" ); my %options = (); foreach my $object (keys %{$session->config->get("workflowActivities")}) { if ($object eq "None") { $options{$object} = $i18n->get("no object"); } else { $options{$object} = $object; } } $f->selectBox( name=>"type", label=>$i18n->get("object type"), options=>\%options, value=>"None", hoverHelp=>$i18n->get("object type help") ); $f->submit; my $ac = WebGUI::AdminConsole->new($session,"workflow"); $ac->addSubmenuItem($session->url->page("op=manageWorkflows"), $i18n->get("manage workflows")); $ac->setHelp('add a new workflow', 'Workflow'); return $ac->render($f->print, 'add a new workflow'); } #------------------------------------------------------------------- =head2 www_addWorkflowSave ( ) Saves the results from www_addWorkflow(). =cut sub www_addWorkflowSave { my $session = shift; return $session->privilege->insufficient() unless ($session->user->isInGroup("pbgroup000000000000015")); my $workflow = WebGUI::Workflow->create($session, {type=>$session->form->get("type")}); return www_editWorkflow($session, $workflow); } #------------------------------------------------------------------- =head2 www_deleteWorkflow ( ) Deletes an entire workflow. =cut sub www_deleteWorkflow { my $session = shift; return $session->privilege->insufficient() unless ($session->user->isInGroup("pbgroup000000000000015")); my $workflow = WebGUI::Workflow->new($session, $session->form->get("workflowId")); $workflow->delete if defined $workflow; return www_manageWorkflows($session); } #------------------------------------------------------------------- =head2 www_deleteWorkflowActivity ( ) Deletes an activity from a workflow. =cut sub www_deleteWorkflowActivity { my $session = shift; return $session->privilege->insufficient() unless ($session->user->isInGroup("pbgroup000000000000015")); my $workflow = WebGUI::Workflow->new($session, $session->form->get("workflowId")); if (defined $workflow) { $workflow->deleteActivity($session->form->get("activityId")); } return www_editWorkflow($session); } #------------------------------------------------------------------ =head2 www_demoteWorkflowActivity ( session ) Moves a workflow activity down one position in the execution order. =head3 session A reference to the current session. =cut sub www_demoteWorkflowActivity { my $session = shift; return $session->privilege->insufficient() unless ($session->user->isInGroup("pbgroup000000000000015")); my $workflow = WebGUI::Workflow->new($session, $session->form->param("workflowId")); $workflow->demoteActivity($session->form->param("activityId")); return www_editWorkflow($session); } #------------------------------------------------------------------- =head2 www_editWorkflow ( session, workflow ) Displays displays the editable properties of a workflow. =cut sub www_editWorkflow { my $session = shift; my $workflow = shift; return $session->privilege->insufficient() unless ($session->user->isInGroup("pbgroup000000000000015")); $workflow = WebGUI::Workflow->new($session, $session->form->get("workflowId")) unless (defined $workflow); my $i18n = WebGUI::International->new($session, "Workflow"); my $workflowActivities = $session->config->get("workflowActivities"); my $addmenu = '
'; foreach my $class (@{$workflowActivities->{$workflow->get("type")}}) { my $activity = WebGUI::Workflow::Activity->newByPropertyHashRef($session, {className=>$class}); next unless defined $activity; $addmenu .= 'getId).'">'.$activity->getName."
\n"; } $addmenu .= '
'; my $f = WebGUI::HTMLForm->new($session); $f->submit; $f->hidden( name=>"op", value=>"editWorkflowSave" ); $f->hidden( name=>"workflowId", value=>$workflow->getId ); $f->readOnly( label=>$i18n->get("workflowId"), value=>$workflow->getId ); $f->readOnly( label=>$i18n->get("object type"), value=>$workflow->get("type"), hoverHelp=>$workflow->get("object type help2"), ); $f->text( name=>"title", value=>$workflow->get("title"), label=>$i18n->get("title"), hoverHelp=>$i18n->get("title help") ); $f->textarea( name=>"description", value=>$workflow->get("description"), label=>$i18n->get("description"), hoverHelp=>$i18n->get("description help") ); $f->yesNo( name=>"enabled", value=>$workflow->get("enabled"), defaultValue=>0, label=>$i18n->get("is enabled"), hoverHelp=>$i18n->get("is enabled help") ); $f->selectBox( name=>"mode", options=>{ singleton=>$i18n->get("singleton"), parallel=>$i18n->get("parallel"), serial=>$i18n->get("serial"), realtime=>$i18n->get("realtime"), }, value=>$workflow->get("mode") || "parallel", defaultValue=>"parallel", label=>$i18n->get("mode"), hoverHelp=>$i18n->get("mode help") ); $f->submit; my $steps = ''; my $rs = $session->db->read("select activityId, title from WorkflowActivity where workflowId=? order by sequenceNumber",[$workflow->getId]); while (my ($id, $title) = $rs->array) { $steps .= ''; } $steps .= '
' .$session->icon->delete("op=deleteWorkflowActivity;workflowId=".$workflow->getId.";activityId=".$id, undef, $i18n->get("confirm delete activity")) .$session->icon->edit("op=editWorkflowActivity;workflowId=".$workflow->getId.";activityId=".$id) .$session->icon->moveDown("op=demoteWorkflowActivity;workflowId=".$workflow->getId.";activityId=".$id) .$session->icon->moveUp("op=promoteWorkflowActivity;workflowId=".$workflow->getId.";activityId=".$id) .''.$title.'
'; my $ac = WebGUI::AdminConsole->new($session,"workflow"); $ac->addSubmenuItem($session->url->page("op=addWorkflow"), $i18n->get("add a new workflow")); $ac->addSubmenuItem($session->url->page("op=manageWorkflows"), $i18n->get("manage workflows")); $ac->setHelp('edit workflow','Workflow'); return $ac->render($f->print.$addmenu.$steps, 'edit workflow'); } #------------------------------------------------------------------- =head2 www_editWorkflowPriority ( ) Save the submitted new workflow priority. =cut sub www_editWorkflowPriority { my $session = shift; return $session->privilege->insufficient() unless $session->user->isInGroup(3); my $i18n = WebGUI::International->new($session, 'Workflow'); my $ac = WebGUI::AdminConsole->new($session,"workflow"); $ac->addSubmenuItem($session->url->page("op=showRunningWorkflows"), $i18n->get('show running workflows')); $ac->setHelp('manage workflows', 'Workflow'); # make sure the input is good my $instanceId = $session->form->get('instanceId') || ''; my $newPriority = $session->form->get('newPriority') || ''; if (! $instanceId) { my $output = $i18n->get('edit priority bad request'); return $ac->render($output, $i18n->get('show running workflows')); } # make the request my $remote = create_ikc_client( port=>$session->config->get("spectrePort"), ip=>$session->config->get("spectreIp"), name=>rand(100000), timeout=>10 ); if (! $remote) { my $output = $i18n->get('edit priority no spectre error'); return $ac->render($output, $i18n->get('show running workflows')); } my $argHref = { instanceId => $instanceId, newPriority => $newPriority, }; my $resultJson = $remote->post_respond('workflow/editWorkflowPriority', $argHref); if (! defined $resultJson) { $remote->disconnect(); my $output = $i18n->get('edit priority no info error'); return $ac->render($output, $i18n->get('show running workflows')); } my $responseHref = jsonToObj($resultJson); my $message = $i18n->get($responseHref->{message}) || $i18n->get('edit priority unknown error'); return $ac->render($message, $i18n->get('show running workflows')); } #------------------------------------------------------------------- =head2 www_editWorkflowSave ( ) Saves the results of www_editWorkflow() =cut sub www_editWorkflowSave { my $session = shift; return $session->privilege->insufficient() unless ($session->user->isInGroup("pbgroup000000000000015")); my $workflow = WebGUI::Workflow->new($session, $session->form->param("workflowId")); $workflow->set({ enabled => $session->form->get("enabled", "yesNo"), mode => $session->form->get("mode"), title => $session->form->get("title"), description => $session->form->get("description", "textarea"), }); return www_editWorkflow($session, $workflow); } #------------------------------------------------------------------- =head2 www_editWorkflowActivity ( ) Displays a form to edit the properties of a workflow activity. =cut sub www_editWorkflowActivity { my $session = shift; return $session->privilege->insufficient() unless ($session->user->isInGroup("pbgroup000000000000015")); my $activity = ''; if ($session->form->process("className","className")) { $activity = WebGUI::Workflow::Activity->newByPropertyHashRef($session, {activityId=>"new",className=>$session->form->process("className","className")}); } else { $activity = WebGUI::Workflow::Activity->new($session, $session->form->get("activityId")); } my $form = $activity->getEditForm; $form->hidden( name=>"op", value=>"editWorkflowActivitySave"); $form->hidden( name=>"workflowId", value=>$session->form->get("workflowId")); $form->submit; my $i18n = WebGUI::International->new($session, "Workflow"); my $ac = WebGUI::AdminConsole->new($session,"workflow"); $ac->addSubmenuItem($session->url->page("op=addWorkflow"), $i18n->get("add a new workflow")); $ac->addSubmenuItem($session->url->page("op=manageWorkflows"), $i18n->get("manage workflows")); return $ac->render($form->print,$activity->getName); } #------------------------------------------------------------------- =head2 www_editWorkflowActivitySave ( ) Saves the results of www_editWorkflowActivity(). =cut sub www_editWorkflowActivitySave { my $session = shift; return $session->privilege->insufficient() unless ($session->user->isInGroup("pbgroup000000000000015")); my $workflow = WebGUI::Workflow->new($session, $session->form->get("workflowId")); if (defined $workflow) { my $activityId = $session->form->get("activityId"); my $activity = ''; if ($activityId eq "new") { $activity = $workflow->addActivity($session->form->process("className","className")); } else { $activity = $workflow->getActivity($activityId); } $activity->processPropertiesFromFormPost; } return www_editWorkflow($session); } #------------------------------------------------------------------- =head2 www_manageWorkflows ( ) Display a list of the workflows. =cut sub www_manageWorkflows { my $session = shift; return $session->privilege->insufficient() unless ($session->user->isInGroup("pbgroup000000000000015")); my $i18n = WebGUI::International->new($session, "Workflow"); my $output = ''; my $rs = $session->db->read("select workflowId, title, enabled from Workflow order by title"); while (my ($id, $title, $enabled) = $rs->array) { $output .= '\n"; } $output .= '
' .$session->icon->delete("op=deleteWorkflow;workflowId=".$id, undef, $i18n->get("are you sure you want to delete this workflow")) .$session->icon->edit("op=editWorkflow;workflowId=".$id) .''.$title.'' .($enabled ? $i18n->get("enabled") : $i18n->get("disabled")) ."
'; my $ac = WebGUI::AdminConsole->new($session,"workflow"); $ac->addSubmenuItem($session->url->page("op=addWorkflow"), $i18n->get("add a new workflow")); $ac->addSubmenuItem($session->url->page("op=showRunningWorkflows"), $i18n->get("show running workflows")); $ac->setHelp('manage workflows', 'Workflow'); return $ac->render($output, 'manage workflows'); } #------------------------------------------------------------------ =head2 www_promoteWorkflowActivity ( session ) Moves a workflow activity up one position in the execution order. =head3 session A reference to the current session. =cut sub www_promoteWorkflowActivity { my $session = shift; return $session->privilege->insufficient() unless ($session->user->isInGroup("pbgroup000000000000015")); my $workflow = WebGUI::Workflow->new($session, $session->form->param("workflowId")); $workflow->promoteActivity($session->form->param("activityId")); return www_editWorkflow($session); } #------------------------------------------------------------------- =head2 www_runWorkflow ( ) Checks to ensure the requestor is who we think it is, and then executes a workflow and returns the results. =cut sub www_runWorkflow { my $session = shift; $session->http->setMimeType("text/plain"); $session->http->setCacheControl("none"); unless (isInSubnet($session->env->get("REMOTE_ADDR"), $session->config->get("spectreSubnets")) || $session->user->isInGroup("3")) { $session->errorHandler->security("make a Spectre workflow runner request, but we're only allowed to accept requests from ".join(",",@{$session->config->get("spectreSubnets")})."."); return "error"; } my $instanceId = $session->form->param("instanceId"); if ($instanceId) { my $instance = WebGUI::Workflow::Instance->new($session, $instanceId); if (defined $instance) { return $instance->run; } else { return "done"; } return "complete"; } $session->errorHandler->warn("No instance ID passed to workflow runner."); return "error"; } #------------------------------------------------------------------- =head2 www_showRunningWorkflows ( ) Display a list of the running workflow instances. =cut sub www_showRunningWorkflows { my $session = shift; return $session->privilege->insufficient() unless ($session->user->isInGroup("pbgroup000000000000015")); my $i18n = WebGUI::International->new($session, "Workflow"); my $ac = WebGUI::AdminConsole->new($session,"workflow"); my $isAdmin = $session->user->isInGroup("3"); # javascript for creating/showing/hiding the edit priority form my $cancel = $i18n->get('edit priority cancel'); my $updatePriority = $i18n->get('edit priority update priority'); my $output = <<"ENDCODE"; ENDCODE my $remote = create_ikc_client( port=>$session->config->get("spectrePort"), ip=>$session->config->get("spectreIp"), name=>rand(100000), timeout=>10 ); if (! $remote) { my $output = $i18n->get('spectre not running error'); return $ac->render($output, $i18n->get('show running workflows')); } my $sitename = $session->config()->get('sitename')->[0]; my $workflowResult = $remote->post_respond('workflow/getJsonStatus',$sitename); if (! defined $workflowResult) { $remote->disconnect(); my $output = $i18n->get('spectre no info error'); return $ac->render($output, $i18n->get('show running workflows')); } my $workflowsHref = jsonToObj($workflowResult); my $workflowTitleFor = $session->db->buildHashRef(<<""); SELECT wi.instanceId, w.title FROM WorkflowInstance wi JOIN Workflow w USING (workflowId) my $lastActivityFor = $session->db->buildHashRef(<<""); SELECT wi.instanceId, wa.title FROM WorkflowInstance wi JOIN WorkflowActivity wa ON wi.currentActivityId = wa.activityId for my $workflowType (qw( Suspended Waiting Running )) { my $workflowsAref = $workflowsHref->{$workflowType}; my $workflowCount = @$workflowsAref; my $titleHeader = $i18n->get('title header'); my $priorityHeader = $i18n->get('priority header'); my $activityHeader = $i18n->get('activity header'); my $lastStateHeader = $i18n->get('last state header'); my $lastRunTimeHeader = $i18n->get('last run time header'); $output .= sprintf $i18n->get('workflow type count'), $workflowCount, $workflowType; $output .= ''; $output .= ""; $output .= ""; for my $workflow (@$workflowsAref) { my($priority, $id, $instance) = @$workflow; my $originalPriority = ($instance->{priority} - 1) * 10; my $instanceId = $instance->{instanceId}; my $title = $workflowTitleFor->{$instanceId} || '(no title)'; my $lastActivity = $lastActivityFor->{$instanceId} || '(none)'; my $lastRunTime = $instance->{lastRunTime} || '(never)'; $output .= ''; $output .= ""; $output .= qq[]; $output .= ""; $output .= ""; $output .= ""; if ($isAdmin) { my $run = $i18n->get('run'); my $href = $session->url->page(qq[op=runWorkflow;instanceId=$instanceId]); $output .= qq[]; } $output .= "\n"; } $output .= '
$titleHeader$priorityHeader$activityHeader$lastStateHeader$lastRunTimeHeader
$title$priority/$originalPriority$lastActivity$instance->{lastState}$lastRunTime$run
'; } $ac->addSubmenuItem($session->url->page("op=addWorkflow"), $i18n->get("add a new workflow")); $ac->addSubmenuItem($session->url->page("op=manageWorkflows"), $i18n->get("manage workflows")); $ac->setHelp('show running workflows', 'Workflow'); return $ac->render($output, 'show running workflows'); } 1;