...
 
Commits (516)
*.DS_Store
<?php
/**
* @file
* Filter based on moderation state.
*/
class workbench_moderation_handler_filter_state extends views_handler_filter_in_operator {
function get_value_options() {
if (!isset($this->value_options)) {
$this->value_title = t('Workbench Moderation States');
$this->value_options = array_map('check_plain', workbench_workflows_options('states'));
}
}
}
/**
* @file
* Sets the summary for Workbench moderation on vertical tabs.
*/
(function ($) {
Drupal.behaviors.workbenchModerationSettingsSummary = {
attach: function(context) {
// Set summary for the revisions information tab to use the event select
// list.
$('fieldset.node-form-revision-information', context).drupalSetSummary(function (context) {
var vals = [];
// @todo, "event" is too generic of a name and might change in the future.
if ($('select[name="event"]', context).val()) {
vals.push(Drupal.checkPlain($('select[name="event"] option:selected').text()));
}
return vals.join(', ');
});
// Override the summary for what core calls publishing options.
$('fieldset.node-form-options', context).drupalSetSummary(function (context) {
var vals = [];
$('input:checked', context).parent().each(function () {
vals.push(Drupal.checkPlain($.trim($(this).text())));
});
return vals.join(', ');
});
}
};
})(jQuery);
<?php
/**
* @file
*
* Functions to install exportables.
*/
/**
* Save the starter exportables to the database.
*/
function workbench_workflows_import_starter_exportables() {
ctools_include('export');
$exportables = _workbench_workflows_starter_exportables();
foreach ($exportables as $exportable_type => $set_of_exportables) {
foreach ($set_of_exportables as $exportable_machine_name => $exportable) {
ctools_export_crud_save('workbench_workflows_' . $exportable_type, $exportable);
}
}
}
/**
* Returns an array of exported starter states, events, and one workflow.
*/
function _workbench_workflows_starter_exportables() {
$events = array();
$exportables = array();
$event = new stdClass();
$event->export_type = EXPORT_IN_CODE;
$event->disabled = FALSE; /* Edit this to true to make a default event disabled initially */
$event->api_version = 1;
$event->name = 'draft';
$event->editor_title = '';
$event->admin_title = 'Draft';
$event->admin_description = '';
$event->requiredcontexts = array(
0 => array(
'identifier' => 'Node',
'keyword' => 'node',
'name' => 'entity:node',
'id' => 1,
),
);
$event->contexts = array();
$event->relationships = array();
$event->access = array(
'logic' => 'and',
);
$event->weight = 0;
$event->target_state = 'draft';
$event->origin_states = array(
'draft' => 'draft',
'needs_review' => 'needs_review',
'published' => 'published',
);
$events['draft'] = $event;
$event = new stdClass();
$event->export_type = EXPORT_IN_CODE;
$event->disabled = FALSE; /* Edit this to true to make a default event disabled initially */
$event->api_version = 1;
$event->name = 'needs_review';
$event->editor_title = '';
$event->admin_title = 'Needs Review';
$event->admin_description = '';
$event->requiredcontexts = array(
0 => array(
'identifier' => 'Node',
'keyword' => 'node',
'name' => 'entity:node',
'id' => 1,
),
);
$event->contexts = array();
$event->relationships = array();
$event->access = array(
'logic' => 'and',
);
$event->weight = 0;
$event->target_state = 'needs_review';
$event->origin_states = array(
'draft' => 'draft',
'needs_review' => 'needs_review',
'published' => 'published',
);
$events['needs_review'] = $event;
$event = new stdClass();
$event->export_type = EXPORT_IN_CODE;
$event->disabled = FALSE; /* Edit this to true to make a default event disabled initially */
$event->api_version = 1;
$event->name = 'published';
$event->editor_title = '';
$event->admin_title = 'Published';
$event->admin_description = '';
$event->requiredcontexts = array(
0 => array(
'identifier' => 'Node',
'keyword' => 'node',
'name' => 'entity:node',
'id' => 1,
),
);
$event->contexts = array();
$event->relationships = array();
$event->access = array(
'logic' => 'and',
);
$event->weight = 0;
$event->target_state = 'published';
$event->origin_states = array(
'draft' => 'draft',
'needs_review' => 'needs_review',
'published' => 'published',
);
$events['published'] = $event;
$exportables['events'] = $events;
$states = array();
$state = new stdClass();
$state->export_type = EXPORT_IN_CODE;
$state->disabled = FALSE; /* Edit this to true to make a default state disabled initially */
$state->api_version = 1;
$state->name = 'draft';
$state->editor_title = '';
$state->admin_title = 'Draft';
$state->admin_description = '';
$state->requiredcontexts = array(
0 => array(
'identifier' => 'Node',
'keyword' => 'node',
'name' => 'entity:node',
'id' => 1,
),
);
$state->contexts = array();
$state->relationships = array();
$state->access = array();
$state->weight = 0;
$state->entity_state_change = WORKBENCH_WORKFLOWS_STATE_UNCHANGED;
$states['draft'] = $state;
$state = new stdClass();
$state->export_type = EXPORT_IN_CODE;
$state->disabled = FALSE; /* Edit this to true to make a default state disabled initially */
$state->api_version = 1;
$state->name = 'needs_review';
$state->editor_title = '';
$state->admin_title = 'Needs Review';
$state->admin_description = '';
$state->requiredcontexts = array(
0 => array(
'identifier' => 'Node',
'keyword' => 'node',
'name' => 'entity:node',
'id' => 1,
),
);
$state->contexts = array();
$state->relationships = array();
$state->access = array();
$state->weight = 0;
$state->entity_state_change = WORKBENCH_WORKFLOWS_STATE_UNCHANGED;
$states['needs_review'] = $state;
$state = new stdClass();
$state->export_type = EXPORT_IN_CODE;
$state->disabled = FALSE; /* Edit this to true to make a default state disabled initially */
$state->api_version = 1;
$state->name = 'published';
$state->editor_title = '';
$state->admin_title = 'Published';
$state->admin_description = '';
$state->requiredcontexts = array(
0 => array(
'identifier' => 'Node',
'keyword' => 'node',
'name' => 'entity:node',
'id' => 1,
),
);
$state->contexts = array();
$state->relationships = array();
$state->access = array();
$state->weight = 0;
$state->entity_state_change = WORKBENCH_WORKFLOWS_STATE_PUBLISHED;
$states['published'] = $state;
$exportables['states'] = $states;
$workflows = array();
$workflow = new stdClass();
$workflow->export_type = EXPORT_IN_CODE;;
$workflow->disabled = FALSE; /* Edit this to true to make a default workflow disabled initially */
$workflow->api_version = 1;
$workflow->name = 'default_workflow';
$workflow->editor_title = '';
$workflow->admin_title = 'Default Workflow';
$workflow->admin_description = '';
$workflow->requiredcontexts = array(
0 => array(
'identifier' => 'Node',
'keyword' => 'node',
'name' => 'entity:node',
'id' => 1,
),
);
$workflow->contexts = array();
$workflow->relationships = array();
$workflow->access = array();
$workflow->weight = 2;
$workflow->category = '';
$workflow->states = array(
'draft' => 'draft',
'needs_review' => 'needs_review',
'published' => 'published',
);
$workflow->events = array(
'draft' => 'draft',
'needs_review' => 'needs_review',
'published' => 'published',
);
$workflows['sample_workflow'] = $workflow;
$exportables['workflows'] = $workflows;
return $exportables;
}
<?php
/**
* @file
*
* A base class meant to be extended by the workbench_workflows_ui, workbench_states_ui, workbench_events_ui.
*/
class workbench_base_ui extends ctools_export_ui {
function edit_form(&$form, &$form_state) {
// Get the basic edit form
parent::edit_form($form, $form_state);
// @todo, add a description.
$form['weight'] = array(
'#type' => 'textfield',
'#default_value' => $form_state['item']->weight,
'#title' => t('Weight'),
'#element_validate' => array('element_validate_integer'),
);
}
function edit_form_context(&$form, &$form_state) {
// Force setting of the node required context.
// @todo, add a way of setting which entity type this state, event, workflow works with.
$form_state['item']->requiredcontexts = array(
0 => array(
'identifier' => 'Node',
'keyword' => 'node',
'name' => 'entity:node',
'id' => 1
)
);
ctools_include('context-admin');
ctools_context_admin_includes();
ctools_add_css('ruleset');
// Set this up and we can use CTools' Export UI's built in wizard caching,
// which already has callbacks for the context cache under this name.
$module = 'export_ui::' . $this->plugin['name'];
$name = $this->edit_cache_get_key($form_state['item'], $form_state['form type']);
ctools_context_add_relationship_form($module, $form, $form_state, $form['relationships_table'], $form_state['item'], $name);
// While these modules are in an experimental state, throw this message in
// for some clarity.
drupal_set_message(t("This is a screen where the CTools export UI needs customization to fit the needs of States/Events/Workflows.
<br /><br />
The idea here is that a site builder could start from an article node and bring in related contexts. For instance the relevant Organic
Group could be brought it with one of these relationship plugins. One the next screen the site builder can then use the relevant Organic Group
as the basis for access control. So the end user's access to this state/event/workflow could be restricted on an arbitrary condition of the Organic
Group, like its published status or taxonomy values.
<br /><br />
If you have an opinion on how to improve this UI please go to
<a href='http://drupal.org/node/1376258'>http://drupal.org/node/1376258</a>"), 'warning');
}
function edit_form_access(&$form, &$form_state) {
// The 'access' UI passes everything via $form_state, unlike the 'context' UI.
// The main difference is that one is about 3 years newer than the other.
ctools_include('context');
ctools_include('context-access-admin');
$form_state['access'] = $form_state['item']->access;
$form_state['contexts'] = ctools_context_load_contexts($form_state['item']);
$form_state['module'] = 'ctools_export_ui';
$form_state['callback argument'] = $form_state['object']->plugin['name'] . ':' . $form_state['object']->edit_cache_get_key($form_state['item'], $form_state['form type']);
$form_state['no buttons'] = TRUE;
$form = ctools_access_admin_form($form, $form_state);
// While these modules are in an experimental state, throw this message in
// for some clarity.
drupal_set_message(t("Here the site builder can set arbitary restrictions on when this state/event/workflow
is available. For instance the site builder could make this available under the condition that the currently
logged in user is either the node author (if this is a node state/event/workflow) or has the role 'site contributor'.
<br /><br />
If you have an opinion on how to improve this UI please go to
<a href='http://drupal.org/node/1376258'>http://drupal.org/node/1376258</a>"), 'warning');
}
function edit_form_rules_submit(&$form, &$form_state) {
$form_state['item']->access['logic'] = $form_state['values']['logic'];
}
function edit_save_form($form_state) {
parent::edit_save_form($form_state);
cache_clear_all('ctools_plugin_files:state_flow_entity', 'cache', TRUE);
cache_clear_all('plugins:state_flow_entity', 'cache', TRUE);
}
}
<?php
/**
* @file
* Export UI plugin for events.
*/
module_load_include('inc', 'workbench_workflows', 'workbench_workflows.admin');
$plugin = workbench_workflows_export_ui_base_plugin('event');
<?php
/**
* @file
*
* The UI class for events exportables.
*/
module_load_include('php', 'workbench_workflows', 'plugins/export_ui/workbench_base_ui.class');
class workbench_events_ui extends workbench_base_ui {
function edit_form(&$form, &$form_state) {
// Get the basic edit form.
parent::edit_form($form, $form_state);
$form['schedulable'] = array(
'#type' => 'checkbox',
'#default_value' => !empty($form_state['item']->schedulable) || (isset($form_state['item']->name) && $form_state['item']->name == 'schedule'),
'#title' => t('Schedulable'),
'#description' => t('Allow scheduling by State Flow Schedule'),
'#access' => module_exists('state_flow_schedule'),
);
$form['target_state'] = array(
'#type' => 'select',
'#options' => workbench_workflows_options('states'),
'#default_value' => $form_state['item']->target_state,
'#title' => t('Target State'),
'#description' => t(""),
);
$form['origin_states'] = array(
'#type' => 'checkboxes',
'#options' => workbench_workflows_options('states'),
'#default_value' => $form_state['item']->origin_states,
'#title' => t('Origin States'),
'#description' => t(""),
);
}
/**
* @todo, need to validate the origin and target states.
*/
function edit_form_basic_validate($form, &$form_state) {
parent::edit_form_validate($form, $form_state);
// if (preg_match("/[^A-Za-z0-9 ]/", $form_state['values']['category'])) {
// form_error($form['category'], t('Categories may contain only alphanumerics or spaces.'));
// }
}
}
<?php
/**
* @file
* Export UI plugin for states.
*/
module_load_include('inc', 'workbench_workflows', 'workbench_workflows.admin');
$plugin = workbench_workflows_export_ui_base_plugin('state');
<?php
/**
* @file
*
* The UI class for states exportables.
*/
module_load_include('php', 'workbench_workflows', 'plugins/export_ui/workbench_base_ui.class');
class workbench_states_ui extends workbench_base_ui {
function edit_form(&$form, &$form_state) {
// Get the basic edit form.
parent::edit_form($form, $form_state);
$form['entity_state_change'] = array(
'#type' => 'radios',
'#default_value' => (isset($form_state['item']->entity_state_change)) ? $form_state['item']->entity_state_change : WORKBENCH_WORKFLOWS_STATE_UNCHANGED,
'#title' => t('Entity status'),
'#options' => array(
WORKBENCH_WORKFLOWS_STATE_UNCHANGED => t("Don't change status"),
WORKBENCH_WORKFLOWS_STATE_UNPUBLISHED => t('Unpublished'),
WORKBENCH_WORKFLOWS_STATE_PUBLISHED => t('Published'),
),
'#description' => t('Defines the status the entity will have when entering this moderation state.'),
);
}
}
<?php
/**
* @file
* Export UI plugin for workflows.
*/
module_load_include('inc', 'workbench_workflows', 'workbench_workflows.admin');
$plugin = workbench_workflows_export_ui_base_plugin('workflow');
// Override the form info because workflows have an extra screen.
$plugin['form info']['order'] = array(
'basic' => t('Settings'),
'events' => t('Events'),
'context' => t('Context'),
'access' => t('Access'),
);
<?php
/**
* @file
*
* The UI class for workflows exportables.
*/
module_load_include('php', 'workbench_workflows', 'plugins/export_ui/workbench_base_ui.class');
class workbench_workflows_ui extends workbench_base_ui {
function init($plugin) {
parent::init($plugin);
ctools_include('context');
}
/*
function list_form(&$form, &$form_state) {
parent::list_form($form, $form_state);
foreach ($this->items as $item) {
$categories[$item->category] = $item->category ? $item->category : t('workbench workflows');
}
$form['top row']['category'] = array(
'#type' => 'select',
'#title' => t('Category'),
'#options' => $categories,
'#default_value' => 'all',
'#weight' => -10,
);
}
function list_filter($form_state, $item) {
if ($form_state['values']['category'] != 'all' && $form_state['values']['category'] != $item->category) {
return TRUE;
}
return parent::list_filter($form_state, $item);
}
*/
function list_sort_options() {
return array(
'disabled' => t('Enabled, title'),
'title' => t('Title'),
'name' => t('Name'),
'category' => t('Category'),
'storage' => t('Storage'),
'weight' => t('Weight'),
);
}
function list_build_row($item, &$form_state, $operations) {
// Set up sorting
switch ($form_state['values']['order']) {
case 'disabled':
$this->sorts[$item->name] = empty($item->disabled) . $item->admin_title;
break;
case 'title':
$this->sorts[$item->name] = $item->admin_title;
break;
case 'name':
$this->sorts[$item->name] = $item->name;
break;
case 'category':
$this->sorts[$item->name] = ($item->category ? $item->category : t('workbench workflows')) . $item->admin_title;
break;
case 'weight':
$this->sorts[$item->name] = $item->weight;
break;
case 'storage':
$this->sorts[$item->name] = $item->type . $item->admin_title;
break;
}
$category = $item->category ? check_plain($item->category) : t('workbench workflows');
$this->rows[$item->name] = array(
'data' => array(
array('data' => check_plain($item->admin_title), 'class' => array('ctools-export-ui-title')),
array('data' => check_plain($item->name), 'class' => array('ctools-export-ui-name')),
array('data' => $category, 'class' => array('ctools-export-ui-category')),
array('data' => $item->type, 'class' => array('ctools-export-ui-storage')),
array('data' => $item->weight, 'class' => array('ctools-export-ui-weight')),
array('data' => theme('links', array('links' => $operations)), 'class' => array('ctools-export-ui-operations')),
),
'title' => !empty($item->admin_description) ? check_plain($item->admin_description) : '',
'class' => array(!empty($item->disabled) ? 'ctools-export-ui-disabled' : 'ctools-export-ui-enabled'),
);
}
function list_table_header() {
return array(
array('data' => t('Title'), 'class' => array('ctools-export-ui-title')),
array('data' => t('Name'), 'class' => array('ctools-export-ui-name')),
array('data' => t('Category'), 'class' => array('ctools-export-ui-category')),
array('data' => t('Storage'), 'class' => array('ctools-export-ui-storage')),
array('data' => t('Weight'), 'class' => array('ctools-export-ui-weight')),
array('data' => t('Operations'), 'class' => array('ctools-export-ui-operations')),
);
}
function edit_form(&$form, &$form_state) {
// Get the basic edit form
parent::edit_form($form, $form_state);
$form['title']['#title'] = t('Title');
$form['title']['#description'] = t('The title for this workbench workflow.');
$form['states'] = array(
'#type' => 'checkboxes',
'#options' => workbench_workflows_options('states'),
'#default_value' => $form_state['item']->states,
'#title' => t('States'),
'#description' => t("States available in this workflow."),
);
$form['default_state'] = array(
'#type' => 'radios',
'#options' => workbench_workflows_options('states'),
'#default_value' => isset($form_state['item']->default_state) ? $form_state['item']->default_state : NULL,
'#title' => t('Default state'),
'#description' => t("The starting state of the workflow."),
);
}
/**
* Validate submission of the workbench workflow edit form.
*
* @todo evaluate need to validate states here.
*/
function edit_form_basic_validate($form, &$form_state) {
parent::edit_form_validate($form, $form_state);
// if (preg_match("/[^A-Za-z0-9 ]/", $form_state['values']['category'])) {
// form_error($form['category'], t('Categories may contain only alphanumerics or spaces.'));
// }
}
function edit_form_events(&$form, &$form_state) {
$available_states = array();
foreach ($form_state['item']->states as $key => $value) {
if (!empty($value)) {
$available_states[$key] =$value;
}
}
ctools_include('export');
$workbench_events = workbench_workflows_load_all('events');
$event_options = array();
$unavailable_events = array();
$unavailable_text_string = '';
$unavailable_events_replacements = array();
foreach ($workbench_events as $workbench_event) {
// @todo
// Exclude events when there is not an origin state in the workflow.
if (in_array($workbench_event->target_state, $available_states)) {
$event_options[$workbench_event->name] = $workbench_event->admin_title;
}
else {
$unavailable_text_string .= '%' . $workbench_event->name . ', ';
$unavailable_events[$workbench_event->name] = $workbench_event->admin_title;
$unavailable_events_replacements['%' . $workbench_event->name] = $workbench_event->admin_title;
}
}
$form['events'] = array(
'#type' => 'checkboxes',
'#options' => $event_options,
'#default_value' => $form_state['item']->events,
'#title' => t('Events'),
);
// @@TODO
// Handle pluralization of event/events
if (!empty($unavailable_text_string)) {
$form['events']['#description'] = t("Unavailable events include: " . $unavailable_text_string, $unavailable_events_replacements);
}
}
}
<?php
/**
* @file
* A class to mark a node as ignored by State Machine / Workbench Workflows.
*/
class WorkbenchWorkflowsIgnore extends StateFlowNode {
public function init($workflow = array()) {
}
public function ignore() {
return TRUE;
}
}
\ No newline at end of file
<?php
/**
* @file
* Provides tests.
*/
/**
* Tests for Workbench Workflows
*/
class WorkbenchWorkflowsTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Workbench Workflows Web Tests',
'description' => '',
'group' => 'Workbench Workflows',
);
}
protected function setUp() {
parent::setUp(array('workbench_workflows'));
module_load_include('inc', 'workbench_workflows', 'includes/workbench_workflows.starter');
workbench_workflows_import_starter_exportables();
}
/**
* Tests the upgrade routines (outside of the user interface).
*/
protected function testInstallOfExportables() {
// These are the machine names and labels of the expected starter
// states, events, and workflows.
$exportables = array(
'states' => array(
'draft' => 'Draft',
'needs_review' => 'Needs Review',
'published' => 'Published',
),
'events' => array(
'draft' => 'Draft',
'needs_review' => 'Needs Review',
'published' => 'Published',
),
'workflows' => array(
'default_workflow' => 'Default Workflow',
),
);
foreach ($exportables as $exportable_type => $set_of_exportables) {
foreach ($set_of_exportables as $exportable_machine_name => $exportable_admin_title) {
$loaded_exportable = workbench_workflows_load($exportable_type, $exportable_machine_name);
$this->assertEqual($loaded_exportable->admin_title, $exportable_admin_title, 'Loading ' . $exportable_type . ': ' . $exportable_machine_name . ' was loaded.');
}
}
}
}
/**
* Tests for Workbench Workflows
*/
class WorkbenchWorkflowsAdminUITestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Workbench Workflows Admin UI Web Tests',
'description' => '',
'group' => 'Workbench Workflows',
);
}
protected function setUp() {
parent::setUp(array('workbench_workflows'));
}
/**
* Test View Draft tab.
*/
function testUIInstallofDefaultWorkflow() {
$web_user = $this->drupalCreateUser(array('administer_workbench_workflows', 'access administration pages', 'administer site configuration'));
$this->drupalLogin($web_user);
// Load all states, events, workflows.
$states = workbench_workflows_load_all('states');
$events = workbench_workflows_load_all('events');
$workflows = workbench_workflows_load_all('workflows');
// Confirm that none of these types have any objects.
$this->assert(empty($states), 'There are no states');
$this->assert(empty($events), 'There are no events');
$this->assert(empty($workflows), 'There are no workflows');
// Check that the form mesage is present.
$this->drupalGet("admin/reports/status");
$this->assertText('There are no states, events, or workflows yet on this site. Would you like to install a default configuration?', 'Default configuration message found.');
// Submit the form.
$edit = array();
$this->drupalPost("admin/reports/status", $edit, t('Install the default workflow'));
// Load all states, events, workflows.
$states = workbench_workflows_load_all('states', TRUE);
$events = workbench_workflows_load_all('events');
$workflows = workbench_workflows_load_all('workflows');
// Confirm that none of these types have any objects.
$this->assert(count($states) === 3, 'There are three states');
$this->assert(count($events) === 3, 'There are three events');
$this->assert(count($workflows) === 1, 'There is one workflow');
// Check for the post-install message.
$this->assertText('A default workflow with the states and events of Draft, Needs Review, and Published.', 'Post-install message found.');
// Go to the page again and check that the form is gone.
$this->drupalGet("admin/reports/status");
// Check that the form mesage is no longer present.
$this->assertNoText('There are no states, events, or workflows yet on this site. Would you like to install a default configuration?', 'Default configuration message found not found after installation of default configuration.');
// @todo, check for a status message indicationthat configuration is present.
// @todo, check that all the objects are installed.
$this->drupalGet("admin/config/workflow/workbench-workflows/states");
$this->assertRaw('<td class="ctools-export-ui-title">Draft</td>', 'The Draft state is present.');
$this->assertRaw('<td class="ctools-export-ui-title">Needs Review</td>', 'The Needs Review state is present.');
$this->assertRaw('<td class="ctools-export-ui-title">Published</td>', 'The Published state is present.');
// @todo, check that all the objects are installed.
$this->drupalGet("admin/config/workflow/workbench-workflows/events");
$this->assertRaw('<td class="ctools-export-ui-title">Draft</td>', 'The Draft event is present.');
$this->assertRaw('<td class="ctools-export-ui-title">Needs Review</td>', 'The Needs Review event is present.');
$this->assertRaw('<td class="ctools-export-ui-title">Published</td>', 'The Published event is present.');
// @todo, check that all the objects are installed.
$this->drupalGet("admin/config/workflow/workbench-workflows/workflows");
$this->assertRaw('<td class="ctools-export-ui-title">Default Workflow</td>', 'Default Workflow');
}
}
<?php
/**
* @file
*
* Administrative functions for workbench_workflows.
*/
/**
* @param string $type
* Allowed values are 'state', 'event', and 'workflow'
* @return array
*/
function workbench_workflows_export_ui_base_plugin($type) {
$plural = $type . 's';
$plugin = array(
"schema" => "workbench_workflows_$plural",
"access" => "administer_workbench_workflows",
"menu" => array(
"menu prefix" => "admin/config/workflow/workbench-workflows",
"menu item" => $plural,
"menu title" => "Workbench " . $plural,
"menu description" => "Add, edit or delete Workbench " . drupal_ucfirst($plural),
),
"title singular" => t("workbench $type"),
"title singular proper" => t("Workbench " . drupal_ucfirst($type)),
"title plural" => t("workbench $type"),
"title plural proper" => t("Workbench " . drupal_ucfirst($plural)),
"handler" => "workbench_" . $plural . "_ui",
"use wizard" => TRUE,
"form info" => array(
"order" => array(
"basic" => t("Basic information"),
"context" => t("Contexts"),
"access" => t("Access"),
),
),
);
return $plugin;
}
name = Workbench Workflows
description = Exportable workflows
package = Workbench
dependencies[] = ctools
; @todo, do all files need to be declared here?
files[] = plugins/export_ui/workbench_workflows_ui.class.php
files[] = plugins/state_flow_entity/workbench_workflows_ignore.inc
files[] = tests/workbench_workflows.test
core = "7.x"
<?php
/**
* @file
* Database functions for workbench_workflows.
*/
/**
* Implements hook_schema().
*/
function workbench_workflows_schema() {
$schema = array();
// Define the states schema.
$schema["workbench_workflows_states"] = workbench_workflows_starter_schema('state');
// Add fields to the states schema.
$additional_state_fields = array(
'entity_state_change' => array(
'type' => 'int',
'length' => 'small',
'description' => 'Defines the state change on the entity level',
'object default' => -1,
),
);
$schema['workbench_workflows_states']['fields'] = array_merge($schema['workbench_workflows_states']['fields'], $additional_state_fields);
// Define the events schema.
$schema["workbench_workflows_events"] = workbench_workflows_starter_schema('event');
// Add fields to the events schema.
$additional_event_fields = array(
'target_state' => array(
'type' => 'varchar',
'length' => '255',
'description' => 'target state',
),
'origin_states' => array(
'type' => 'text',
'size' => 'big',
'description' => 'Origin states',
'serialize' => TRUE,
'object default' => array(),
),
'schedulable' => array(
'type' => 'int',
'size' => 'tiny',
'description' => 'This state can be scheduled with state flow scheduler',
'object default' => FALSE,
),
);
$schema["workbench_workflows_events"]['fields'] = array_merge($schema["workbench_workflows_events"]['fields'], $additional_event_fields);
// Define the workflows schema
$schema["workbench_workflows_workflows"] = workbench_workflows_starter_schema('workflow');
$additional_workflow_fields = array(
'category' => array(
'type' => 'varchar',
'length' => '64',
'description' => 'The category this workbench workflow appears in.',
),
'states' => array(
'type' => 'text',
'size' => 'big',
'serialize' => TRUE,
'object default' => array(),
'description' => 'An array of states allowed in the workflow',
),
'default_state' => array(
'type' => 'text',
'size' => 'big',
'serialize' => FALSE,
'object default' => '',
'description' => 'The starter state of the workflow.',
),
'events' => array(
'type' => 'text',
'size' => 'big',
'serialize' => TRUE,
'object default' => array(),
'description' => 'An array of events allowed in the workflow',
),
);
$schema["workbench_workflows_workflows"]['fields'] = array_merge($schema["workbench_workflows_workflows"]['fields'], $additional_workflow_fields);
return $schema;
}
/**
* Helper function for defining schema.
*/
function workbench_workflows_starter_schema($type) {
$plural = $type . 's';
$schema = array(
"description" => "Contains exportable customized $plural.",
"export" => array(
"identifier" => "$type",
"bulk export" => TRUE,
"primary key" => $type . "id",
"api" => array(
"owner" => "workbench_workflows",
"api" => "workbench_workflows",
"minimum_version" => 1,
"current_version" => 1,
),
),
"fields" => array(
$type . "id" => array(
"type" => "serial",
"description" => "A database primary key to ensure uniqueness",
"not null" => TRUE,
"no export" => TRUE,
),
"name" => array(
"type" => "varchar",
"length" => "255",
"description" => "Unique ID for this $type. Used to identify it programmatically.",
),
"editor_title" => array(
"type" => "varchar",
"length" => "255",
"description" => "Administrative title for this $type.",
),
"admin_title" => array(
"type" => "varchar",
"length" => "255",
"description" => "Administrative title for this $type.",
),
"admin_description" => array(
"type" => "text",
"size" => "big",
"description" => "Administrative description for this $type.",
"object default" => "",
),
"requiredcontexts" => array(
"type" => "text",
"size" => "big",
"description" => "Any required contexts for this $type.",
"serialize" => TRUE,
"object default" => array(),
),
"contexts" => array(
"type" => "text",
"size" => "big",
"description" => "Any embedded contexts for this $type.",
"serialize" => TRUE,
"object default" => array(),
),
"relationships" => array(
"type" => "text",
"size" => "big",
"description" => "Any relationships for this $type.",
"serialize" => TRUE,
"object default" => array(),
),
"access" => array(
"type" => "text",
"size" => "big",
"description" => "The actual group of access plugins for this $type.",
"serialize" => TRUE,
"object default" => array(),
),
'weight' => array(
'type' => 'int',
'description' => 'Weight',
),
),
"primary key" => array($type . "id"),
'unique keys' => array(
'name' => array('name'),
),
);
return $schema;
}
/**
* Implements hook_requirements().
*/
function workbench_workflows_requirements($phase) {
$requirements = array();
if($phase == 'runtime'){
$states = workbench_workflows_load_all('states');
$events = workbench_workflows_load_all('events');
$workflows = workbench_workflows_load_all('workflows');
if (empty($states) && empty($events) && empty($workflows)) {
$form = drupal_get_form('workbench_workflows_install_default_workflow_form');
$requirements['workbench_workflows_default'] = array(
'title' => t('Workbench Workflows default workflow'),
'value' => t('Install the default workflow'),
'description' => drupal_render($form),
'severity' => REQUIREMENT_WARNING,
);
}
}
return $requirements;
}
/**
* Provides a form to install the default workflow.
*/
function workbench_workflows_install_default_workflow_form($form, &$form_state) {
$form = array();
// @todo Would it be overkill to do a theme function for this form so that <p> tags
// are not added in a normal function?
$form['message'] = array(
'#markup' => '<p>' . t('There are no states, events, or workflows yet on this site. Would you like to install a default configuration?') . '</p>',
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Install the default workflow')
);
return $form;
}
/**
* Actually installs the default configuration.
*
* submit handler for workbench_workflows_install_default_workflow_form().
*/
function workbench_workflows_install_default_workflow_form_submit($form, &$form_state) {
module_load_include('inc', 'workbench_workflows', 'includes/workbench_workflows.starter');
workbench_workflows_import_starter_exportables();
// Notify the user that the default workflow is installed.
drupal_set_message(t('A default workflow with the states and events of Draft, Needs Review, and Published.'));
}
/**
* Helper to do db updates.
*
* Supported actions based on the schema hook:
* - Add new tables
* - Add new fields
* - Drop tables
*
* @param string $table
* The name of the table to update.
*/
function workbench_workflows_db_update($table) {
$schema = workbench_workflows_schema();
// If schema contains requested table handle it, else drop it.
if (isset($schema[$table])) {
// If table exists check existing items, else create table.
if (db_table_exists($table)) {
if (isset($schema[$table]['fields'])) {
foreach ($schema[$table]['fields'] as $field => $field_schema) {
if (!db_field_exists($table, $field)) {
db_add_field($table, $field, $field_schema);
}
}
}
}
else {
db_create_table($table, $schema[$table]);
}
}
elseif (db_table_exists($table)) {
db_drop_table($table);
}
}
/**
* Add new fields for state and event plugin to support event scheduling.
*/
function workbench_workflows_update_7000() {
workbench_workflows_db_update('workbench_workflows_states');
}
/**
* Add new fields for workflow to have default state per workflows.
*/
function workbench_workflows_update_7001() {
workbench_workflows_db_update('workbench_workflows_workflows');
}
This diff is collapsed.
<?php
/**
* @file
* Helper function for hook_state_flow_entity_plugins().
*/
/**
* Helper function for hook_state_flow_entity_plugins().
*/
function _workbench_workflows_state_flow_entity_plugins() {
$info = array();
// Load all workflows, events and states.
$workflows = workbench_workflows_load_all('workflows');
$event_exportables = workbench_workflows_load_all('events');
$state_exportables = workbench_workflows_load_all('states');
// We're just building on top of the state_flow plugins.
$class_path = drupal_get_path('module', 'state_flow') . '/plugins';
foreach ($workflows as $workflow) {
// This array will be built up and included with the state_flow plugin.
$workflow_options = array();
$workflow_options['default_state'] = $workflow->default_state;
// Build up states in a way compatible with state_flow_plugins.
foreach ($workflow->states as $state_name) {
// Make sure the load_all() array has the state.
if (isset($state_exportables[$state_name])) {
$state = $state_exportables[$state_name];
$state_array = array(
'label' => $state->admin_title,
);
if ($state->entity_state_change == WORKBENCH_WORKFLOWS_STATE_PUBLISHED) {
$state_array['on_enter'] = 'on_enter_published';
$state_array['on_exit'] = 'on_exit_published';
}
// Integrate with state flow schedule.
elseif ($state_name == 'schedule') {
$state_array['on_exit'] = 'on_exit_scheduled';
}
// @todo, this piece should be tested here as well as the unpublished
// test in state machine.
elseif ($state->entity_state_change == WORKBENCH_WORKFLOWS_STATE_UNPUBLISHED) {
$state_array['on_enter'] = 'on_enter_unpublished';
}
$workflow_options['states'][$state_name] = $state_array;
}
}
// Build up events in a way compatible with state_flow_plugins.
foreach ($workflow->events as $event_name) {
$origins = array();
// Make sure the load_all() array has the event.
if (isset($event_exportables[$event_name])) {
$event = $event_exportables[$event_name];
// Ensure only active origin_states are available.
$origins = array_filter($event->origin_states);
$target_state = $event->target_state;
$event_array = array(
'origin' => $origins,
'target' => $target_state,
'guard' => 'workbench_workflows_guard',
'label' => $event->admin_title,
);
$workflow_options['events'][$event_name] = $event_array;
}
}
$info['workbench_workflows__' . $workflow->name] = array(
'handler' => array(
// @todo, Once StateFlow can handle non-nodes, these properties will have
// to respond to something in the $workflow variable to change the class
// name and the file, parent etc.
'class' => 'StateFlowNode',
'file' => 'state_flow_node.inc',
'path' => $class_path,
'parent' => 'state_flow_entity',
'workflow_options' => $workflow_options,
'entity_type' => 'node',
// @todo, make this configurable in workflow exportables.
// @todo, should this key be inside "handler" or at the top level of the plugin?
'event_form_options' => array(
'event_element_label' => t('Change State'),
'require_log_message' => FALSE,
),
),
);
}
// A plugin for ignoring workflows.
$info['workbench_workflows_ignore'] = array(
'handler' => array(
'class' => 'WorkbenchWorkflowsIgnore',
'file' => 'workbench_workflows_ignore.inc',
'path' => drupal_get_path('module', 'workbench_workflows') . '/plugins/state_flow_entity',
'parent' => 'state_flow_node',
'workflow_options' => array(),
'entity_type' => 'node',
'event_form_options' => array(),
),
);
return $info;
}
/**
* Return the appropriate workflow for a node.
*/
function workbench_workflows_select_workflow($entity) {
$workflows = workbench_workflows_load_enabled('workflows');
foreach ($workflows as $workflow) {
if (workbench_workflows_exportable_access($entity, $workflow, 'workflows')) {
// Return the first workflow for which access returns TRUE.
return $workflow;
}
}
return FALSE;
}
This diff is collapsed.
This diff is collapsed.
name = Workbench Moderation
description = Workbench Moderation now extends State Flow
package = Workbench
core = 7.x
; Core classes
; files[] = plugins/state_flow/workbench_stateflow.inc @todo, remove this file
dependencies[] = state_machine (>2.99)
dependencies[] = state_flow (>2.99)
dependencies[] = views
; @todo, It's possible that workbench moderation could be used without
; workbench_workflows. There are currently coded assumptions that workbench_workflows is used.
dependencies[] = workbench_workflows
; added to support testbot due to dependencies set to >2.99 above
test_dependencies[] = state_machine (3.x)
files[]=includes/workbench_moderation_handler_filter_state.inc
files[] = tests/workbench_moderation.test
This diff is collapsed.
<?php
/**
* @file functions related to node pages.
*/
/**
* Displays the current draft the node, if it is not published.
*
* @param $node
* The node being acted upon.
*
* @return
* A fully themed node page.
*/
function workbench_moderation_node_view_draft($node) {
//get draft node
$draft_node = state_flow_entity_get_active_revision($node, 'node');
//return themed draft node page
return workbench_moderation_router_item_page_callback($draft_node);
}
/**
* Get the menu router item for nodes.
*
* @param $node
* The node being acted upon.
* @return
* A fully themed node page.
*/
function workbench_moderation_router_item_page_callback($node) {
$router_item = menu_get_item('node/' . $node->nid);
if ($router_item['include_file']) {
require_once DRUPAL_ROOT . '/' . $router_item['include_file'];
}
// Call whatever function is assigned to the main node path but pass the
// current node as an argument. This approach allows for the reuse of of Panel
// definition acting on node/%node.
return $router_item['page_callback']($node);
}
/**
* Displays a specific revisison of the node.
*
* @param $node
* The node being acted upon.
*
* @return
* A fully themed node page.
*/
function workbench_moderation_node_view_revision($node) {
return workbench_moderation_router_item_page_callback($node);
}
<?php
/**
* @file
* Content moderation views integration for Workbench.
*/
/**
* Implements hook_views_default_views().
*/
function workbench_moderation_views_default_views() {
$module = 'workbench_moderation';
$directory = 'views';
$extension = 'view.inc';
$name = 'view';
// From workbench_load_all_exports().
$return = array();
// Find all the files in the directory with the correct extension.
$files = file_scan_directory(drupal_get_path('module', $module) . "/$directory", "/.$extension/");
foreach ($files as $path => $file) {
require $path;
if (isset($$name)) {
$return[$$name->name] = $$name;
}
}
return $return;