Commit 21c8f344 authored by New Zeal's avatar New Zeal

add tests

parent fe010e5c
......@@ -35,3 +35,9 @@ Fix thread urls and redirects
8.x-1.0-alpha12
Refine tabs and access rules
8.x-1.0-beta1
Add tests along with corrections to scripts
TodDo
Delete messages in thread when thread is deleted
......@@ -4,7 +4,6 @@ dependencies: { }
template: conversation
label: Messages
description: 'Message thread to accompany Private Messages'
message_template: private_message
settings:
message_template: private_message
view_id: private_messages
......
message_thread.message_thread_template.*:
message_thread.template.*:
type: config_entity
label: 'Message thread template'
mapping:
......@@ -11,19 +11,43 @@ message_thread.message_thread_template.*:
description:
type: text
label: 'Description'
message_template:
type: string
label: 'Message Template'
text:
type: sequence
label: 'Message Text'
sequence:
type: text_format
label: 'Text'
message_template:
type: string
label: 'Message Template'
view_id:
type: string
label: 'Messages View'
view_display_id:
type: string
label: 'Messages View Display'
view_display:
type: string
label: 'View Display'
settings:
type: mapping
label: 'Settings'
mapping:
message_template:
type: string
label: 'Message Template'
thread_view_id:
type: string
label: 'Thread View'
thread_view_display_id:
type: string
label: 'Thread View Display'
view_id:
type: string
label: 'Messages View'
view_display_id:
type: string
label: 'Messages View Display'
'token options':
type: mapping
label: 'Token options'
......
......@@ -45,6 +45,9 @@ function message_thread_help($route_name, RouteMatchInterface $arg) {
* Implements hook_form_alter().
*/
function message_thread_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
if (substr($form_id,0, 8) != 'message_' ) {
return;
}
// When a message is created we need to ensure that the participants are included
// This is best done in the validation hook to ensure participants are not missed from submit functions
$thread_templates = \Drupal::entityTypeManager()->getListBuilder('message_thread_template')->load();
......@@ -488,7 +491,7 @@ function message_thread_get_messages($thread_id) {
*/
function message_history_message_thread_view_alter(array &$build, EntityInterface $message_thread,
EntityViewDisplayInterface
$display) {
$display) {
// Update the message_history table, stating that this user viewed all messages in this thread.
if (!\Drupal::service('module_handler')->moduleExists('message_history')) {
......@@ -509,4 +512,23 @@ $display) {
$build['#attached']['drupalSettings']['message_history']['itemsToMarkAsRead'][$mid] = TRUE;
}
$build['#attached']['library'][] = 'message_history/mark-as-read';
}
\ No newline at end of file
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
function message_thread_theme_suggestions_message_thread(array $variables) {
$suggestions = [];
/** @var \Drupal\message\MessageInterface $message */
$message_thread = $variables['elements']['#message_thread'];
$sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
$suggestions[] = 'message_thread__' . $sanitized_view_mode;
$suggestions[] = 'message_thread__' . $message_thread->bundle();
$suggestions[] = 'message_thread__' . $message_thread->bundle() . '__' . $sanitized_view_mode;
$suggestions[] = 'message_thread__' . $message_thread->id();
$suggestions[] = 'message_thread__' . $message_thread->id() . '__' . $sanitized_view_mode;
return $suggestions;
}
administer message thread templates:
title: 'Administer message thread templates'
description: 'Access to administer message thread templates.'
administer message threads:
title: 'Administer message threads'
description: 'Access to administer message threads.'
# todo overview page doesn't exist. Replace this permission
overview message threads:
title: 'Overview message threads'
description: 'Access to view message threads overview page.'
......
message_thread.overview_threads:
path: '/admin/content/message-threads'
defaults:
_title: 'Message Threads'
_entity_list: 'message_thread'
requirements:
_permission: 'overview message threads'
message_thread.overview_templates:
path: '/admin/structure/message-threads'
defaults:
......@@ -13,7 +5,7 @@ message_thread.overview_templates:
entity_type: 'message_thread_template'
_title: 'Message thread templates'
requirements:
_permission: 'administer message private'
_permission: 'administer message thread templates'
#message_thread.thread_add:
......@@ -25,28 +17,28 @@ message_thread.overview_templates:
# _permission: 'administer message templates'
message_thread.template_add:
path: '/admin/structure/message-threads/template/add'
path: '/admin/structure/message-thread/template/add'
defaults:
_entity_form: 'message_thread_template.add'
_title: 'Add message thread template'
requirements:
_permission: 'administer message templates'
_permission: 'administer message thread templates'
entity.message_thread_template.edit_form:
path: '/admin/structure/message-threads/manage/{message_thread_template}'
path: '/admin/structure/message-thread/manage/{message_thread_template}'
defaults:
_entity_form: 'message_thread_template.edit'
_title: 'Edit message thread template'
requirements:
_permission: 'administer message templates'
_permission: 'administer message thread templates'
entity.message_thread_template.delete_form:
path: '/admin/structure/message-threads/delete/{message_thread_template}'
path: '/admin/structure/message-thread/delete/{message_thread_template}'
defaults:
_entity_form: 'message_thread_template.delete'
_title: 'Delete message thread template'
requirements:
_permission: 'administer message templates'
_permission: 'administer message thread templates'
message_thread.add_page:
path: '/message/thread/add'
......
<?php
/**
* @file
* Builds placeholder replacement tokens for message-related data.
*/
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\user\Entity\User;
/**
* Implements hook_token_info().
*/
function message_thread_token_info() {
$type = [
'name' => t('message threads'),
'description' => t('Tokens related to individual content items, or "message threads".'),
'needs-data' => 'message_thread',
];
// Core tokens for message threads.
$message_thread['thread_id'] = [
'name' => t("Thread ID"),
'description' => t('The unique ID of the message thread.'),
];
$message_thread['template'] = [
'name' => t("Message thread template"),
];
$message_thread['template-name'] = [
'name' => t("message thread template name"),
'description' => t("The human-readable name of the message thread template."),
];
$message_thread['uuid'] = [
'name' => t("Message thread UID"),
'description' => t("The message thread UUID."),
];
$message_thread['created'] = [
'name' => t("Date created"),
'type' => 'date',
];
$message_thread['author'] = [
'name' => t("Author"),
'type' => 'user',
];
dpm('tokens');
return [
'types' => ['message_thread' => $type],
'tokens' => ['message_thread' => $message_thread],
];
}
/**
* Implements hook_tokens().
*/
function message_thread_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
$token_service = \Drupal::token();
$replacements = [];
if ($type == 'message_thread' && !empty($data['message_thread'])) {
/** @var \Drupal\message\Entity\Message $message_thread */
$message_thread = $data['message_thread'];
foreach ($tokens as $name => $original) {
switch ($name) {
// Simple key values on the message.
case 'thread_id':
$replacements[$original] = $message_thread->id();
break;
case 'template':
$replacements[$original] = $message_thread->getTemplate()->id();
break;
case 'template-name':
$replacements[$original] = $message_thread->getTemplate()->label();
break;
case 'uuid':
$replacements[$original] = $message_thread->getUuid();
break;
// Default values for the chained tokens handled below.
case 'author':
$account = $message_thread->getOwner() ? $message_thread->getOwner() : User::load(0);
$replacements[$original] = $account->label();
break;
case 'created':
$replacements[$original] = \Drupal::service('date.formatter')->format($message_thread->getCreatedTime(), 'medium', '', NULL);
break;
}
}
if ($author_tokens = $token_service->findWithPrefix($tokens, 'author')) {
$replacements += $token_service->generate('user', $author_tokens, ['user' => $message_thread->getOwner()], $options, $bubbleable_metadata);
}
if ($created_tokens = $token_service->findWithPrefix($tokens, 'created')) {
$replacements += $token_service->generate('date', $created_tokens, ['date' => $message_thread->getCreatedTime()], $options, $bubbleable_metadata);
}
}
return $replacements;
}
......@@ -203,31 +203,6 @@ class MessageThread extends ContentEntityBase {
return $fields;
}
/**
* {@inheritdoc}
*/
public function getText($langcode = Language::LANGCODE_NOT_SPECIFIED, $delta = NULL) {
if (!$message_thread = $this->getTemplate()) {
// Message thread does not exist any more.
// We don't throw an exception, to make sure we don't break sites that
// removed the message thread, so we silently ignore.
return [];
}
$message_arguments = $this->getArguments();
$message_thread_text = $message_thread->getText($langcode, $delta);
$output = $this->processArguments($message_arguments, $message_thread_text);
$token_options = $message_thread->getSetting('token options', []);
if (!empty($token_options['token replace'])) {
// Token should be processed.
$output = $this->processTokens($output, !empty($token_options['clear']));
}
return $output;
}
/**
* Process the message given the arguments saved with it.
*
......@@ -254,7 +229,7 @@ class MessageThread extends ContentEntityBase {
if ($value['pass message']) {
// Pass the message object as-well.
$value['arguments']['message'] = $this;
$value['arguments']['message_thread'] = $this;
}
$arguments[$key] = call_user_func_array($value['callback'], $value['arguments']);
......@@ -288,7 +263,7 @@ class MessageThread extends ContentEntityBase {
foreach ($output as $key => $value) {
$output[$key] = \Drupal::token()
->replace($value, ['message' => $this], $options);
->replace($value, ['message_thread' => $this], $options);
}
return $output;
......@@ -307,20 +282,6 @@ class MessageThread extends ContentEntityBase {
throw new MessageException('No valid template found.');
}
// Handle hard coded arguments.
foreach ($this->getTemplate()->getText() as $text) {
preg_match_all('/[@|%|\!]\{([a-z0-9:_\-]+?)\}/i', $text, $matches);
foreach ($matches[1] as $delta => $token) {
$output = \Drupal::token()->replace('[' . $token . ']', ['message' => $this], $token_options);
if ($output != '[' . $token . ']') {
// Token was replaced and token sanitizes.
$argument = $matches[0][$delta];
$tokens[$argument] = Markup::create($output);
}
}
}
$arguments = $this->getArguments();
$this->setArguments(array_merge($tokens, $arguments));
......@@ -361,7 +322,7 @@ class MessageThread extends ContentEntityBase {
* {@inheritdoc}
*/
public static function deleteMultiple(array $ids) {
\Drupal::entityTypeManager()->getStorage('message')->delete($ids);
\Drupal::entityTypeManager()->getStorage('message_thread')->delete($ids);
}
/**
......@@ -376,9 +337,6 @@ class MessageThread extends ContentEntityBase {
/**
* {@inheritdoc}
*/
public function __toString() {
return trim(implode("\n", $this->getText()));
}
/**
* {@inheritdoc}
......
......@@ -6,7 +6,7 @@ use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Language\Language;
use Drupal\language\ConfigurableLanguageManagerInterface;
use Drupal\message\MessageTemplateInterface;
use Drupal\message_thread\MessageThreadTemplateInterface;
/**
* Defines the Message thread template entity class.
......@@ -50,7 +50,7 @@ use Drupal\message\MessageTemplateInterface;
* }
* )
*/
class MessageThreadTemplate extends ConfigEntityBundleBase implements MessageTemplateInterface {
class MessageThreadTemplate extends ConfigEntityBundleBase implements MessageThreadTemplateInterface {
/**
* The ID of this message template thread.
......@@ -87,13 +87,6 @@ class MessageThreadTemplate extends ConfigEntityBundleBase implements MessageTem
*/
protected $message_template;
/**
* The serialised text of the message template thread.
*
* @var array
*/
protected $text = [];
/**
* Array with the arguments and their replacement value, or callbacks.
*
......@@ -117,20 +110,20 @@ class MessageThreadTemplate extends ConfigEntityBundleBase implements MessageTem
* // get the most up-to-date path of message ID 1.
* '@message-url' => [
* 'callback' => 'url',
* 'callback arguments' => ['message/1'],
* 'callback arguments' => ['message/thread/1'],
* ],
*
* // Use callback, but instead of passing callback argument, we will
* // pass the Message entity itself.
* '@message-title' => [
* 'callback' => 'example_bar',
* 'pass message' => TRUE,
* 'pass message thread' => TRUE,
* ],
* ];
* @endcode
*
* Arguments assigned to message-template can be overridden by the ones
* assigned to the message.
* assigned to the message thread.
*/
public $arguments = [];
......@@ -145,13 +138,13 @@ class MessageThreadTemplate extends ConfigEntityBundleBase implements MessageTem
* global settings will be used unless 'purge_override' is TRUE).
*
* Token settings:
* - 'token replace': Indicate if message's text should be passed
* - 'token replace': Indicate if message thread's text should be passed
* through token_replace(). defaults to TRUE.
* - 'token options': Array with options to be passed to
* token_replace().
*
* Tokens settings assigned to message-template can be overriden by the ones
* assigned to the message.
* assigned to the message thread.
*
* @var array
*/
......@@ -265,51 +258,6 @@ class MessageThreadTemplate extends ConfigEntityBundleBase implements MessageTem
return $this->uuid;
}
/**
* {@inheritdoc}
*/
public function getText($langcode = Language::LANGCODE_NOT_SPECIFIED, $delta = NULL) {
$text = $this->text;
$language_manager = \Drupal::languageManager();
if ($language_manager instanceof ConfigurableLanguageManagerInterface) {
if ($langcode == Language::LANGCODE_NOT_SPECIFIED) {
// Get the default language code when not specified.
$langcode = $language_manager->getDefaultLanguage()->getId();
}
$config_translation = $language_manager->getLanguageConfigOverride($langcode, 'message.template.' . $this->id());
$translated_text = $config_translation->get('text');
// If there was no translated text, we return nothing instead of falling
// back to the default language.
$text = $translated_text ?: [];
}
// Process text format.
foreach ($text as $key => $item) {
// Call the renderer directly instead of adding a dependency on the Filter
// module's check_markup() function.
// @see check_markup()
$build = [
'#type' => 'processed_text',
'#text' => $item['value'],
'#format' => $item['format'],
'#langcode' => $langcode,
];
$text[$key] = \Drupal::service('renderer')->renderPlain($build);
}
if ($delta) {
// Return just the delta if it exists. Always wrap in an array here to
// ensure compatibility with methods calling getText.
return isset($text[$delta]) ? [$text[$delta]] : [];
}
return $text;
}
/**
* {@inheritdoc}
*/
......@@ -331,20 +279,6 @@ class MessageThreadTemplate extends ConfigEntityBundleBase implements MessageTem
* {@inheritdoc}
*/
public function preSave(EntityStorageInterface $storage) {
$this->text = array_filter($this->text, function ($partial) {
// Filter out any partials with an empty `value`.
return !empty($partial['value']);
});
$language_manager = \Drupal::languageManager();
if ($language_manager instanceof ConfigurableLanguageManagerInterface) {
// Set the values for the default site language.
$config_translation = $language_manager->getLanguageConfigOverride($language_manager->getDefaultLanguage()->getId(), 'message_thread.thread_template.' . $this->id());
$config_translation->set('text', $this->text);
$config_translation->save();
}
parent::preSave($storage);
}
......
......@@ -24,16 +24,6 @@ class MessageThreadForm extends ContentEntityForm {
/** @var \Drupal\message\Entity\Message $message */
$message_thread = $this->entity;
$template = \Drupal::entityTypeManager()->getStorage('message_thread_template')->load($this->entity->bundle());
if ($this->config('message_thread.settings')->get('show_preview')) {
$form['text'] = [
'#type' => 'item',
'#title' => t('Message template'),
'#markup' => implode("\n", $template->getText()),
];
}
// Create the advanced vertical tabs "group".
$form['advanced'] = [
'#type' => 'details',
......
......@@ -227,25 +227,22 @@ class MessageThreadTemplateForm extends EntityForm {
];
// $multiple = new MessageTemplateMultipleTextField($this->entity, [get_class($this), 'addMoreAjax']);
// $multiple->textField($form, $form_state);
$form['settings']['token options']['clear'] = [
'#title' => $this->t('Clear empty tokens'),
'#type' => 'checkbox',
'#description' => $this->t('When this option is selected, empty tokens will be removed from display.'),
'#default_value' => isset($settings['token options']['clear']) ? $settings['token options']['clear'] : FALSE,
];
// $form['settings']['token options']['clear'] = [
// '#title' => $this->t('Clear empty tokens'),
// '#type' => 'checkbox',
// '#description' => $this->t('When this option is selected, empty tokens will be removed from display.'),
// '#default_value' => isset($settings['token options']['clear']) ? $settings['token options']['clear'] : FALSE,
// ];
//
// $form['settings']['token options']['token replace'] = array(
// '#type' => 'checkbox',
// '#title' => $this->t('Token replace'),
// '#description' => $this->t('When this option is selected, token processing will happen.'),
// '#default_value' => !isset($settings['token options']['token replace']) || !empty($settings['token options']['token replace']),
// );
$form['settings']['token options']['token replace'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Token replace'),
'#description' => $this->t('When this option is selected, token processing will happen.'),
'#default_value' => !isset($settings['token options']['token replace']) || !empty($settings['token options']['token replace']),
);
// $form['settings']['purge_override'] = [
// '#title' => $this->t('Override global purge settings'),
......@@ -336,8 +333,8 @@ class MessageThreadTemplateForm extends EntityForm {
*/
protected function actions(array $form, FormStateInterface $form_state) {
$actions = parent::actions($form, $form_state);
$actions['submit']['#value'] = t('Save message thread template ');
$actions['delete']['#value'] = t('Delete message thread template ');
$actions['submit']['#value'] = t('Save message thread template');
$actions['delete']['#value'] = t('Delete message thread template');
return $actions;
}
......@@ -372,17 +369,6 @@ class MessageThreadTemplateForm extends EntityForm {
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
// Sort by weight.
// $text = $form_state->getValue('text');
// usort($text, function ($a, $b) {
// return SortArray::sortByKeyInt($a, $b, '_weight');
// });
// // Do not store weight, as these are now sorted.
// $text = array_map(function ($a) {
// unset($a['_weight']);
// return $a;
// }, $text);
// $this->entity->set('text', $text);
parent::save($form, $form_state);
......@@ -390,7 +376,7 @@ class MessageThreadTemplateForm extends EntityForm {
'@template' => $form_state->getValue('label'),
];
drupal_set_message(t('The message thread template @template created successfully.', $params));
drupal_set_message(t('The message thread template @template created successfully.', $params));
$form_state->setRedirect('message_thread.overview_templates');
return $this->entity;
}
......
......@@ -94,20 +94,6 @@ interface MessageThreadInterface extends ContentEntityInterface, EntityOwnerInte
*/
public function setLanguage($language);
/**
* Replace arguments with their placeholders.
*
* @param string $langcode
* The language code.
* @param null|int $delta
* The delta of the message to return. If NULL all the message text will be
* returned.
*
* @return array
* The message text.
*/
public function getText($langcode = Language::LANGCODE_NOT_SPECIFIED, $delta = NULL);
/**
* Delete multiple message.
*
......
......@@ -90,7 +90,6 @@ class MessageThreadListBuilder extends EntityListBuilder {
return [
'changed' => $this->dateService->format($entity->getCreatedTime(), 'short'),
// 'title' => $this->get('field_thread_title')->getValue()[0]['value'],
'text' => $entity->getText(),
'template' => $entity->getTemplate()->label(),
'author' => $entity->getOwner()->label(),
];
......
......@@ -86,22 +86,6 @@ interface MessageThreadTemplateInterface extends ConfigEntityInterface {
*/
public function getUuid();
/**
* Retrieves the configured message text in a certain language.
*
* @param string $langcode
* The language code of the Message text field, the text should be
* extracted from.
* @param int $delta
* Optional; Represents the partial number. If not provided - all partials
* will be returned.
*
* @return array
* An array of the text field values. These will have been processed for
* their corresponding text formats.
*/
public function getText($langcode = Language::LANGCODE_NOT_SPECIFIED, $delta = NULL);
/**
* Set additional settings for the message template.
*/
......
......@@ -30,25 +30,14 @@ class MessageThreadViewBuilder extends EntityViewBuilder {
if ($langcode) {
$entity->setLanguage($langcode);
}
$partials = $entity->getText();
$extra = '';
// Get the partials the user selected for the current view mode.
$extra_fields = entity_get_display('message', $entity->bundle(), $view_mode);
foreach ($extra_fields->getComponents() as $field_name => $settings) {
// The partials are keyed with `partial_X`, check if that is set.
if (strpos($field_name, 'partial_') === 0) {
list(, $delta) = explode('_', $field_name);
if (isset($partials[$delta])) {
$extra .= $partials[$delta];
}
}
else {
// This is another field.
$display = $this->getSingleFieldDisplay($entity, $field_name, $settings);
$build += $display->build($entity);
}
$display = $this->getSingleFieldDisplay($entity, $field_name, $settings);
$build += $display->build($entity);
}
$build['#markup'] = $extra;
......
<?php
namespace Drupal\Tests\message\Functional;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
/**
* Tests admin menus for the message module.
*
* @group message_thread
*/
class MenuTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['message_thread'];
/**
* Test that the menu links are working properly.
*/
public function testMenuLinks() {
$admin = $this->drupalCreateUser([], NULL, TRUE);
$this->drupalLogin($admin);
// Link should appear on main config page.
$this->drupalGet(Url::fromRoute('system.admin_structure'));
$this->assertSession()->linkExists(t('Message thread templates'));
// Link should be on the message-specific overview page.
$this->clickLink(t('Message thread templates'));