...
 
Commits (336)
This diff is collapsed.
@CHARSET "UTF-8";
.current-revision td {
background-color: #faafbe;
}
.published-revision td {
background-color: #aaffaa;
}
.width-auto {
width: auto;
}
form.workbench-moderation-moderate-form,
form.workbench-moderation-moderate-form div,
form.workbench-moderation-moderate-form label {
display: inline;
}
#workbench-moderation-admin-transitions-form table {
min-width: 380px;
}
\ No newline at end of file
<?php
/**
* @file
* Provides a link to Moderation History for Views.
*/
class workbench_moderation_handler_field_history_link extends views_handler_field_node_link {
function render_link($data, $values) {
// ensure user has access to view moderation history for this node.
$node = node_load($this->get_value($values, 'nid'));
if (!_workbench_moderation_access('view history', $node)) {
return;
}
$this->options['alter']['make_link'] = TRUE;
$this->options['alter']['path'] = "node/$node->nid/moderation";
$text = !empty($this->options['text']) ? $this->options['text'] : t('View moderation history');
return $text;
}
}
<?php
/**
* @file
* Provides moderation links for Views.
*/
class workbench_moderation_handler_field_links extends views_handler_field {
function render($values) {
if ($values->{$this->aliases['is_current']}) {
$node = node_load($values->{$this->aliases['nid']}, $values->{$this->aliases['vid']});
return theme('links', array('links' => workbench_moderation_get_moderation_links($node, array('html' => TRUE, 'query' => array('destination' => $_GET['q'])))));
}
return '';
}
}
<?php
/**
* Field handler to translate a moderation state into its readable form.
*/
class workbench_moderation_handler_field_state extends views_handler_field_node {
function option_definition() {
$options = parent::option_definition();
$options['machine_name'] = array('default' => FALSE);
return $options;
}
/**
* Provide machine_name option for to node type display.
*/
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['machine_name'] = array(
'#title' => t('Output machine name'),
'#description' => t('Display field as the moderation state machine name.'),
'#type' => 'checkbox',
'#default_value' => !empty($this->options['machine_name']),
'#fieldset' => 'more',
);
}
/**
* Render node type as human readable name, unless using machine_name option.
*/
function render_name($data, $values) {
if ($this->options['machine_name'] != 1 && $data !== NULL && $data !== '') {
return t($this->sanitize_value(workbench_moderation_state_label($data)));
}
return $this->sanitize_value($data);
}
function render($values) {
$value = $this->get_value($values);
return $this->render_link($this->render_name($value, $values), $values);
}
}
<?php
/**
* @file
* Provides moderation filters for Views.
*/
/**
* Filter by whether a node type has moderation enabled or not.
*/
class workbench_moderation_handler_filter_moderated_type extends views_handler_filter_boolean_operator {
function query() {
if (!isset($this->value) || $this->value === NULL) {
return;
}
$node_types = workbench_moderation_moderate_node_types();
// If there are no node types using moderation set this variable to an array with a blank value.
// This will force the query to return no values.
if (empty($node_types)) {
$node_types = array('');
// Tell users to configure content types for moderation
// It's conceivable that a hook_menu_alter has changed the permission needed to get to admin/structure/types
// and as such, perhaps a better check should be used here.
if (user_access('administer content types')) {
$message = t('<a href="@settings" title="Content type administration">No content types have been configured to use Workbench Moderation.</a>', array('@settings' => url('admin/structure/types')));
$type = 'error';
}
// Non admins get a different message.
else {
$message = t('Moderation is not ready to for use at this time. Please contact your administrator.');
$type = 'warning';
}
drupal_set_message($message, $type, $repeat = FALSE);
}
$operator = ($this->value ? "IN" : "NOT IN");
$this->ensure_my_table();
$this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field", $node_types, $operator);
}
}
<?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('Moderation status');
$this->value_options = array_map('check_plain', workbench_moderation_state_labels());
}
}
}
<?php
/**
* @file
* Filter based on moderation privlieges.
*/
class workbench_moderation_handler_filter_user_can_moderate extends views_handler_filter {
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
drupal_set_message(t("This filter isn't even possible right now since workbench moderation permissions are incomplete--there's no way to figure out what transitions a user may make for a particular type of content."), 'error');
}
function query() {
// add table, add node table, add where statments like "(n.type = 'blog' AND moderation.state IN ('review', 'approve')) OR (n.type = 'article' AND moderation.state IN ('review'))"
// $this->ensure_my_table();
// $node_alias = $this->query->ensure_table('node');
// $this->query->add_where();
}
}
/**
* @file
* Sets the summary for Workbench moderation on vertical tabs.
*/
(function ($) {
Drupal.behaviors.workbenchModerationSettingsSummary = {
attach: function(context) {
$('fieldset.node-form-options', context).drupalSetSummary(function (context) {
var vals = [];
$('input:checked', context).parent().each(function () {
vals.push(Drupal.checkPlain($.trim($(this).text())));
});
if ($('select[name="workbench_moderation_state_new"]', context).val()) {
vals.push(Drupal.checkPlain($('select[name="workbench_moderation_state_new"] option:selected').text()));
}
return vals.join(', ');
});
}
};
})(jQuery);
<?php
/**
* Specialized implementation of hook_page_manager_task_tasks(). See api-task.html for
* more information.
*/
function workbench_moderation_nodedraft_page_manager_tasks() {
return array(
// This is a 'page' task and will fall under the page admin UI
'task type' => 'page',
'title' => t('Node draft'),
'admin title' => t('The draft page for moderated nodes.'),
'admin description' => t('When enabled, this overrides the default node view at node/%node/draft'),
'admin path' => 'node/%node/draft',
// Menu hooks so that we can alter the node/%node menu entry to point to us.
'hook menu alter' => 'workbench_moderation_nodedraft_menu_alter',
// This is task uses 'context' handlers and must implement these to give the
// handler data it needs.
'handler type' => 'context',
'get arguments' => 'workbench_moderation_nodedraft_get_arguments',
'get context placeholders' => 'workbench_moderation_nodedraft_get_contexts',
// Allow this to be enabled or disabled:
'disabled' => variable_get('workbench_moderation_nodedraft_disabled', TRUE),
'enable callback' => 'workbench_moderation_nodedraft_enable',
);
}
/**
* Callback defined by workbench_moderation_nodedraft_page_manager_tasks().
*
* Alter menu item so that admin/workbench comes here.
*/
function workbench_moderation_nodedraft_menu_alter(&$items, $task) {
if (variable_get('workbench_moderation_nodedraft_disabled', TRUE)) {
return;
}
$callback = $items['node/%node/draft']['page callback'];
// Override the node edit handler for our purpose.
if ($callback == 'workbench_moderation_node_view_draft' || variable_get('page_manager_override_anyway', FALSE)) {
$items['node/%node/draft']['page callback'] = 'workbench_moderation_nodedraft';
$items['node/%node/draft']['file path'] = $task['path'];
$items['node/%node/draft']['file'] = $task['file'];
}
else {
//variable_set('workbench_moderation_nodedraft_disabled', TRUE);
if (!empty($GLOBALS['page_manager_enabling_workbench'])) {
drupal_set_message(t('Page manager module is unable to enable Workbench Moderation Draft Node because some other module already has overridden with %callback.', array('%callback' => $callback)), 'warning');
}
return;
}
}
/**
* Entry point for our overridden My Workbench.
*
* This function asks its assigned handlers who, if anyone, would like
* to run with it. If no one does, it passes through to the main node draft page.
*/
function workbench_moderation_nodedraft($node) {
// Load my task plugin
$task = page_manager_get_task('nodedraft');
// Get the most recent revision to pass to the task handler.
$current_node = workbench_moderation_node_current_load($node);
// Load the node into a context.
ctools_include('context');
ctools_include('context-task-handler');
$contexts = ctools_context_handler_get_task_contexts($task, '', array($current_node));
$output = ctools_context_handler_render($task, '', $contexts, array($current_node->nid));
if ($output !== FALSE) {
return $output;
}
module_load_include('inc', 'workbench_moderation', 'workbench_moderation.node');
$function = 'workbench_moderation_node_view_draft';
foreach (module_implements('page_manager_override') as $module) {
$call = $module . '_page_manager_override';
if (($rc = $call('workbench')) && function_exists($rc)) {
$function = $rc;
break;
}
}
// Otherwise, fall back.
return $function($node);
}
/**
* Callback to enable/disable the page from the UI.
*/
function workbench_moderation_nodedraft_enable($cache, $status) {
variable_set('workbench_moderation_nodedraft_disabled', $status);
// Set a global flag so that the menu routine knows it needs
// to set a message if enabling cannot be done.
if (!$status) {
$GLOBALS['page_manager_enabling_workbench'] = TRUE;
}
}
/**
* Callback to get arguments provided by this task handler.
*
* Since this is the node view and there is no UI on the arguments, we
* create dummy arguments that contain the needed data.
*/
function workbench_moderation_nodedraft_get_arguments($task, $subtask_id) {
return array(
array(
'keyword' => 'node',
'identifier' => t('Node draft being viewed'),
'id' => 1,
'name' => 'entity_id:node',
'settings' => array(),
),
);
}
/**
* Callback to get context placeholders provided by this handler.
*/
function workbench_moderation_nodedraft_get_contexts($task, $subtask_id) {
return ctools_context_get_placeholders_from_argument(page_manager_node_view_get_arguments($task, $subtask_id));
}
<?php
/**
* Specialized implementation of hook_page_manager_task_tasks(). See api-task.html for
* more information.
*/
function workbench_moderation_noderevision_page_manager_tasks() {
return array(
// This is a 'page' task and will fall under the page admin UI
'task type' => 'page',
'title' => t('Node revision'),
'admin title' => t('The revision page for moderated nodes.'),
'admin description' => t('When enabled, this overrides the default node view at node/%node/revisions/%/view'),
'admin path' => 'node/%node/revisions/%/view',
// Menu hooks so that we can alter the node/%node menu entry to point to us.
'hook menu alter' => 'workbench_moderation_noderevision_menu_alter',
// This is task uses 'context' handlers and must implement these to give the
// handler data it needs.
'handler type' => 'context',
'get arguments' => 'workbench_moderation_noderevision_get_arguments',
'get context placeholders' => 'workbench_moderation_noderevisoin_get_contexts',
// Allow this to be enabled or disabled:
'disabled' => variable_get('workbench_moderation_noderevision_disabled', TRUE),
'enable callback' => 'workbench_moderation_noderevision_enable',
);
}
/**
* Callback defined by workbench_moderation_noderevision_page_manager_tasks().
*
* Alter menu item so that admin/workbench comes here.
*/
function workbench_moderation_noderevision_menu_alter(&$items, $task) {
if (variable_get('workbench_moderation_noderevision_disabled', TRUE)) {
return;
}
$callback = $items['node/%node/revisions/%/view']['page callback'];
// Override the node edit handler for our purpose.
if ($callback == 'workbench_moderation_node_view_revision' || variable_get('page_manager_override_anyway', FALSE)) {
$items['node/%node/revisions/%/view']['page callback'] = 'workbench_moderation_noderevision';
$items['node/%node/revisions/%/view']['file path'] = $task['path'];
$items['node/%node/revisions/%/view']['file'] = $task['file'];
}
else {
variable_set('workbench_moderation_noderevision_disabled', TRUE);
if (!empty($GLOBALS['page_manager_enabling_workbench_noderevision'])) {
drupal_set_message(t('Page manager module is unable to enable Workbench Moderation Revision Node because some other module already has overridden with %callback.', array('%callback' => $callback)), 'warning');
}
return;
}
}
/**
* Entry point for our overridden My Workbench.
*
* This function asks its assigned handlers who, if anyone, would like
* to run with it. If no one does, it passes through to the main node draft page.
*/
function workbench_moderation_noderevision($node) {
// Load my task plugin
$task = page_manager_get_task('noderevision');
// Load the node into a context.
ctools_include('context');
ctools_include('context-task-handler');
$contexts = ctools_context_handler_get_task_contexts($task, '', array($node));
$output = ctools_context_handler_render($task, '', $contexts, array($node->nid));
if ($output !== FALSE) {
return $output;
}
module_load_include('inc', 'workbench_moderation', 'workbench_moderation.node');
$function = 'workbench_moderation_node_view_revision';
foreach (module_implements('page_manager_override') as $module) {
$call = $module . '_page_manager_override';
if (($rc = $call('workbench')) && function_exists($rc)) {
$function = $rc;
break;
}
}
// Otherwise, fall back.
return $function($node);
}
/**
* Callback to enable/disable the page from the UI.
*/
function workbench_moderation_noderevision_enable($cache, $status) {
variable_set('workbench_moderation_noderevision_disabled', $status);
// Set a global flag so that the menu routine knows it needs
// to set a message if enabling cannot be done.
if (!$status) {
$GLOBALS['page_manager_enabling_workbench_noderevision'] = TRUE;
}
}
/**
* Callback to get arguments provided by this task handler.
*
* Since this is the node view and there is no UI on the arguments, we
* create dummy arguments that contain the needed data.
*/
function workbench_moderation_noderevision_get_arguments($task, $subtask_id) {
return array(
array(
'keyword' => 'node',
'identifier' => t('Node revision being viewed'),
'id' => 1,
'name' => 'entity_id:node',
'settings' => array(),
),
);
}
/**
* Callback to get context placeholders provided by this handler.
*/
function workbench_moderation_noderevision_get_contexts($task, $subtask_id) {
return ctools_context_get_placeholders_from_argument(page_manager_node_view_get_arguments($task, $subtask_id));
}
<?php
/**
* @file
* Tests moderation states when nodes are (un)published by other modules.
*/
class WorkbenchModerationExternalNodeUpdateTestCase extends WorkbenchModerationTestCase {
/**
* {@inheritdoc}
*/
protected $profile = 'testing';
/**
* A test node.
*
* @var object
*/
protected $node;
/**
* Returns test case metadata.
*
* @return array
* The metadata.
*/
public static function getInfo() {
return array(
'name' => 'External node update',
'description' => 'Test if nodes are correctly moderated when updated by third party modules.',
'group' => 'Workbench Moderation',
);
}
/**
* {@inheritdoc}
*/
public function setUp($modules = array()) {
// Enable a test module that will publish and unpublish nodes for us.
parent::setUp(array_merge($modules, array('workbench_moderation_test')));
$this->drupalLogin($this->moderator_user);
}
/**
* Tests if nodes can be moderated by third party modules.
*/
public function testNodeSave() {
// Create a brand new unpublished node programmatically.
$settings = array(
'title' => $this->randomName(),
'type' => $this->content_type,
'status' => NODE_NOT_PUBLISHED,
);
$this->node = $this->drupalCreateNode($settings);
// Assert that the node is initially in state draft and not published.
$expected = array('state' => 'draft');
$this->assertModerationStatus($expected, 'is_current', 'The moderation status is correct for a newly created node.');
$this->assertNoPublishedRecord('A newly created node does not have a published entry in the node history table.');
$this->assertPublicationState(FALSE, 'A newly created node is not published.');
// Resave the node and check that the status doesn't change.
$this->resaveNode();
$this->assertModerationStatus($expected, 'is_current', 'The moderation status is correct for a newly created node.');
$this->assertNoPublishedRecord('A newly created node does not have a published entry in the node history table.');
$this->assertPublicationState(FALSE, 'A newly created node is not published.');
// Publish the node in an external module and check that the moderation
// state changes accordingly.
$this->drupalGet('workbench_moderation_test/' . $this->node->nid . '/publish');
$this->refreshNode();
$expected = array('state' => 'published');
$this->assertModerationStatus($expected, 'is_current', 'The moderation state changed to "published" if the node is published externally.');
$this->assertModerationStatus($expected, 'published', 'A published moderation state record is created when the node is published externally.');
$this->assertPublicationState(TRUE, 'A node which is published externally is actually published.');
// Resave the node and check that the status doesn't change.
$this->resaveNode();
$this->assertModerationStatus($expected, 'is_current', 'The moderation state changed to "published" if the node is published externally.');
$this->assertModerationStatus($expected, 'published', 'A published moderation state record is created when the node is published externally.');
$this->assertPublicationState(TRUE, 'A node which is published externally is actually published.');
// Unpublish the node in an external module and check that the moderation
// state changes accordingly.
$this->drupalGet('workbench_moderation_test/' . $this->node->nid . '/unpublish');
$this->refreshNode();
$expected = array('state' => 'draft');
$this->assertModerationStatus($expected, 'is_current', 'The moderation state changed to "draft" if the node is unpublished externally.');
$this->assertNoPublishedRecord('The published moderation state record is removed when the node is unpublished externally.');
$this->assertPublicationState(FALSE, 'A node which is unpublished externally is actually unpublished.');
// Resave the node and check that the status doesn't change.
$this->resaveNode();
$this->assertModerationStatus($expected, 'is_current', 'The moderation state changed to "draft" if the node is unpublished externally.');
$this->assertNoPublishedRecord('The published moderation state record is removed when the node is unpublished externally.');
$this->assertPublicationState(FALSE, 'A node which is unpublished externally is actually unpublished.');
}
/**
* Resave the node in an external module.
*/
public function resaveNode() {
$this->drupalGet('workbench_moderation_test/' . $this->node->nid);
$this->refreshNode();
}
/**
* Checks if the node history table matches the expected values.
*
* @param array $expected
* An associative array containing expected moderation status values.
* @param string $status
* Which status to assert. Can be either 'current' or 'published'.
* @param string $message
* The message to display along with the assertion.
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
public function assertModerationStatus(array $expected, $status = 'is_current', $message = '') {
$record = $this->getModerationRecord($status);
$success = TRUE;
foreach ($expected as $key => $value) {
$success |= $this->assertEqual($value, $record[$key], format_string('Found value %value for %key, expected %expected.', array(
'%key' => $key,
'%value' => $record[$key],
'%expected' => $value,
)));
}
return $this->assertTrue($success, $message);
}
/**
* Checks if the node is not marked as 'published' in the node history table.
*
* @param string $message
* The message to display along with the assertion.
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
public function assertNoPublishedRecord($message = '') {
$record = $this->getModerationRecord('published');
return $this->assertFalse($record, $message);
}
/**
* Checks that the test node has the expected publication state.
*
* @param bool $expected
* TRUE if the the node should be published, FALSE otherwise.
* @param string $message
* The message to display along with the assertion.
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
public function assertPublicationState($expected, $message = '') {
return $this->assertEqual($expected, $this->node->status, $message);
}
/**
* Refreshes the test node so it matches the actual state in the database.
*/
public function refreshNode() {
$this->node = node_load($this->node->nid, NULL, TRUE);
}
/**
* Returns a moderation status record of the tested node.
*
* @param string $status
* Which status to return. Can be either 'current' or 'published'.
*
* @return array
* The node's record(s) from the {workbench_moderation_node_history} table.
*/
protected function getModerationRecord($status = 'is_current') {
return db_select('workbench_moderation_node_history', 'nh')
->fields('nh', array('from_state', 'state', 'published', 'is_current'))
->condition('nid', $this->node->nid, '=')
->condition($status, 1)
->execute()
->fetchAssoc();
}
}
<?php
/**
* @file
* Tests for using file fields with workbench_moderation.module.
*/
class WorkbenchModerationFilesTestCase extends FileFieldTestCase {
protected $content_type;
protected $moderator_user;
protected $field_name;
function setUp() {
parent::setUp();
module_enable(array('workbench_moderation'));
// Create a new content type and enable moderation on it.
$type = $this->drupalCreateContentType();
$this->content_type = $type->name;
variable_set('node_options_' . $this->content_type, array('revision', 'moderation'));
// Add a file field to the new content type.
$this->field_name = strtolower($this->randomName());
$this->createFileField($this->field_name, $this->content_type);
$this->moderator_user = $this->drupalCreateUser(array(
'access content',
'access administration pages',
'administer site configuration',
'administer users',
'administer permissions',
'administer content types',
'administer nodes',
'bypass node access',
'view revisions',
'revert revisions',
"edit any {$this->content_type} content",
'view moderation history',
'view moderation messages',
'bypass workbench moderation',
));
$this->drupalLogin($this->moderator_user);
}
public static function getInfo() {
return array(
'name' => 'Workbench Moderation file attachments',
'description' => 'Test moderation on nodes with with file attachments.',
'group' => 'Workbench Moderation',
);
}
function testModeratedFileField() {
// Create a new node with an uploaded file.
$file = $this->getTestFile('text');
$edit = array(
'title' => $this->randomName(),
'files[' . $this->field_name . '_' . LANGUAGE_NONE . '_0]' => drupal_realpath($file->uri),
);
$this->drupalPost("node/add/{$this->content_type}", $edit, t('Save'));
// Get the new node.
$node = $this->drupalGetNodeByTitle($edit['title']);
$nid = $node->nid;
// Publish the node via the moderation form.
$moderate = array('state' => workbench_moderation_state_published());
$this->drupalPost("node/{$nid}/moderation", $moderate, t('Apply'));
// Update the node; remove the first file and add a second file.
$file = $this->getTestFile('text');
$edit = array(
'title' => $this->randomName(10) . '_second',
'files[' . $this->field_name . '_' . LANGUAGE_NONE . '_0]' => drupal_realpath($file->uri),
);
$this->drupalPost("node/$nid/edit", array(), t('Remove'));
$this->drupalPost(NULL, $edit, t('Save'));
// Load the published node.
$published = node_load($nid, NULL, TRUE);
// Check for a published revision.
$this->assertTrue(isset($published->workbench_moderation['published']), t('Workbench moderation has published revision'));
// Load the draft revision.
$draft = clone $published;
$draft = workbench_moderation_node_current_load($draft);
// Check that the draft revision is different from the published revision.
$this->assertNotEqual($published->vid, $draft->vid, t('Workbench moderation loads second revision'));
// Check that the original file is present on the published revision.
$published_file = (object) $published->{$this->field_name}[LANGUAGE_NONE][0];
$this->assertFileExists($published_file, t('File is present on published revision'));
// Check that the second file is present on the draft revision.
$draft_file = (object) $draft->{$this->field_name}[LANGUAGE_NONE][0];
$this->assertFileExists($draft_file, t('File is present on draft revision'));
$this->assertNotEqual($published_file->uri, $draft_file->uri, t('File on published revision is different from file on draft revision'));
}
}
This diff is collapsed.
name = Workbench Moderation Test
description = Test module for Workbench Moderation.
package = Workbench
core = 7.x
hidden = TRUE
<?php
/**
* @file
* Test module for Workbench Moderation.
*/
/**
* Implements hook_menu().
*/
function workbench_moderation_test_menu() {
return array(
'workbench_moderation_test/%node' => array(
'title' => 'Publish a node',
'page callback' => 'workbench_moderation_test_update_node',
'page arguments' => array(1),
'access arguments' => array('bypass workbench moderation'),
),
);
}
/**
* Implements hook_menu_alter().
*/
function workbench_moderation_test_menu_alter(&$items) {
// This menu altering replicates what restws_menu_alter() does.
// @see https://www.drupal.org/node/1838640
array_unshift($items['node/%node']['page arguments'], 'additional parameter', $items['node/%node']['page callback']);
$items['node/%node']['page callback'] = 'workbench_moderation_test_menu_node_callback';
}
function workbench_moderation_test_menu_node_callback($ignored_parameter, $page_callback) {
$args = func_get_args();
return call_user_func_array($page_callback, array_slice($args, 2));
}
/**
* Page callback. Publishes, unpublishes or resaves the given node.
*
* @param object $node
* The node to publish, unpublish or resave.
* @param string $action
* Optionally the action to take, either 'publish' or 'unpublish'. If omitted
* the node will be resaved.
*/
function workbench_moderation_test_update_node($node, $action = NULL) {
if (!empty($action)) {
$node->status = $action == 'publish' ? NODE_PUBLISHED : NODE_NOT_PUBLISHED;
}
node_save($node);
return array('#markup' => t('Node status: @status', array('@status' => $node->status ? t('published') : t('unpublished'))));
}
This diff is collapsed.
This diff is collapsed.
<?php
/**
* @file
* API documentation file for Workbench Moderation.
*/
/**
* Allows modules to alter moderation access.
*
* @param &$access
* A boolean access declaration. Passed by reference.
* @param $op
* The operation being performed. May be 'view', 'update', 'delete',
* 'view revisions' or 'moderate'.
* @param $node
* The node being acted upon.
*/
function hook_workbench_moderation_access_alter(&$access, $op, $node) {
global $user;
// If the node is marked private, only let its owner moderate it.
if (empty($node->private) || $op != 'moderate') {
return;
}
if ($user->uid != $node->uid) {
$access = FALSE;
}
}
/**
* Allows modules to alter the list of possible next states for a node.
*
* @param &$states
* An array of possible state changes, or FALSE if none were found before
* invoking this hook. Passed by reference.
* @param $current_state
* The current moderation state.
* @param $context
* An associative array containing:
* - 'account': The user object being checked.
* - 'node': The node object being acted upon.
*
* @see workbench_moderation_states_next()
*/
function hook_workbench_moderation_states_next_alter(&$states, $current_state, $context) {
// Do not permit users to give final approval to their own nodes, even if
// they would otherwise have rights to do so.
$published = workbench_moderation_state_published();
if (isset($states[$published]) && ($context['account']->uid == $context['node']->uid)) {
unset($states[$published]);
}
}
/**
* Allows modules to respond to state transitions.
*
* @param $node
* The node that is being transitioned.
*
* @param $previous_state
* The state of the revision before the transition occurred.
*
* @param $new_state
* The new state of the revision.
*/
function hook_workbench_moderation_transition($node, $previous_state, $new_state) {
// Your code here.
}
/**
* Allows modules to respond when a transition is saved.
*
* @param object $state
* The state which was just saved.
* @param int $status
* Either MergeQuery::STATUS_INSERT or MergeQuery::STATUS_UPDATE depending
* on if this INSERT'ing a new transation or UPDATE'ing an existing one.
*/
function hook_workbench_moderation_state_save($state, $status) {
if ($status == MergeQuery::STATUS_INSERT) {
// Add data to a custom table for each new transition.
db_insert('mytable')
->fields(array(
'state' => $state->name,
))
->execute();
}
}
/**
* Allows modules to respond when a transition is saved.
*
* @param object $transition
* The transition which was just saved.
* @param int $status
* Either MergeQuery::STATUS_INSERT or MergeQuery::STATUS_UPDATE depending
* on if this INSERT'ing a new transation or UPDATE'ing an existing one.
*/
function hook_workbench_moderation_transition_save($transition, $status) {
if ($status == MergeQuery::STATUS_INSERT) {
// Add data to a custom table for each new transition.
db_insert('mytable')
->fields(array(
'from_state' => $transition->from_name,
'to_state' => $transition->to_name,
))
->execute();
}
}
/**
* Allows modules to respond when a state is deleted.
*
* @param object $state
* The state which was just deleted.
*/
function hook_workbench_moderation_state_delete($state) {
// Remove data from a custom table which refers to the old state.
db_delete('mytable')
->condition('state', $state->name)
->execute();
}
/**
* Allows modules to respond when a transition is deleted.
*
* @param object $transition
* The transition which was just deleted.
*/
function hook_workbench_moderation_transition_delete($transition) {
// Remove data from a custom table which refers to the old state.
db_delete('mytable')
->condition('from_state', $transition->from_name)
->condition('to_state', $transition->to_name)
->execute();
}
<?php
/**
* @file
* Features file for the workbench_moderation module.
*/
/**
* Implements COMPONENT_features_export_options().
*
* Inform features about the available states in the database.
*/
function workbench_moderation_states_features_export_options() {
$states = db_select('workbench_moderation_states', 'states')
->fields('states', array('name', 'name'))
->execute()
->fetchAllKeyed();
return $states;
}
/**
* Implements COMPONENT_features_export().
*
* Process the features export array for states.
*/
function workbench_moderation_states_features_export($data, &$export, $module_name) {
$export['dependencies']['workbench_moderation_states'] = 'workbench_moderation';
foreach ($data as $component) {
$export['features']['workbench_moderation_states'][$component] = $component;
}
return array();
}
/**
* Implements COMPONENT_features_export_render().
*
* Render workbench moderation states as code.
*/
function workbench_moderation_states_features_export_render($module_name, $data) {
$items = array();
foreach ($data as $state) {
$items[$state] = workbench_moderation_state_load($state);
}
$code = " \$items = " . features_var_export($items, ' ') . ";\n";
$code .= ' return $items;';
return array('workbench_moderation_export_states' => $code);
}
/**
* Implements COMPONENT_features_revert().
*/
function workbench_moderation_states_features_revert($module) {
workbench_moderation_states_features_rebuild($module);
}
/**
* Implements COMPONENT_features_enable_feature().
*/
function workbench_moderation_states_features_enable_feature($module) {
workbench_moderation_states_features_rebuild($module);
}
/**
* Implements COMPONENT_features_rebuild().
*
* Store each exported transition in the database.
*/
function workbench_moderation_states_features_rebuild($module) {
$defaults = features_get_default('workbench_moderation_states', $module);
foreach ($defaults as $state) {
workbench_moderation_state_save((object) $state);
}
drupal_static_reset('workbench_moderation_states');
}
/**
* Implements COMPONENT_features_export_options().
*
* Inform features about the available transitions in the database.
*/
function workbench_moderation_transitions_features_export_options() {
$options = array();
foreach (workbench_moderation_transitions() as $transition) {
$options[$transition->from_name . ':' . $transition->to_name] = $transition->from_name . ' -> ' . $transition->to_name;
}
return $options;
}
/**
* Implements COMPONENT_features_export().
*
* Process the features export array for transitions.
*/
function workbench_moderation_transitions_features_export($data, &$export, $module_name) {
$export['dependencies']['workbench_moderation_transitions'] = 'workbench_moderation';
foreach ($data as $component) {
$export['features']['workbench_moderation_transitions'][$component] = $component;
}
return array();
}
/**
* Implements COMPONENT_features_export_render().
*
* Render workbench moderation transitions as code.
*/
function workbench_moderation_transitions_features_export_render($module_name, $data) {
$items = array();
foreach ($data as $transition) {
list($from_name, $to_name) = explode(':', $transition);
$item = db_select('workbench_moderation_transitions', 't')
->fields('t', array('from_name', 'to_name', 'name'))
->condition('from_name', $from_name)
->condition('to_name', $to_name)
->execute()
->fetchObject();
if (!empty($item)) {
$items[$item->from_name . ':' . $item->to_name] = $item;
}
}
$code = " \$items = " . features_var_export($items, ' ') . ";\n";
$code .= ' return $items;';
return array('workbench_moderation_export_transitions' => $code);
}
/**
* Implements COMPONENT_features_revert().
*/
function workbench_moderation_transitions_features_revert($module) {
workbench_moderation_transitions_features_rebuild($module);
}
/**
* Implements COMPONENT_features_enable_feature().
*/
function workbench_moderation_transitions_features_enable_feature($module) {
workbench_moderation_transitions_features_rebuild($module);
}
/**
* Implements COMPONENT_features_rebuild().
*
* Store each exported transition in the database.
*/
function workbench_moderation_transitions_features_rebuild($module) {
$defaults = features_get_default('workbench_moderation_transitions', $module);
foreach ($defaults as $machine_name => $transition) {
workbench_moderation_transition_save((object) $transition);
}
drupal_static_reset('workbench_moderation_transitions');
}
<?php
/**
* @file Provides workbench integration for iib.
*/
/**
* Implements hook_iib_entity_item().
*
* Add the workbench moderation status to the iib.
*/
function workbench_moderation_iib_entity_item($entity, $entity_type, $view_mode) {
if ($entity_type == 'node' && $view_mode == 'full' && !empty($entity->workbench_moderation)) {
$state = $entity->workbench_moderation;
$status = check_plain(workbench_moderation_state_label($state['my_revision']->state));
$items['center'][] = array(
'#prefix' => '<div class="workbench-status workbench-iib">',
'#markup' => t('Current State: @state', array('@state' => $status)),
'#suffix' => '</div>',
);
$node_published = FALSE;
$revision_published = FALSE;
$revision_current = FALSE;
if (!empty($state['published'])) {
$node_published = TRUE;
}
if ($state['my_revision']->published) {
$revision_published = TRUE;
}
if ($state['my_revision']->vid == $state['current']->vid) {
$revision_current = TRUE;
}
// Add a moderation form.
if ($revision_current && !$revision_published && _workbench_moderation_access('update', $entity) &&
$moderate_form = drupal_get_form('workbench_moderation_moderate_form', $entity, "node/{$entity->nid}/current-revision")) {
$items['center'][] = array(
'#prefix' => '<div class="workbench-moderate workbench-iib">',
'label' => array(
'#markup' => t('Moderate:'),
),
'form' => $moderate_form,
'#suffix' => '</div>',
);
}
return $items;
}
return array();
}
\ No newline at end of file
name = Workbench Moderation
description = Provides content moderation services
package = Workbench
core = 7.x
configure = admin/config/workbench/moderation
files[] = workbench_moderation.module
files[] = includes/workbench_moderation_handler_field_history_link.inc
files[] = includes/workbench_moderation_handler_field_links.inc
files[] = includes/workbench_moderation_handler_field_state.inc
files[] = includes/workbench_moderation_handler_filter_state.inc
files[] = includes/workbench_moderation_handler_filter_moderated_type.inc
files[] = includes/workbench_moderation_handler_filter_user_can_moderate.inc
files[] = workbench_moderation.migrate.inc
files[] = tests/external_node_update.test
files[] = tests/workbench_moderation.test
files[] = tests/workbench_moderation.files.test
This diff is collapsed.
<?php
class WorkbenchModerationMigrateDestinationHandler extends MigrateDestinationHandler {
public function __construct() {}
public function handlesType($destination) {
return ($destination == 'Node');
}
public function fields($entity_type, $bundle_type) {
$fields = array();
if (workbench_moderation_node_type_moderated($bundle_type)) {
$fields['workbench_moderation_state_new'] = t('Moderation state');
}
return $fields;
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?php
/**
* @file
* Content moderation views integration for Workbench.
*/
/**
* Implements hook_views_data().
*/
function workbench_moderation_views_data() {
$data = array();
$data['workbench_moderation_node_history']['table']['group'] = t('Workbench Moderation');
$data['workbench_moderation_node_history']['table']['join'] = array(
'node' => array(
'left_field' => 'nid',
'field' => 'nid',
'type' => 'INNER',
),
'node_revision' => array(
'left_field' => 'vid',
'field' => 'vid',
'type' => 'INNER',
),
);
$data['workbench_moderation_node_history']['hid'] = array(
'title' => t('Moderation history ID'),
'help' => t('Content moderation history record ID.'),
'filter' => array(
'handler' => 'views_handler_filter',
),
'field' => array(
'handler' => 'views_handler_field',
'click sortable' => TRUE,
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'argument' => array(
'handler' => 'views_handler_argument',
),
);
$data['workbench_moderation_node_history']['nid'] = array(
'title' => t('Node'),
'help' => t('The node according to the Workbench Moderation.'),
'relationship' => array(
'base' => 'node',
'field' => 'nid',
'handler' => 'views_handler_relationship',
'label' => t('Node'),
),
);
$data['workbench_moderation_node_history']['state'] = array(
'title' => t('State'),
'help' => t('Content moderation state of the node revisision.'),
'filter' => array(
'handler' => 'workbench_moderation_handler_filter_state',
),
'field' => array(
'handler' => 'workbench_moderation_handler_field_state',
'click sortable' => TRUE,
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'argument' => array(
'handler' => 'views_handler_argument_string',
'name table' => 'workbench_moderation_states',
'name field' => 'label',
),
);
$data['workbench_moderation_node_history']['from_state'] = array(
'title' => t('From state'),
'help' => t('Previous content moderation state of the node revisision.'),
'filter' => array(
'handler' => 'workbench_moderation_handler_filter_state',
),
'field' => array(
'handler' => 'views_handler_field',
'click sortable' => TRUE,
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'argument' => array(
'handler' => 'views_handler_argument_string',
'name table' => 'workbench_moderation_states',
'name field' => 'label',
),
);
$data['workbench_moderation_node_history']['uid'] = array(
'title' => t('User'),
'help' => t('User who moderated this revision.'),
'relationship' => array(
'title' => t('User'),
'label' => t('moderator user'),
'base' => 'users',
'base field' => 'uid',
),
);
$data['workbench_moderation_node_history']['stamp'] = array(
'title' => t('Timestamp'),
'help' => t('The date this revision was moderated.'),
'field' => array(
'handler' => 'views_handler_field_date',
'click sortable' => TRUE,
),
'sort' => array(
'handler' => 'views_handler_sort_date',
),
'filter' => array(
'handler' => 'views_handler_filter_date',
),
);
$data['workbench_moderation_node_history']['published'] = array(
'title' => t('Published'),
'help' => t('Whether or not this revision is published.'),
'field' => array(
'handler' => 'views_handler_field_boolean',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_boolean_operator',
'label' => t('Published'),
'type' => 'yes-no',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['workbench_moderation_node_history']['is_current'] = array(
'title' => t('Current'),
'help' => t('Whether or not this is the current revision.'),
'field' => array(
'handler' => 'views_handler_field_boolean',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_boolean_operator',
'label' => t('Current'),
'type' => 'yes-no',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['workbench_moderation_node_history']['moderation_actions'] = array(
'title' => t('Moderation actions'),
'help' => t('Content moderation state of the node revisision.'),
'real field' => 'state',
'field' => array(
'title' => t('Moderation links'),
'handler' => 'workbench_moderation_handler_field_links',
'click sortable' => FALSE,
'additional fields' => array('nid', 'vid', 'is_current'),
),
'filter' => array(
'title' => t('User can moderate'),
'handler' => 'workbench_moderation_handler_filter_user_can_moderate',
'label' => t('Can moderate'),
),
);
$data['workbench_moderation_states']['table']['group'] = t('Workbench Moderation');
$data['workbench_moderation_states']['table']['join'] = array(
// Add a join for labeling the 'state' and 'from_state' arguments on workbench_moderation_node_history.
'workbench_moderation_node_history' => array(
'left_field' => 'state',
'field' => 'name',
),
'node' => array(
'left_table' => 'workbench_moderation_node_history',
'left_field' => 'state',
'field' => 'name',
),
'node_revision' => array(
'left_table' => 'workbench_moderation_node_history',
'left_field' => 'state',
'field' => 'name',
),
);
$data['workbench_moderation_states']['description'] = array(
'title' => t('Moderation state description'),
'help' => t('Shows a description of the moderation state.'),
'field' => array(
'handler' => 'views_handler_field',
),
);
$data['workbench_moderation_states']['weight'] = array(
'title' => t('Moderation state order'),
'sort' => array(