Move into nested docroot

This commit is contained in:
Rob Davies 2017-02-13 15:31:17 +00:00
parent 83a0d3a149
commit c8b70abde9
13405 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,7 @@
name: Actions
type: module
description: 'Perform tasks on specific events triggered within the system.'
package: Core
version: VERSION
core: 8.x
configure: entity.action.collection

View file

@ -0,0 +1,5 @@
action.admin:
title: Actions
description: 'Create tasks that the system can execute.'
route_name: entity.action.collection
parent: system.admin_config_system

View file

@ -0,0 +1,4 @@
action.admin:
route_name: entity.action.collection
title: 'Manage actions'
base_route: entity.action.collection

View file

@ -0,0 +1,50 @@
<?php
/**
* @file
* This is the Actions module for executing stored actions.
*/
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function action_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.action':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Actions module provides tasks that can be executed by the site such as unpublishing content, sending email messages, or blocking a user. Other modules can trigger these actions when specific system events happen; for example, when new content is posted or when a user logs in. Modules can also provide additional actions. For more information, see the <a href=":documentation">online documentation for the Actions module</a>.', array(':documentation' => 'https://www.drupal.org/documentation/modules/action')) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Using simple actions') . '</dt>';
$output .= '<dd>' . t('<em>Simple actions</em> do not require configuration and are listed automatically as available on the <a href=":actions">Actions page</a>.', array(':actions' => \Drupal::url('entity.action.collection'))) . '</dd>';
$output .= '<dt>' . t('Creating and configuring advanced actions') . '</dt>';
$output .= '<dd>' . t('<em>Advanced actions</em> are user-created and have to be configured individually. Create an advanced action on the <a href=":actions">Actions page</a> by selecting an action type from the drop-down list. Then configure your action, for example by specifying the recipient of an automated email message.', array(':actions' => \Drupal::url('entity.action.collection'))) . '</dd>';
$output .= '</dl>';
return $output;
case 'entity.action.collection':
$output = '<p>' . t('There are two types of actions: simple and advanced. Simple actions do not require any additional configuration and are listed here automatically. Advanced actions need to be created and configured before they can be used because they have options that need to be specified; for example, sending an email to a specified address or unpublishing content containing certain words. To create an advanced action, select the action from the drop-down list in the advanced action section below and click the <em>Create</em> button.') . '</p>';
return $output;
case 'entity.action.edit_form':
return t('An advanced action offers additional configuration options which may be filled out below. Changing the <em>Description</em> field is recommended in order to better identify the precise action taking place.');
}
}
/**
* Implements hook_entity_type_build().
*/
function action_entity_type_build(array &$entity_types) {
/** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
$entity_types['action']
->setFormClass('add', 'Drupal\action\ActionAddForm')
->setFormClass('edit', 'Drupal\action\ActionEditForm')
->setFormClass('delete', 'Drupal\action\Form\ActionDeleteForm')
->setListBuilderClass('Drupal\action\ActionListBuilder')
->setLinkTemplate('delete-form', '/admin/config/system/actions/configure/{action}/delete')
->setLinkTemplate('edit-form', '/admin/config/system/actions/configure/{action}')
->setLinkTemplate('collection', '/admin/config/system/actions');
}

View file

@ -0,0 +1,3 @@
administer actions:
title: 'Administer actions'
restrict access: true

View file

@ -0,0 +1,32 @@
entity.action.collection:
path: '/admin/config/system/actions'
defaults:
_title: 'Actions'
_entity_list: 'action'
requirements:
_permission: 'administer actions'
action.admin_add:
path: '/admin/config/system/actions/add/{action_id}'
defaults:
_entity_form: 'action.add'
_title: 'Add'
requirements:
_permission: 'administer actions'
entity.action.edit_form:
path: '/admin/config/system/actions/configure/{action}'
defaults:
_entity_form: 'action.edit'
_title: 'Edit'
requirements:
_permission: 'administer actions'
entity.action.delete_form:
path: '/admin/config/system/actions/configure/{action}/delete'
defaults:
_entity_form: 'action.delete'
_title: 'Delete'
requirements:
_permission: 'administer actions'

View file

@ -0,0 +1,20 @@
<?php
/**
* @file
* Provides views runtime hooks for action.module.
*/
/**
* Implements hook_views_form_substitutions().
*/
function action_views_form_substitutions() {
$select_all = array(
'#type' => 'checkbox',
'#default_value' => FALSE,
'#attributes' => array('class' => array('action-table-select-all')),
);
return array(
'<!--action-bulk-form-select-all-->' => drupal_render($select_all),
);
}

View file

@ -0,0 +1 @@
recursion_limit: 35

View file

@ -0,0 +1,40 @@
# Schema for the configuration files of the Action module.
action.settings:
type: config_object
label: 'Action settings'
mapping:
recursion_limit:
type: integer
label: 'Recursion limit for actions'
action.configuration.action_send_email_action:
type: mapping
label: 'Send email configuration'
mapping:
recipient:
type: string
label: 'Recipient'
subject:
type: label
label: 'Subject'
message:
type: text
label: 'Message'
action.configuration.action_goto_action:
type: mapping
label: 'Redirect to URL configuration'
mapping:
url:
type: string
label: 'URL'
action.configuration.action_message_action:
type: mapping
label: 'Display a message to the user configuration'
mapping:
message:
type: text
label: 'Message'

View file

@ -0,0 +1,14 @@
id: action_settings
label: Action configuration
migration_tags:
- Drupal 6
- Drupal 7
source:
plugin: variable
variables:
- actions_max_stack
process:
recursion_limit: actions_max_stack
destination:
plugin: config
config_name: action.settings

View file

@ -0,0 +1,39 @@
id: d6_action
label: Actions
migration_tags:
- Drupal 6
source:
plugin: action
process:
id:
-
plugin: machine_name
source: aid
label: description
type: type
plugin:
-
plugin: static_map
source: callback
map:
system_goto_action: action_goto_action
system_send_email_action: action_send_email_action
system_message_action: action_message_action
user_block_ip_action: 0
imagecache_flush_action: 0
imagecache_generate_all_action: 0
imagecache_generate_action: 0
bypass: true
-
plugin: skip_on_empty
method: row
configuration:
-
plugin: default_value
source: parameters
default_value: "a:0:{}"
-
plugin: callback
callable: unserialize
destination:
plugin: entity:action

View file

@ -0,0 +1,36 @@
id: d7_action
label: Actions
migration_tags:
- Drupal 7
source:
plugin: action
process:
id:
-
plugin: machine_name
source: aid
label: label
type: type
plugin:
-
plugin: static_map
source: callback
map:
system_goto_action: action_goto_action
system_send_email_action: action_send_email_action
system_message_action: action_message_action
system_block_ip_action: 0
bypass: true
-
plugin: skip_on_empty
method: row
configuration:
-
plugin: default_value
source: parameters
default_value: "a:0:{}"
-
plugin: callback
callable: unserialize
destination:
plugin: entity:action

View file

@ -0,0 +1,70 @@
<?php
namespace Drupal\action;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Action\ActionManager;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a form for action add forms.
*/
class ActionAddForm extends ActionFormBase {
/**
* The action manager.
*
* @var \Drupal\Core\Action\ActionManager
*/
protected $actionManager;
/**
* Constructs a new ActionAddForm.
*
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
* The action storage.
* @param \Drupal\Core\Action\ActionManager $action_manager
* The action plugin manager.
*/
public function __construct(EntityStorageInterface $storage, ActionManager $action_manager) {
parent::__construct($storage);
$this->actionManager = $action_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.manager')->getStorage('action'),
$container->get('plugin.manager.action')
);
}
/**
* {@inheritdoc}
*
* @param string $action_id
* The hashed version of the action ID.
*/
public function buildForm(array $form, FormStateInterface $form_state, $action_id = NULL) {
// In \Drupal\action\Form\ActionAdminManageForm::buildForm() the action
// are hashed. Here we have to decrypt it to find the desired action ID.
foreach ($this->actionManager->getDefinitions() as $id => $definition) {
$key = Crypt::hashBase64($id);
if ($key === $action_id) {
$this->entity->setPlugin($id);
// Derive the label and type from the action definition.
$this->entity->set('label', $definition['label']);
$this->entity->set('type', $definition['type']);
break;
}
}
return parent::buildForm($form, $form_state);
}
}

View file

@ -0,0 +1,10 @@
<?php
namespace Drupal\action;
/**
* Provides a form for action edit forms.
*/
class ActionEditForm extends ActionFormBase {
}

View file

@ -0,0 +1,150 @@
<?php
namespace Drupal\action;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\PluginFormInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a base form for action forms.
*/
abstract class ActionFormBase extends EntityForm {
/**
* The action plugin being configured.
*
* @var \Drupal\Core\Action\ActionInterface
*/
protected $plugin;
/**
* The action storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $storage;
/**
* Constructs a new action form.
*
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
* The action storage.
*/
public function __construct(EntityStorageInterface $storage) {
$this->storage = $storage;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.manager')->getStorage('action')
);
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$this->plugin = $this->entity->getPlugin();
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
$form['label'] = array(
'#type' => 'textfield',
'#title' => $this->t('Label'),
'#default_value' => $this->entity->label(),
'#maxlength' => '255',
'#description' => $this->t('A unique label for this advanced action. This label will be displayed in the interface of modules that integrate with actions.'),
);
$form['id'] = array(
'#type' => 'machine_name',
'#default_value' => $this->entity->id(),
'#disabled' => !$this->entity->isNew(),
'#maxlength' => 64,
'#description' => $this->t('A unique name for this action. It must only contain lowercase letters, numbers and underscores.'),
'#machine_name' => array(
'exists' => array($this, 'exists'),
),
);
$form['plugin'] = array(
'#type' => 'value',
'#value' => $this->entity->get('plugin'),
);
$form['type'] = array(
'#type' => 'value',
'#value' => $this->entity->getType(),
);
if ($this->plugin instanceof PluginFormInterface) {
$form += $this->plugin->buildConfigurationForm($form, $form_state);
}
return parent::form($form, $form_state);
}
/**
* Determines if the action already exists.
*
* @param string $id
* The action ID
*
* @return bool
* TRUE if the action exists, FALSE otherwise.
*/
public function exists($id) {
$action = $this->storage->load($id);
return !empty($action);
}
/**
* {@inheritdoc}
*/
protected function actions(array $form, FormStateInterface $form_state) {
$actions = parent::actions($form, $form_state);
unset($actions['delete']);
return $actions;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
if ($this->plugin instanceof PluginFormInterface) {
$this->plugin->validateConfigurationForm($form, $form_state);
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
parent::submitForm($form, $form_state);
if ($this->plugin instanceof PluginFormInterface) {
$this->plugin->submitConfigurationForm($form, $form_state);
}
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
$this->entity->save();
drupal_set_message($this->t('The action has been successfully saved.'));
$form_state->setRedirect('entity.action.collection');
}
}

View file

@ -0,0 +1,120 @@
<?php
namespace Drupal\action;
use Drupal\Core\Action\ActionManager;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a class to build a listing of action entities.
*
* @see \Drupal\system\Entity\Action
* @see action_entity_info()
*/
class ActionListBuilder extends ConfigEntityListBuilder {
/**
* @var bool
*/
protected $hasConfigurableActions = FALSE;
/**
* The action plugin manager.
*
* @var \Drupal\Core\Action\ActionManager
*/
protected $actionManager;
/**
* Constructs a new ActionListBuilder object.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type definition.
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
* The action storage.
* @param \Drupal\Core\Action\ActionManager $action_manager
* The action plugin manager.
*/
public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, ActionManager $action_manager) {
parent::__construct($entity_type, $storage);
$this->actionManager = $action_manager;
}
/**
* {@inheritdoc}
*/
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
return new static(
$entity_type,
$container->get('entity.manager')->getStorage($entity_type->id()),
$container->get('plugin.manager.action')
);
}
/**
* {@inheritdoc}
*/
public function load() {
$entities = parent::load();
foreach ($entities as $entity) {
if ($entity->isConfigurable()) {
$this->hasConfigurableActions = TRUE;
continue;
}
}
return $entities;
}
/**
* {@inheritdoc}
*/
public function buildRow(EntityInterface $entity) {
$row['type'] = $entity->getType();
$row['label'] = $entity->label();
if ($this->hasConfigurableActions) {
$row += parent::buildRow($entity);
}
return $row;
}
/**
* {@inheritdoc}
*/
public function buildHeader() {
$header = array(
'type' => t('Action type'),
'label' => t('Label'),
) + parent::buildHeader();
return $header;
}
/**
* {@inheritdoc}
*/
public function getDefaultOperations(EntityInterface $entity) {
$operations = $entity->isConfigurable() ? parent::getDefaultOperations($entity) : array();
if (isset($operations['edit'])) {
$operations['edit']['title'] = t('Configure');
}
return $operations;
}
/**
* {@inheritdoc}
*/
public function render() {
$build['action_header']['#markup'] = '<h3>' . $this->t('Available actions:') . '</h3>';
$build['action_table'] = parent::render();
if (!$this->hasConfigurableActions) {
unset($build['action_table']['table']['#header']['operations']);
}
$build['action_admin_manage_form'] = \Drupal::formBuilder()->getForm('Drupal\action\Form\ActionAdminManageForm');
return $build;
}
}

View file

@ -0,0 +1,95 @@
<?php
namespace Drupal\action\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Action\ActionManager;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a configuration form for configurable actions.
*/
class ActionAdminManageForm extends FormBase {
/**
* The action plugin manager.
*
* @var \Drupal\Core\Action\ActionManager
*/
protected $manager;
/**
* Constructs a new ActionAdminManageForm.
*
* @param \Drupal\Core\Action\ActionManager $manager
* The action plugin manager.
*/
public function __construct(ActionManager $manager) {
$this->manager = $manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('plugin.manager.action')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'action_admin_manage';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$actions = array();
foreach ($this->manager->getDefinitions() as $id => $definition) {
if (is_subclass_of($definition['class'], '\Drupal\Core\Plugin\PluginFormInterface')) {
$key = Crypt::hashBase64($id);
$actions[$key] = $definition['label'] . '...';
}
}
$form['parent'] = array(
'#type' => 'details',
'#title' => $this->t('Create an advanced action'),
'#attributes' => array('class' => array('container-inline')),
'#open' => TRUE,
);
$form['parent']['action'] = array(
'#type' => 'select',
'#title' => $this->t('Action'),
'#title_display' => 'invisible',
'#options' => $actions,
'#empty_option' => $this->t('Choose an advanced action'),
);
$form['parent']['actions'] = array(
'#type' => 'actions'
);
$form['parent']['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Create'),
);
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
if ($form_state->getValue('action')) {
$form_state->setRedirect(
'action.admin_add',
array('action_id' => $form_state->getValue('action'))
);
}
}
}

View file

@ -0,0 +1,20 @@
<?php
namespace Drupal\action\Form;
use Drupal\Core\Entity\EntityDeleteForm;
use Drupal\Core\Url;
/**
* Builds a form to delete an action.
*/
class ActionDeleteForm extends EntityDeleteForm {
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return new Url('entity.action.collection');
}
}

View file

@ -0,0 +1,217 @@
<?php
namespace Drupal\action\Plugin\Action;
use Drupal\Component\Render\PlainTextOutput;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Action\ConfigurableActionBase;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Mail\MailManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Utility\Token;
use Psr\Log\LoggerInterface;
use Egulias\EmailValidator\EmailValidator;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Sends an email message.
*
* @Action(
* id = "action_send_email_action",
* label = @Translation("Send email"),
* type = "system"
* )
*/
class EmailAction extends ConfigurableActionBase implements ContainerFactoryPluginInterface {
/**
* The token service.
*
* @var \Drupal\Core\Utility\Token
*/
protected $token;
/**
* The user storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $storage;
/**
* A logger instance.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* The mail manager
*
* @var \Drupal\Core\Mail\MailManagerInterface
*/
protected $mailManager;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* The email validator.
*
* @var \Egulias\EmailValidator\EmailValidator
*/
protected $emailValidator;
/**
* Constructs a EmailAction object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin ID for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Utility\Token $token
* The token service.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Psr\Log\LoggerInterface $logger
* A logger instance.
* @param \Drupal\Core\Mail\MailManagerInterface $mail_manager
* The mail manager.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Egulias\EmailValidator\EmailValidator $email_validator
* The email validator.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, Token $token, EntityManagerInterface $entity_manager, LoggerInterface $logger, MailManagerInterface $mail_manager, LanguageManagerInterface $language_manager, EmailValidator $email_validator) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->token = $token;
$this->storage = $entity_manager->getStorage('user');
$this->logger = $logger;
$this->mailManager = $mail_manager;
$this->languageManager = $language_manager;
$this->emailValidator = $email_validator;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition,
$container->get('token'),
$container->get('entity.manager'),
$container->get('logger.factory')->get('action'),
$container->get('plugin.manager.mail'),
$container->get('language_manager'),
$container->get('email.validator')
);
}
/**
* {@inheritdoc}
*/
public function execute($entity = NULL) {
if (empty($this->configuration['node'])) {
$this->configuration['node'] = $entity;
}
$recipient = PlainTextOutput::renderFromHtml($this->token->replace($this->configuration['recipient'], $this->configuration));
// If the recipient is a registered user with a language preference, use
// the recipient's preferred language. Otherwise, use the system default
// language.
$recipient_accounts = $this->storage->loadByProperties(array('mail' => $recipient));
$recipient_account = reset($recipient_accounts);
if ($recipient_account) {
$langcode = $recipient_account->getPreferredLangcode();
}
else {
$langcode = $this->languageManager->getDefaultLanguage()->getId();
}
$params = array('context' => $this->configuration);
if ($this->mailManager->mail('system', 'action_send_email', $recipient, $langcode, $params)) {
$this->logger->notice('Sent email to %recipient', array('%recipient' => $recipient));
}
else {
$this->logger->error('Unable to send email to %recipient', array('%recipient' => $recipient));
}
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return array(
'recipient' => '',
'subject' => '',
'message' => '',
);
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form['recipient'] = array(
'#type' => 'textfield',
'#title' => t('Recipient'),
'#default_value' => $this->configuration['recipient'],
'#maxlength' => '254',
'#description' => t('The email address to which the message should be sent OR enter [node:author:mail], [comment:author:mail], etc. if you would like to send an email to the author of the original post.'),
);
$form['subject'] = array(
'#type' => 'textfield',
'#title' => t('Subject'),
'#default_value' => $this->configuration['subject'],
'#maxlength' => '254',
'#description' => t('The subject of the message.'),
);
$form['message'] = array(
'#type' => 'textarea',
'#title' => t('Message'),
'#default_value' => $this->configuration['message'],
'#cols' => '80',
'#rows' => '20',
'#description' => t('The message that should be sent. You may include placeholders like [node:title], [user:account-name], [user:display-name] and [comment:body] to represent data that will be different each time message is sent. Not all placeholders will be available in all contexts.'),
);
return $form;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
if (!$this->emailValidator->isValid($form_state->getValue('recipient')) && strpos($form_state->getValue('recipient'), ':mail') === FALSE) {
// We want the literal %author placeholder to be emphasized in the error message.
$form_state->setErrorByName('recipient', t('Enter a valid email address or use a token email address such as %author.', array('%author' => '[node:author:mail]')));
}
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configuration['recipient'] = $form_state->getValue('recipient');
$this->configuration['subject'] = $form_state->getValue('subject');
$this->configuration['message'] = $form_state->getValue('message');
}
/**
* {@inheritdoc}
*/
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
$result = AccessResult::allowed();
return $return_as_object ? $result : $result->isAllowed();
}
}

View file

@ -0,0 +1,140 @@
<?php
namespace Drupal\action\Plugin\Action;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Action\ConfigurableActionBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Utility\UnroutedUrlAssemblerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Redirects to a different URL.
*
* @Action(
* id = "action_goto_action",
* label = @Translation("Redirect to URL"),
* type = "system"
* )
*/
class GotoAction extends ConfigurableActionBase implements ContainerFactoryPluginInterface {
/**
* The event dispatcher service.
*
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/
protected $dispatcher;
/**
* The unrouted URL assembler service.
*
* @var \Drupal\Core\Utility\UnroutedUrlAssemblerInterface
*/
protected $unroutedUrlAssembler;
/**
* Constructs a new DeleteNode object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin ID for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
* The tempstore factory.
* @param \Drupal\Core\Utility\UnroutedUrlAssemblerInterface $url_assembler
* The unrouted URL assembler service.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EventDispatcherInterface $dispatcher, UnroutedUrlAssemblerInterface $url_assembler) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->dispatcher = $dispatcher;
$this->unroutedUrlAssembler = $url_assembler;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container->get('event_dispatcher'), $container->get('unrouted_url_assembler'));
}
/**
* {@inheritdoc}
*/
public function execute($object = NULL) {
$url = $this->configuration['url'];
// Leave external URLs unchanged, and assemble others as absolute URLs
// relative to the site's base URL.
if (!UrlHelper::isExternal($url)) {
$parts = UrlHelper::parse($url);
// @todo '<front>' is valid input for BC reasons, may be removed by
// https://www.drupal.org/node/2421941
if ($parts['path'] === '<front>') {
$parts['path'] = '';
}
$uri = 'base:' . $parts['path'];
$options = [
'query' => $parts['query'],
'fragment' => $parts['fragment'],
'absolute' => TRUE,
];
// Treat this as if it's user input of a path relative to the site's
// base URL.
$url = $this->unroutedUrlAssembler->assemble($uri, $options);
}
$response = new RedirectResponse($url);
$listener = function($event) use ($response) {
$event->setResponse($response);
};
// Add the listener to the event dispatcher.
$this->dispatcher->addListener(KernelEvents::RESPONSE, $listener);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return array(
'url' => '',
);
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form['url'] = array(
'#type' => 'textfield',
'#title' => t('URL'),
'#description' => t('The URL to which the user should be redirected. This can be an internal URL like /node/1234 or an external URL like @url.', array('@url' => 'http://example.com')),
'#default_value' => $this->configuration['url'],
'#required' => TRUE,
);
return $form;
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configuration['url'] = $form_state->getValue('url');
}
/**
* {@inheritdoc}
*/
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
$access = AccessResult::allowed();
return $return_as_object ? $access : $access->isAllowed();
}
}

View file

@ -0,0 +1,123 @@
<?php
namespace Drupal\action\Plugin\Action;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Action\ConfigurableActionBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Utility\Token;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Sends a message to the current user's screen.
*
* @Action(
* id = "action_message_action",
* label = @Translation("Display a message to the user"),
* type = "system"
* )
*/
class MessageAction extends ConfigurableActionBase implements ContainerFactoryPluginInterface {
/**
* The token service.
*
* @var \Drupal\Core\Utility\Token
*/
protected $token;
/**
* The renderer.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* Constructs a MessageAction object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Utility\Token $token
* The token service.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, Token $token, RendererInterface $renderer) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->token = $token;
$this->renderer = $renderer;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container->get('token'), $container->get('renderer'));
}
/**
* {@inheritdoc}
*/
public function execute($entity = NULL) {
if (empty($this->configuration['node'])) {
$this->configuration['node'] = $entity;
}
$message = $this->token->replace($this->configuration['message'], $this->configuration);
$build = [
'#markup' => $message,
];
// @todo Fix in https://www.drupal.org/node/2577827
drupal_set_message($this->renderer->renderPlain($build));
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return array(
'message' => '',
);
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form['message'] = array(
'#type' => 'textarea',
'#title' => t('Message'),
'#default_value' => $this->configuration['message'],
'#required' => TRUE,
'#rows' => '8',
'#description' => t('The message to be displayed to the current user. You may include placeholders like [node:title], [user:account-name], [user:display-name] and [comment:body] to represent data that will be different each time message is sent. Not all placeholders will be available in all contexts.'),
);
return $form;
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configuration['message'] = $form_state->getValue('message');
unset($this->configuration['node']);
}
/**
* {@inheritdoc}
*/
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
$result = AccessResult::allowed();
return $return_as_object ? $result : $result->isAllowed();
}
}

View file

@ -0,0 +1,69 @@
<?php
namespace Drupal\action\Plugin\migrate\source;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
use Drupal\migrate\Row;
/**
* Drupal action source from database.
*
* @MigrateSource(
* id = "action",
* source_provider = "system"
* )
*/
class Action extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function query() {
return $this->select('actions', 'a')
->fields('a');
}
/**
* {@inheritdoc}
*/
public function fields() {
$fields = array(
'aid' => $this->t('Action ID'),
'type' => $this->t('Module'),
'callback' => $this->t('Callback function'),
'parameters' => $this->t('Action configuration'),
);
if ($this->getModuleSchemaVersion('system') >= 7000) {
$fields['label'] = $this->t('Label of the action');
}
else {
$fields['description'] = $this->t('Action description');
}
return $fields;
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['aid']['type'] = 'string';
return $ids;
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
$aid = $row->getSourceProperty('aid');
if (is_numeric($aid)) {
if ($this->getModuleSchemaVersion('system') >= 7000) {
$label = $row->getSourceProperty('label');
}
else {
$label = $row->getSourceProperty('description');
}
$row->setSourceProperty('aid', $label);
}
}
}

View file

@ -0,0 +1,37 @@
<?php
namespace Drupal\action\Tests;
use Drupal\simpletest\WebTestBase;
/**
* Test behaviors when visiting the action listing page.
*
* @group action
*/
class ActionListTest extends WebTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = array('action');
/**
* Tests the behavior when there are no actions to list in the admin page.
*/
public function testEmptyActionList() {
// Create a user with permission to view the actions administration pages.
$this->drupalLogin($this->drupalCreateUser(['administer actions']));
// Ensure the empty text appears on the action list page.
/** @var $storage \Drupal\Core\Entity\EntityStorageInterface */
$storage = $this->container->get('entity.manager')->getStorage('action');
$actions = $storage->loadMultiple();
$storage->delete($actions);
$this->drupalGet('/admin/config/system/actions');
$this->assertRaw('There is no Action yet.');
}
}

View file

@ -0,0 +1,10 @@
name: 'Action bulk form test'
type: module
description: 'Support module for action bulk form testing.'
package: Testing
version: VERSION
core: 8.x
dependencies:
- action
- views
- node

View file

@ -0,0 +1,181 @@
langcode: en
status: true
dependencies:
module:
- node
- user
id: test_bulk_form
label: form
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: null
display_options:
access:
type: perm
cache:
type: tag
query:
type: views_query
exposed_form:
type: basic
pager:
type: full
options:
items_per_page: 10
style:
type: table
options:
grouping: { }
row_class: ''
default_row_class: true
override: true
sticky: false
summary: ''
columns:
title: title
node_bulk_form: node_bulk_form
info:
title:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
bulk_form:
align: ''
separator: ''
empty_column: false
responsive: ''
default: ''
empty_table: false
row:
type: fields
fields:
title:
id: title
table: node_field_data
field: title
label: ''
alter:
alter_text: false
make_link: false
absolute: false
trim: false
word_boundary: false
ellipsis: false
strip_tags: false
html: false
hide_empty: false
empty_zero: false
plugin_id: field
entity_type: node
entity_field: title
node_bulk_form:
id: node_bulk_form
table: node
field: node_bulk_form
relationship: none
group_type: group
admin_label: ''
label: 'Bulk form'
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
plugin_id: node_bulk_form
entity_type: node
filters:
status:
value: '1'
table: node_field_data
field: status
id: status
expose:
operator: ''
group: 1
plugin_id: boolean
entity_type: node
entity_field: status
sorts:
created:
id: created
table: node_field_data
field: created
order: DESC
plugin_id: date
entity_type: node
entity_field: created
title: form
page_1:
display_plugin: page
id: page_1
display_title: Page
position: null
display_options:
path: test_bulk_form
page_2:
display_plugin: page
id: page_2
display_title: Page
position: null
display_options:
path: test_bulk_form_empty
defaults:
style: false
empty: false
style:
type: default
empty:
area:
id: area
table: views
field: area_text_custom
empty: true
content: 'This view is empty.'
plugin_id: text_custom

View file

@ -0,0 +1,41 @@
<?php
namespace Drupal\Tests\action\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests that uninstalling actions does not remove other module's actions.
*
* @group action
* @see \Drupal\action\Plugin\views\field\BulkForm
*/
class ActionUninstallTest extends BrowserTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = array('views', 'action');
/**
* Tests Action uninstall.
*/
public function testActionUninstall() {
\Drupal::service('module_installer')->uninstall(array('action'));
$storage = $this->container->get('entity_type.manager')->getStorage('action');
$storage->resetCache(['user_block_user_action']);
$this->assertTrue($storage->load('user_block_user_action'), 'Configuration entity \'user_block_user_action\' still exists after uninstalling action module.' );
$admin_user = $this->drupalCreateUser(array('administer users'));
$this->drupalLogin($admin_user);
$this->drupalGet('admin/people');
// Ensure we have the user_block_user_action listed.
$this->assertRaw('<option value="user_block_user_action">Block the selected user(s)</option>');
}
}

View file

@ -0,0 +1,156 @@
<?php
namespace Drupal\Tests\action\Functional;
use Drupal\Tests\BrowserTestBase;
use Drupal\views\Views;
/**
* Tests the views bulk form test.
*
* @group action
* @see \Drupal\action\Plugin\views\field\BulkForm
*/
class BulkFormTest extends BrowserTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = array('node', 'action_bulk_test');
/**
* Tests the bulk form.
*/
public function testBulkForm() {
$node_storage = $this->container->get('entity.manager')->getStorage('node');
// First, test an empty bulk form with the default style plugin to make sure
// the empty region is rendered correctly.
$this->drupalGet('test_bulk_form_empty');
$this->assertText(t('This view is empty.'), 'Empty text found on empty bulk form.');
$nodes = array();
for ($i = 0; $i < 10; $i++) {
// Ensure nodes are sorted in the same order they are inserted in the
// array.
$timestamp = REQUEST_TIME - $i;
$nodes[] = $this->drupalCreateNode(array(
'sticky' => FALSE,
'created' => $timestamp,
'changed' => $timestamp,
));
}
$this->drupalGet('test_bulk_form');
// Test that the views edit header appears first.
$first_form_element = $this->xpath('//form/div[1][@id = :id]', array(':id' => 'edit-header'));
$this->assertTrue($first_form_element, 'The views form edit header appears first.');
$this->assertFieldById('edit-action', NULL, 'The action select field appears.');
// Make sure a checkbox appears on all rows.
$edit = array();
for ($i = 0; $i < 10; $i++) {
$this->assertFieldById('edit-node-bulk-form-' . $i, NULL, format_string('The checkbox on row @row appears.', array('@row' => $i)));
$edit["node_bulk_form[$i]"] = TRUE;
}
// Log in as a user with 'administer nodes' permission to have access to the
// bulk operation.
$this->drupalCreateContentType(['type' => 'page']);
$admin_user = $this->drupalCreateUser(['administer nodes', 'edit any page content', 'delete any page content']);
$this->drupalLogin($admin_user);
$this->drupalGet('test_bulk_form');
// Set all nodes to sticky and check that.
$edit += array('action' => 'node_make_sticky_action');
$this->drupalPostForm(NULL, $edit, t('Apply to selected items'));
foreach ($nodes as $node) {
$changed_node = $node_storage->load($node->id());
$this->assertTrue($changed_node->isSticky(), format_string('Node @nid got marked as sticky.', array('@nid' => $node->id())));
}
$this->assertText('Make content sticky was applied to 10 items.');
// Unpublish just one node.
$node = $node_storage->load($nodes[0]->id());
$this->assertTrue($node->isPublished(), 'The node is published.');
$edit = array('node_bulk_form[0]' => TRUE, 'action' => 'node_unpublish_action');
$this->drupalPostForm(NULL, $edit, t('Apply to selected items'));
$this->assertText('Unpublish content was applied to 1 item.');
// Load the node again.
$node_storage->resetCache(array($node->id()));
$node = $node_storage->load($node->id());
$this->assertFalse($node->isPublished(), 'A single node has been unpublished.');
// The second node should still be published.
$node_storage->resetCache(array($nodes[1]->id()));
$node = $node_storage->load($nodes[1]->id());
$this->assertTrue($node->isPublished(), 'An unchecked node is still published.');
// Set up to include just the sticky actions.
$view = Views::getView('test_bulk_form');
$display = &$view->storage->getDisplay('default');
$display['display_options']['fields']['node_bulk_form']['include_exclude'] = 'include';
$display['display_options']['fields']['node_bulk_form']['selected_actions']['node_make_sticky_action'] = 'node_make_sticky_action';
$display['display_options']['fields']['node_bulk_form']['selected_actions']['node_make_unsticky_action'] = 'node_make_unsticky_action';
$view->save();
$this->drupalGet('test_bulk_form');
$options = $this->xpath('//select[@id=:id]/option', array(':id' => 'edit-action'));
$this->assertEqual(count($options), 2);
$this->assertOption('edit-action', 'node_make_sticky_action');
$this->assertOption('edit-action', 'node_make_unsticky_action');
// Set up to exclude the sticky actions.
$view = Views::getView('test_bulk_form');
$display = &$view->storage->getDisplay('default');
$display['display_options']['fields']['node_bulk_form']['include_exclude'] = 'exclude';
$view->save();
$this->drupalGet('test_bulk_form');
$this->assertNoOption('edit-action', 'node_make_sticky_action');
$this->assertNoOption('edit-action', 'node_make_unsticky_action');
// Check the default title.
$this->drupalGet('test_bulk_form');
$result = $this->xpath('//label[@for="edit-action"]');
$this->assertEqual('Action', $result[0]->getText());
// Setup up a different bulk form title.
$view = Views::getView('test_bulk_form');
$display = &$view->storage->getDisplay('default');
$display['display_options']['fields']['node_bulk_form']['action_title'] = 'Test title';
$view->save();
$this->drupalGet('test_bulk_form');
$result = $this->xpath('//label[@for="edit-action"]');
$this->assertEqual('Test title', $result[0]->getText());
$this->drupalGet('test_bulk_form');
// Call the node delete action.
$edit = array();
for ($i = 0; $i < 5; $i++) {
$edit["node_bulk_form[$i]"] = TRUE;
}
$edit += array('action' => 'node_delete_action');
$this->drupalPostForm(NULL, $edit, t('Apply to selected items'));
// Make sure we don't show an action message while we are still on the
// confirmation page.
$errors = $this->xpath('//div[contains(@class, "messages--status")]');
$this->assertFalse($errors, 'No action message shown.');
$this->drupalPostForm(NULL, array(), t('Delete'));
$this->assertText(t('Deleted 5 posts.'));
// Check if we got redirected to the original page.
$this->assertUrl('test_bulk_form');
}
}

View file

@ -0,0 +1,89 @@
<?php
namespace Drupal\Tests\action\Functional;
use Drupal\Component\Utility\Crypt;
use Drupal\system\Entity\Action;
use Drupal\Tests\BrowserTestBase;
/**
* Tests complex actions configuration by adding, editing, and deleting a
* complex action.
*
* @group action
*/
class ConfigurationTest extends BrowserTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = array('action');
/**
* Tests configuration of advanced actions through administration interface.
*/
function testActionConfiguration() {
// Create a user with permission to view the actions administration pages.
$user = $this->drupalCreateUser(array('administer actions'));
$this->drupalLogin($user);
// Make a POST request to admin/config/system/actions.
$edit = array();
$edit['action'] = Crypt::hashBase64('action_goto_action');
$this->drupalPostForm('admin/config/system/actions', $edit, t('Create'));
$this->assertResponse(200);
// Make a POST request to the individual action configuration page.
$edit = array();
$action_label = $this->randomMachineName();
$edit['label'] = $action_label;
$edit['id'] = strtolower($action_label);
$edit['url'] = 'admin';
$this->drupalPostForm('admin/config/system/actions/add/' . Crypt::hashBase64('action_goto_action'), $edit, t('Save'));
$this->assertResponse(200);
// Make sure that the new complex action was saved properly.
$this->assertText(t('The action has been successfully saved.'), "Make sure we get a confirmation that we've successfully saved the complex action.");
$this->assertText($action_label, "Make sure the action label appears on the configuration page after we've saved the complex action.");
// Make another POST request to the action edit page.
$this->clickLink(t('Configure'));
preg_match('|admin/config/system/actions/configure/(.+)|', $this->getUrl(), $matches);
$aid = $matches[1];
$edit = array();
$new_action_label = $this->randomMachineName();
$edit['label'] = $new_action_label;
$edit['url'] = 'admin';
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertResponse(200);
// Make sure that the action updated properly.
$this->assertText(t('The action has been successfully saved.'), "Make sure we get a confirmation that we've successfully updated the complex action.");
$this->assertNoText($action_label, "Make sure the old action label does NOT appear on the configuration page after we've updated the complex action.");
$this->assertText($new_action_label, "Make sure the action label appears on the configuration page after we've updated the complex action.");
$this->clickLink(t('Configure'));
$element = $this->xpath('//input[@type="text" and @value="admin"]');
$this->assertTrue(!empty($element), 'Make sure the URL appears when re-editing the action.');
// Make sure that deletions work properly.
$this->drupalGet('admin/config/system/actions');
$this->clickLink(t('Delete'));
$this->assertResponse(200);
$edit = array();
$this->drupalPostForm("admin/config/system/actions/configure/$aid/delete", $edit, t('Delete'));
$this->assertResponse(200);
// Make sure that the action was actually deleted.
$this->assertRaw(t('The action %action has been deleted.', array('%action' => $new_action_label)), 'Make sure that we get a delete confirmation message.');
$this->drupalGet('admin/config/system/actions');
$this->assertResponse(200);
$this->assertNoText($new_action_label, "Make sure the action label does not appear on the overview page after we've deleted the action.");
$action = Action::load($aid);
$this->assertFalse($action, 'Make sure the action is gone after being deleted.');
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace Drupal\Tests\action\Kernel\Migrate\d6;
use Drupal\config\Tests\SchemaCheckTestTrait;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade variables to action.settings.yml.
*
* @group migrate_drupal_6
*/
class MigrateActionConfigsTest extends MigrateDrupal6TestBase {
use SchemaCheckTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['action'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('action_settings');
}
/**
* Tests migration of action variables to action.settings.yml.
*/
public function testActionSettings() {
$config = $this->config('action.settings');
$this->assertIdentical(35, $config->get('recursion_limit'));
$this->assertConfigSchema(\Drupal::service('config.typed'), 'action.settings', $config->get());
}
}

View file

@ -0,0 +1,72 @@
<?php
namespace Drupal\Tests\action\Kernel\Migrate\d6;
use Drupal\system\Entity\Action;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Tests migration of action items.
*
* @group migrate_drupal_6
*/
class MigrateActionsTest extends MigrateDrupal6TestBase {
public static $modules = ['action', 'comment', 'node'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('d6_action');
}
/**
* Test Drupal 6 action migration to Drupal 8.
*/
public function testActions() {
// Test default actions.
$this->assertEntity('node_publish_action', 'Publish post', 'node', []);
$this->assertEntity('node_make_sticky_action', 'Make post sticky', 'node', []);
$this->assertEntity('user_block_user_action', 'Block current user', 'user', []);
$this->assertEntity('comment_publish_action', 'Publish comment', 'comment', []);
// Test advanced actions.
$this->assertEntity('unpublish_comment_containing_keyword_s_', 'Unpublish comment containing keyword(s)', 'comment', ["keywords" => [0 => "drupal"]]);
$this->assertEntity('change_the_author_of_a_post', 'Change the author of a post', 'node', ["owner_uid" => "2"]);
$this->assertEntity('unpublish_post_containing_keyword_s_', 'Unpublish post containing keyword(s)', 'node', ["keywords" => [0 => "drupal"]]);
$this->assertEntity('display_a_message_to_the_user', 'Display a message to the user', 'system', ["message" => "Drupal migration test"]);
$this->assertEntity('send_e_mail', 'Send e-mail', 'system', [
"recipient" => "test@example.com",
"subject" => "Drupal migration test",
"message" => "Drupal migration test"
]);
$this->assertEntity('redirect_to_url', 'Redirect to URL', 'system', ["url" => "https://www.drupal.org"]);
}
/**
* Asserts various aspects of an Action entity.
*
* @param string $id
* The expected Action ID.
* @param string $label
* The expected Action label.
* @param string $type
* The expected Action type.
* @param array $configuration
* The expected Action configuration.
*/
protected function assertEntity($id, $label, $type, $configuration) {
$action = Action::load($id);
$this->assertTrue($action instanceof Action);
/** @var \Drupal\system\Entity\Action $action */
$this->assertIdentical($id, $action->id());
$this->assertIdentical($label, $action->label());
$this->assertIdentical($type, $action->getType());
$this->assertIdentical($configuration, $action->get('configuration'));
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace Drupal\Tests\action\Kernel\Migrate\d7;
use Drupal\config\Tests\SchemaCheckTestTrait;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
/**
* Upgrade variables to action.settings.yml.
*
* @group migrate_drupal_7
*/
class MigrateActionConfigsTest extends MigrateDrupal7TestBase {
use SchemaCheckTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['action'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('action_settings');
}
/**
* Tests migration of action variables to action.settings.yml.
*/
public function testActionSettings() {
$config = $this->config('action.settings');
$this->assertSame(28, $config->get('recursion_limit'));
$this->assertConfigSchema(\Drupal::service('config.typed'), 'action.settings', $config->get());
}
}

View file

@ -0,0 +1,72 @@
<?php
namespace Drupal\Tests\action\Kernel\Migrate\d7;
use Drupal\system\Entity\Action;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
/**
* Tests migration of action items.
*
* @group action
*/
class MigrateActionsTest extends MigrateDrupal7TestBase {
public static $modules = ['action', 'comment', 'node'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('d7_action');
}
/**
* Test Drupal 7 action migration to Drupal 8.
*/
public function testActions() {
// Test default actions.
$this->assertEntity('node_publish_action', 'Publish content', 'node', []);
$this->assertEntity('node_make_sticky_action', 'Make content sticky', 'node', []);
$this->assertEntity('user_block_user_action', 'Block current user', 'user', []);
$this->assertEntity('comment_publish_action', 'Publish comment', 'comment', []);
// Test advanced actions.
$this->assertEntity('unpublish_comment_containing_keyword_s_', 'Unpublish comment containing keyword(s)', 'comment', ["keywords" => [0 => "drupal"]]);
$this->assertEntity('change_the_author_of_content', 'Change the author of content', 'node', ["owner_uid" => "2"]);
$this->assertEntity('unpublish_content_containing_keyword_s_', 'Unpublish content containing keyword(s)', 'node', ["keywords" => [0 => "drupal"]]);
$this->assertEntity('display_a_message_to_the_user', 'Display a message to the user', 'system', ["message" => "Drupal migration test"]);
$this->assertEntity('send_e_mail', 'Send e-mail', 'system', [
"recipient" => "test@example.com",
"subject" => "Drupal migration test",
"message" => "Drupal migration test"
]);
$this->assertEntity('redirect_to_url', 'Redirect to URL', 'system', ["url" => "https://www.drupal.org"]);
}
/**
* Asserts various aspects of an Action entity.
*
* @param string $id
* The expected Action ID.
* @param string $label
* The expected Action label.
* @param string $type
* The expected Action type.
* @param array $configuration
* The expected Action configuration.
*/
protected function assertEntity($id, $label, $type, $configuration) {
$action = Action::load($id);
$this->assertTrue($action instanceof Action);
/** @var \Drupal\system\Entity\Action $action */
$this->assertIdentical($id, $action->id());
$this->assertIdentical($label, $action->label());
$this->assertIdentical($type, $action->getType());
$this->assertIdentical($configuration, $action->get('configuration'));
}
}

View file

@ -0,0 +1,62 @@
<?php
namespace Drupal\Tests\action\Kernel\Plugin\migrate\source;
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
/**
* Tests actions source plugin.
*
* @covers \Drupal\action\Plugin\migrate\source\Action
* @group action
*/
class ActionTest extends MigrateSqlSourceTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['action', 'migrate_drupal'];
/**
* {@inheritdoc}
*/
public function providerSource() {
$tests = [];
$tests[0][0]['actions'] = [
[
'aid' => 'Redirect to node list page',
'type' => 'system',
'callback' => 'system_goto_action',
'parameters' => 'a:1:{s:3:"url";s:4:"node";}',
'description' => 'Redirect to node list page',
],
[
'aid' => 'Test notice email',
'type' => 'system',
'callback' => 'system_send_email_action',
'parameters' => 'a:3:{s:9:"recipient";s:7:"%author";s:7:"subject";s:4:"Test";s:7:"message";s:4:"Test',
'description' => 'Test notice email',
],
[
'aid' => 'comment_publish_action',
'type' => 'comment',
'callback' => 'comment_publish_action',
'parameters' => NULL,
'description' => NULL,
],
[
'aid' => 'node_publish_action',
'type' => 'comment',
'callback' => 'node_publish_action',
'parameters' => NULL,
'description' => NULL,
],
];
// The expected results are identical to the source data.
$tests[0][1] = $tests[0][0]['actions'];
return $tests;
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace Drupal\Tests\action\Unit\Menu;
use Drupal\Tests\Core\Menu\LocalTaskIntegrationTestBase;
/**
* Tests action local tasks.
*
* @group action
*/
class ActionLocalTasksTest extends LocalTaskIntegrationTestBase {
protected function setUp() {
$this->directoryList = array('action' => 'core/modules/action');
parent::setUp();
}
/**
* Tests local task existence.
*/
public function testActionLocalTasks() {
$this->assertLocalTasks('entity.action.collection', array(array('action.admin')));
}
}