Commit c2938505 authored by kent@passingphase.nz's avatar kent@passingphase.nz

merge in fixes and improvements from github

parent e9497141
...@@ -5,14 +5,17 @@ ...@@ -5,14 +5,17 @@
"license": "GPL-2.0+", "license": "GPL-2.0+",
"minimum-stability": "dev", "minimum-stability": "dev",
"prefer-stable": true, "prefer-stable": true,
"homepage": "https://www.drupal.org/project/message_private", "homepage": "https://www.drupal.org/project/message_thread",
"require": { "require": {
"php": "^5.5|^7.0", "php": "^5.5|^7.0",
"drupal/core": "^8.6", "drupal/core": "^8.6",
"drupal/message": "^1.0", "drupal/message": "^1.0",
"drupal/message_history": "dev-1.x",
"drupal/message_notify": "^1.0", "drupal/message_notify": "^1.0",
"drupal/message_ui": "^1.0", "drupal/message_ui": "^1.0",
"drupal/message_private": "^1.0" "drupal/message_private": "^1.0",
"drupal/message_thread_history": "1.0-alpha1",
"squizlabs/php_codesniffer": "*"
}, },
"require-dev": { "require-dev": {
"composer/installers": "^1.2", "composer/installers": "^1.2",
......
id: message_thread_delete_action
label: 'Delete selected message threads'
status: true
langcode: en
type: message_thread
plugin: message_thread_delete_action
dependencies:
module:
- message_thread
This diff is collapsed.
...@@ -7,3 +7,4 @@ configure: message_thread.admin_settings ...@@ -7,3 +7,4 @@ configure: message_thread.admin_settings
dependencies: dependencies:
- drupal:views - drupal:views
- message_private:message_private - message_private:message_private
- message_history:message_history
...@@ -2,9 +2,103 @@ ...@@ -2,9 +2,103 @@
/** /**
* @file * @file
* Message Thread un-installer. * Message Thread installer.
*/ */
use Drupal\Core\Database\Database;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Implements hook_install().
*/
function message_thread_install() {
// By default, maintain entity statistics for messages.
// @see \Drupal\message_thread\MessageStatisticsInterface
\Drupal::state()->set('message.maintain_entity_statistics', TRUE);
}
/**
* Implements hook_schema().
*/
function message_thread_schema() {
$schema['message_thread_statistics'] = [
'description' => 'Maintains statistics of message threads and messages to show "new" and "updated" flags.',
'fields' => [
'entity_id' => [
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'description' => 'The entity_id of the entity for which the statistics are compiled.',
],
'entity_type' => [
'type' => 'varchar_ascii',
'not null' => TRUE,
'default' => 'message_thread',
'length' => EntityTypeInterface::ID_MAX_LENGTH,
'description' => 'The entity_type of the entity to which this message is a reply.',
],
'field_name' => [
'type' => 'varchar_ascii',
'not null' => TRUE,
'default' => '',
'length' => FieldStorageConfig::NAME_MAX_LENGTH,
'description' => 'The field_name of the field that was used to add this message.',
],
'mid' => [
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'description' => 'The {message}.mid of the last message.',
],
'last_message_timestamp' => [
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'description' => 'The Unix timestamp of the last message that was posted within this entity, from {message}.changed.',
],
'last_message_name' => [
'type' => 'varchar',
'length' => 60,
'not null' => FALSE,
'description' => 'The name of the latest author to post a message on this message thread, from {message}.name.',
],
'last_message_uid' => [
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'description' => 'The user ID of the latest author to post a message on this message thread, from {message}.uid.',
],
'message_count' => [
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'description' => 'The total number of messages on this entity.',
],
],
'primary key' => ['entity_id', 'entity_type', 'field_name'],
'indexes' => [
'last_message_timestamp' => ['last_message_timestamp'],
'message_count' => ['message_count'],
'last_message_uid' => ['last_message_uid'],
],
'foreign keys' => [
'last_message_author' => [
'table' => 'users',
'columns' => [
'last_message_uid' => 'uid',
],
],
],
];
return $schema;
}
/** /**
* Implements hook_uninstall(). * Implements hook_uninstall().
* *
...@@ -16,6 +110,31 @@ function message_thread_uninstall() { ...@@ -16,6 +110,31 @@ function message_thread_uninstall() {
/** /**
* Implements hook_update_N(). * Implements hook_update_N().
*
* Add new table for statistics.
*/
function message_thread_update_8002() {
if (db_table_exists('message_thread_statistics')) {
return;
}
$schema_manager = Database::getConnection()->schema();
$schema = drupal_get_module_schema('message_thread');
$schema_manager->createTable('message_thread_statistics', $schema['message_thread_statistics']);
}
/**
* Implements hook_update_N().
*
* Turn on statistics.
*/
function message_thread_update_8003() {
\Drupal::state()->set('message.maintain_entity_statistics', TRUE);
}
/**
* Implements hook_update_N().
*
* Add new field definitions.
*/ */
function message_thread_update_8001() { function message_thread_update_8001() {
$entity_definition_update_manager = \Drupal::service('entity.definition_update_manager'); $entity_definition_update_manager = \Drupal::service('entity.definition_update_manager');
......
...@@ -29,6 +29,7 @@ task.message_thread.delete_form: ...@@ -29,6 +29,7 @@ task.message_thread.delete_form:
base_route: message_thread.threads base_route: message_thread.threads
title: Delete title: Delete
## Provide dynamic local tasks. task.message_thread.admin:
#message_thread.dynamic_tasks: title: Message Threads
# deriver: 'Drupal\message_thread\Plugin\Derivative\DynamicLocalTasks' route_name: message_thread.message_threads
base_route: node.content_overview
...@@ -25,9 +25,10 @@ use Drupal\Core\Access\AccessResultForbidden; ...@@ -25,9 +25,10 @@ use Drupal\Core\Access\AccessResultForbidden;
/** /**
* Implements hook_installed(). * Implements hook_installed().
*
* Flush cache after install to ensure that all routes are read.
*/ */
function message_thread_modules_installed() { function message_thread_modules_installed() {
// Flush cache after install to ensure that all routes are read.
drupal_flush_all_caches(); drupal_flush_all_caches();
} }
...@@ -40,8 +41,7 @@ function message_thread_help($route_name, RouteMatchInterface $arg) { ...@@ -40,8 +41,7 @@ function message_thread_help($route_name, RouteMatchInterface $arg) {
$output = file_get_contents(drupal_get_path('module', 'message_thread') . '/README.md'); $output = file_get_contents(drupal_get_path('module', 'message_thread') . '/README.md');
return \Drupal::moduleHandler()->moduleExists('markdown') ? Xss::filterAdmin(\Drupal::moduleHandler()->invoke('markdown', 'filter', [ return \Drupal::moduleHandler()->moduleExists('markdown') ? Xss::filterAdmin(\Drupal::moduleHandler()->invoke('markdown', 'filter', [
'process', 0, -1, $output, 'process', 0, -1, $output,
] ])) : '<h3>Message Private README</h3><pre>' . Html::escape($output) . '</pre>';
)) : '<h3>Message Private README</h3><pre>' . Html::escape($output) . '</pre>';
} }
} }
...@@ -54,10 +54,10 @@ function message_thread_form_alter(array &$form, FormStateInterface $form_state, ...@@ -54,10 +54,10 @@ function message_thread_form_alter(array &$form, FormStateInterface $form_state,
return; return;
} }
// When a message is created we need to ensure that the participants // When a message is created we need to ensure
// are included. // that the participants are included.
// This is best done in the validation hook // This is best done in the validation hook to ensure participants
// to ensure participants are not missed from submit functions. // are not missed from submit functions.
$thread_templates = \Drupal::entityTypeManager()->getListBuilder('message_thread_template')->load(); $thread_templates = \Drupal::entityTypeManager()->getListBuilder('message_thread_template')->load();
foreach ($thread_templates as $name => $template) { foreach ($thread_templates as $name => $template) {
$settings = $template->getSettings(); $settings = $template->getSettings();
...@@ -117,7 +117,7 @@ function message_thread_form_alter(array &$form, FormStateInterface $form_state, ...@@ -117,7 +117,7 @@ function message_thread_form_alter(array &$form, FormStateInterface $form_state,
} }
/** /**
* Submit handler. * Submit message callback.
*/ */
function message_thread_submit_message(array &$form, FormStateInterface $form_state) { function message_thread_submit_message(array &$form, FormStateInterface $form_state) {
$thread_id = $form_state->getValue('message_thread'); $thread_id = $form_state->getValue('message_thread');
...@@ -131,6 +131,10 @@ function message_thread_submit_message(array &$form, FormStateInterface $form_st ...@@ -131,6 +131,10 @@ function message_thread_submit_message(array &$form, FormStateInterface $form_st
] ]
)->execute(); )->execute();
// Update statistics.
$entity = $form_state->getFormObject()->getEntity();
\Drupal::service('message.statistics')->update($entity);
// Redirect to the thread not the message. // Redirect to the thread not the message.
$params = [ $params = [
'message_thread' => $thread_id, 'message_thread' => $thread_id,
...@@ -231,8 +235,8 @@ function message_thread_preprocess_links(&$variables) { ...@@ -231,8 +235,8 @@ function message_thread_preprocess_links(&$variables) {
if (substr($route_name, 0, 15) == 'entity.message.') { if (substr($route_name, 0, 15) == 'entity.message.') {
// $message_access_manager = // $message_access_manager =
// new MessagePrivateAccessControlHandler($entity->getEntityType());. // new MessagePrivateAccessControlHandler($entity->getEntityType());.
// $access = $message_access_manager->checkAccess( // $access =
// $entity, $operation, $account);. // $message_access_manager->checkAccess($entity, $operation, $account);.
$access = message_private_message_access($entity, $operation, $account); $access = message_private_message_access($entity, $operation, $account);
// Disable link if user does not have access. // Disable link if user does not have access.
if ($access instanceof AccessResultForbidden) { if ($access instanceof AccessResultForbidden) {
...@@ -275,8 +279,8 @@ function message_thread_theme() { ...@@ -275,8 +279,8 @@ function message_thread_theme() {
* Default template: message_thread.html.twig. * Default template: message_thread.html.twig.
* *
* Most themes use their own copy of message_thread.html.twig. * Most themes use their own copy of message_thread.html.twig.
* The default is located * The default is located inside
* inside "/core/modules/message_thread/templates/message_thread.html.twig". * "/core/modules/message_thread/templates/message_thread.html.twig".
* Look in there for the full list of variables. * Look in there for the full list of variables.
* *
* @param array $variables * @param array $variables
...@@ -380,10 +384,10 @@ function message_thread_entity_view_alter(array &$build, EntityInterface $entity ...@@ -380,10 +384,10 @@ function message_thread_entity_view_alter(array &$build, EntityInterface $entity
* Helper function to display the messages as a View. * Helper function to display the messages as a View.
* *
* @param array $settings * @param array $settings
* Template settings. * Message thread settings.
* *
* @return array|bool|false * @return array|bool|null
* Display inof or false. * The view or False.
*/ */
function message_thread_get_messages_display(array $settings, $entity) { function message_thread_get_messages_display(array $settings, $entity) {
...@@ -446,7 +450,6 @@ function message_thread_reply_link($entity, $component) { ...@@ -446,7 +450,6 @@ function message_thread_reply_link($entity, $component) {
function message_thread_reply_form($entity, $component) { function message_thread_reply_form($entity, $component) {
$user = \Drupal::currentUser(); $user = \Drupal::currentUser();
$account = User::load($user->id()); $account = User::load($user->id());
$ref = User::load(1);
$message = \Drupal::entityTypeManager()->getStorage('message')->create([ $message = \Drupal::entityTypeManager()->getStorage('message')->create([
'template' => 'private_message', 'template' => 'private_message',
'uid' => $account->id(), 'uid' => $account->id(),
...@@ -540,7 +543,7 @@ function message_thread_local_tasks_alter(&$local_tasks) { ...@@ -540,7 +543,7 @@ function message_thread_local_tasks_alter(&$local_tasks) {
* Views Plugin access callback. * Views Plugin access callback.
* *
* @return \Drupal\Core\Access\AccessResult * @return \Drupal\Core\Access\AccessResult
* Access result object. * Whether or not to allow access.
*/ */
function message_thread_tab_access_check() { function message_thread_tab_access_check() {
$account = \Drupal::currentUser(); $account = \Drupal::currentUser();
...@@ -589,10 +592,9 @@ function message_thread_get_messages($thread_id) { ...@@ -589,10 +592,9 @@ function message_thread_get_messages($thread_id) {
/** /**
* Implements hook_ENTITY_TYPE_view_alter() for message thread entities. * Implements hook_ENTITY_TYPE_view_alter() for message thread entities.
*/ */
function message_thread_message_thread_view_alter(array &$build, function message_history_message_thread_view_alter(array &$build,
EntityInterface $message_thread, EntityInterface $message_thread,
EntityViewDisplayInterface $display) { EntityViewDisplayInterface $display) {
// Update the message_history table, // Update the message_history table,
// stating that this user viewed all messages in this thread. // stating that this user viewed all messages in this thread.
if (!\Drupal::service('module_handler')->moduleExists('message_history')) { if (!\Drupal::service('module_handler')->moduleExists('message_history')) {
...@@ -633,3 +635,34 @@ function message_thread_theme_suggestions_message_thread(array $variables) { ...@@ -633,3 +635,34 @@ function message_thread_theme_suggestions_message_thread(array $variables) {
return $suggestions; return $suggestions;
} }
/**
* Implements hook_entity_insert().
*/
function message_thread_entity_insert(EntityInterface $entity) {
// On insert of a message thread create the statistics entry.
switch ($entity->getEntityType()->id()) {
case 'message_thread':
if (!\Drupal::state()->get('message.maintain_entity_statistics')) {
return;
}
\Drupal::service('message.statistics')->create($entity);
break;
}
}
/**
* Implements hook_entity_predelete().
*/
function message_thread_entity_predelete(EntityInterface $entity) {
switch ($entity->getEntityTypeId()) {
case 'message_thread':
\Drupal::service('message.statistics')->delete($entity);
break;
case 'message':
\Drupal::service('message.statistics')->update($entity);
break;
}
}
...@@ -128,5 +128,12 @@ message_thread.reply: ...@@ -128,5 +128,12 @@ message_thread.reply:
message_template: message_template:
with_config_overrides: FALSE with_config_overrides: FALSE
message_thread.multiple_delete_confirm:
path: '/admin/content/message-thread/delete'
defaults:
_form: '\Drupal\message_thread\Form\DeleteMultiple'
requirements:
_permission: 'administer message threads'
route_callbacks: route_callbacks:
- 'Drupal\message_thread\Routing\MessageThreadRoutes::routes' - 'Drupal\message_thread\Routing\MessageThreadRoutes::routes'
...@@ -3,3 +3,9 @@ services: ...@@ -3,3 +3,9 @@ services:
class: Drupal\message_thread\Plugin\Breadcrumbs\MessageThreadBreadcrumbs class: Drupal\message_thread\Plugin\Breadcrumbs\MessageThreadBreadcrumbs
tags: tags:
- { name: breadcrumb_builder, priority: 1020 } - { name: breadcrumb_builder, priority: 1020 }
message.statistics:
class: Drupal\message_thread\MessageStatistics
arguments: ['@database', '@current_user', '@entity.manager', '@state']
tags:
- { name: backend_overridable }
...@@ -6,9 +6,7 @@ use Drupal\Core\Url; ...@@ -6,9 +6,7 @@ use Drupal\Core\Url;
use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Controller\ControllerBase;
use Drupal\message_thread\Entity\MessageThread; use Drupal\message_thread\Entity\MessageThread;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\message_thread\MessageThreadTemplateInterface;
use Drupal\message\Entity\Message; use Drupal\message\Entity\Message;
use Drupal\message\MessageTemplateInterface;
use Drupal\Component\Utility\Xss; use Drupal\Component\Utility\Xss;
use Drupal\views\Views; use Drupal\views\Views;
...@@ -77,15 +75,15 @@ class MessageThreadController extends ControllerBase implements ContainerInjecti ...@@ -77,15 +75,15 @@ class MessageThreadController extends ControllerBase implements ContainerInjecti
} }
/** /**
* Form output to add a new message entity of message_thread_template. * Generates form output for adding a new message_thread_template.
* *
* @param \Drupal\message\MessageThreadTemplateInterface $message_thread_template * @param string $message_thread_template
* The message template object. * The message template name.
* *
* @return array * @return array
* An array as expected by drupal_render(). * An array as expected by drupal_render().
*/ */
public function add(MessageThreadTemplateInterface $message_thread_template) { public function add($message_thread_template) {
$message_thread = MessageThread::create(['template' => $message_thread_template]); $message_thread = MessageThread::create(['template' => $message_thread_template]);
$form = $this->entityFormBuilder()->getForm($message_thread); $form = $this->entityFormBuilder()->getForm($message_thread);
...@@ -93,9 +91,17 @@ class MessageThreadController extends ControllerBase implements ContainerInjecti ...@@ -93,9 +91,17 @@ class MessageThreadController extends ControllerBase implements ContainerInjecti
} }
/** /**
* Form output to add a message entity of message_template inside a thread. * Generates form output for adding a new message entity inside a thread.
*
* @param string $message_template
* The message template name.
* @param string $message_thread
* The message thread id.
*
* @return array
* An array as expected by drupal_render().
*/ */
public function reply(MessageTemplateInterface $message_template, $message_thread) { public function reply($message_template, $message_thread) {
$message = Message::create(['template' => $message_template]); $message = Message::create(['template' => $message_template]);
$form = $this->entityFormBuilder()->getForm($message); $form = $this->entityFormBuilder()->getForm($message);
...@@ -134,7 +140,7 @@ class MessageThreadController extends ControllerBase implements ContainerInjecti ...@@ -134,7 +140,7 @@ class MessageThreadController extends ControllerBase implements ContainerInjecti
* Generates output of all threads belonging to the current user. * Generates output of all threads belonging to the current user.
* *
* @return array * @return array
* A render array for a list of the messages; * A render array for a list of the messages.
*/ */
public function inBox() { public function inBox() {
// Get threads that the current user belongs to. // Get threads that the current user belongs to.
...@@ -167,7 +173,6 @@ class MessageThreadController extends ControllerBase implements ContainerInjecti ...@@ -167,7 +173,6 @@ class MessageThreadController extends ControllerBase implements ContainerInjecti
$view->preExecute(); $view->preExecute();
$view->execute($display_id); $view->execute($display_id);
$message_threads = $view->buildRenderable($display_id); $message_threads = $view->buildRenderable($display_id);
// Return build array. // Return build array.
...@@ -177,7 +182,8 @@ class MessageThreadController extends ControllerBase implements ContainerInjecti ...@@ -177,7 +182,8 @@ class MessageThreadController extends ControllerBase implements ContainerInjecti
else { else {
$url = Url::fromRoute('message.template_add'); $url = Url::fromRoute('message.template_add');
return [ return [
'#markup' => 'You have no messages in your inbox. Try sending a message to someone <a href="/' . $url->getInternalPath() . '">sending a message to someone</a>.', '#markup' => 'You have no messages in your inbox. Try sending a message to someone <a href="/' .
$url->getInternalPath() . '">sending a message to someone</a>.',
]; ];
} }
} }
...@@ -185,18 +191,21 @@ class MessageThreadController extends ControllerBase implements ContainerInjecti ...@@ -185,18 +191,21 @@ class MessageThreadController extends ControllerBase implements ContainerInjecti
/** /**
* Message thread title. * Message thread title.
* *
* @param Drupal\message_thread\Entity\MessageThread|null $message_thread * @param \Drupal\message_thread\Entity\MessageThread $message_thread
* The message thread object. * Message thread object.
* *
* @return array|string * @return array|string
* The title. * Markup.
*/ */
public function messageThreadTitle(MessageThread $message_thread = NULL) { public function messageThreadTitle(MessageThread $message_thread = NULL) {
return $message_thread ? ['#markup' => $message_thread->get('field_thread_title')->getValue()[0]['value'], '#allowed_tags' => Xss::getHtmlTagList()] : ''; return $message_thread ? ['#markup' => $message_thread->get('field_thread_title')->getValue()[0]['value'], '#allowed_tags' => Xss::getHtmlTagList()] : '';
} }
/** /**
* Display sent message threads using a view. * Generates form output for adding a new message entity of message_template.
*
* @return array
* An array as expected by drupal_render().
*/ */
public function sent() { public function sent() {
$view_name = 'conversations'; $view_name = 'conversations';
......
<?php
namespace Drupal\message_thread\Form;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\message_thread\Entity\MessageThread;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a message thread deletion confirmation form.
*/
class DeleteMultiple extends ConfirmFormBase {
/**
* The array of message threads to delete.
*
* @var array
*/
protected $messageThreads = [];
/**
* The tempstore factory.
*
* @var \Drupal\Core\TempStore\PrivateTempStoreFactory
*/
protected $tempStoreFactory;
/**
* The message storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $manager;
/**
* Constructs a DeleteMultiple form object.
*
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $temp_store_factory
* The tempstore factory.
* @param \Drupal\Core\Entity\EntityManagerInterface $manager
* The entity manager.
*/
public function __construct(PrivateTempStoreFactory $temp_store_factory, EntityManagerInterface $manager) {
$this->tempStoreFactory = $temp_store_factory;
$this->storage = $manager->getStorage('message_thread');
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('tempstore.private'),
$container->get('entity.manager')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'message_thread_multiple_delete_confirm';
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
return \Drupal::translation()->formatPlural(count($this->messageThreads), 'Are you sure you want to delete this item?', 'Are you sure you want to delete these items?');
}
/**
* {@inheritdoc}
*/
public function getCancelRoute() {
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return t('Delete');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$this->messageThreads = $this->tempStoreFactory->get('message_thread_multiple_delete_confirm')->get(\Drupal::currentUser()->id());
if (empty($this->messageThreads)) {
return new RedirectResponse($this->getCancelUrl()->setAbsolute()->toString());
}
$form['message_threads'] = [
'#theme' => 'item_list',
'#items' => array_map(function (MessageThread $message_thread) {
$params = [
'@id' => $message_thread->id(),
'@template' => $message_thread->getTemplate()->label(),
];
return t('Delete message thread ID @id for template @template', $params);
}, $this->messageThreads),
];
$form = parent::buildForm($form, $form_state);
$form['actions']['cancel']['#href'] = $this->getCancelRoute();
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
if ($form_state->getValue('confirm') && !empty($this->messageThreads)) {
$this->storage->delete($this->messageThreads);
$this->tempStoreFactory->get('message_thread_multiple_delete_confirm')->delete(\Drupal::currentUser()->id());
$count = count($this->messageThreads);
$this->logger('message_thread')->notice('Deleted @count message threads.', ['@count' => $count]);
drupal_set_message(\Drupal::translation()->formatPlural($count, 'Deleted 1 message thread.', 'Deleted @count message threads.'));
}