first commit
This commit is contained in:
49
plugins/workflow/notification/forms/action.xml
Normal file
49
plugins/workflow/notification/forms/action.xml
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form>
|
||||
<fields name="options">
|
||||
<fieldset name="notification" label="COM_WORKFLOW_NOTIFICATION_FIELDSET_LABEL">
|
||||
<field
|
||||
name="notification_send_mail"
|
||||
type="radio"
|
||||
label="PLG_WORKFLOW_NOTIFICATION_SENDMAIL_LABEL"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
default="1"
|
||||
filter="boolean"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
<field
|
||||
name="notification_text"
|
||||
type="textarea"
|
||||
label="PLG_WORKFLOW_NOTIFICATION_ADDTEXT_LABEL"
|
||||
description="PLG_WORKFLOW_NOTIFICATION_ADDTEXT_DESC"
|
||||
rows="3"
|
||||
filter="safehtml"
|
||||
showon="notification_send_mail:1"
|
||||
/>
|
||||
<field
|
||||
name="notification_groups"
|
||||
type="usergrouplist"
|
||||
label="PLG_WORKFLOW_NOTIFICATION_USERGROUP_LABEL"
|
||||
description="PLG_WORKFLOW_NOTIFICATION_USERGROUP_DESC"
|
||||
multiple="true"
|
||||
layout="joomla.form.field.list-fancy-select"
|
||||
default="0"
|
||||
showon="notification_send_mail:1"
|
||||
/>
|
||||
<field
|
||||
name="notification_receivers"
|
||||
type="sql"
|
||||
label="PLG_WORKFLOW_NOTIFICATION_RECEIVERS_LABEL"
|
||||
desc="PLG_WORKFLOW_NOTIFICATION_RECEIVERS_DESC"
|
||||
query="SELECT id, name FROM #__users WHERE block=0 ORDER BY name ASC"
|
||||
key_field="id"
|
||||
value_field="name"
|
||||
multiple="true"
|
||||
layout="joomla.form.field.list-fancy-select"
|
||||
showon="notification_send_mail:1"
|
||||
/>
|
||||
</fieldset>
|
||||
</fields>
|
||||
</form>
|
||||
45
plugins/workflow/notification/notification.xml
Normal file
45
plugins/workflow/notification/notification.xml
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<extension type="plugin" group="workflow" method="upgrade">
|
||||
<name>plg_workflow_notification</name>
|
||||
<author>Joomla! Project</author>
|
||||
<creationDate>2020-05</creationDate>
|
||||
<copyright>(C) 2020 Open Source Matters, Inc.</copyright>
|
||||
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
|
||||
<authorEmail>admin@joomla.org</authorEmail>
|
||||
<authorUrl>www.joomla.org</authorUrl>
|
||||
<version>4.0.0</version>
|
||||
<description>PLG_WORKFLOW_NOTIFICATION_XML_DESCRIPTION</description>
|
||||
<namespace path="src">Joomla\Plugin\Workflow\Notification</namespace>
|
||||
<files>
|
||||
<folder>forms</folder>
|
||||
<folder plugin="notification">services</folder>
|
||||
<folder>src</folder>
|
||||
</files>
|
||||
<languages>
|
||||
<language tag="en-GB">language/en-GB/plg_workflow_notification.ini</language>
|
||||
<language tag="en-GB">language/en-GB/plg_workflow_notification.sys.ini</language>
|
||||
</languages>
|
||||
<config>
|
||||
<fields name="params">
|
||||
<fieldset name="basic">
|
||||
<field
|
||||
name="allowedlist"
|
||||
type="WorkflowComponentSections"
|
||||
label="JWORKFLOW_EXTENSION_ALLOWED_LABEL"
|
||||
description="JWORKFLOW_EXTENSION_ALLOWED_DESCRIPTION"
|
||||
multiple="multiple"
|
||||
layout="joomla.form.field.list-fancy-select"
|
||||
/>
|
||||
<field
|
||||
name="forbiddenlist"
|
||||
type="WorkflowComponentSections"
|
||||
label="JWORKFLOW_EXTENSION_FORBIDDEN_LABEL"
|
||||
description="JWORKFLOW_EXTENSION_FORBIDDEN_DESCRIPTION"
|
||||
multiple="multiple"
|
||||
layout="joomla.form.field.list-fancy-select"
|
||||
/>
|
||||
</fieldset>
|
||||
</fields>
|
||||
</config>
|
||||
|
||||
</extension>
|
||||
52
plugins/workflow/notification/services/provider.php
Normal file
52
plugins/workflow/notification/services/provider.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Plugin
|
||||
* @subpackage Workflow.notification
|
||||
*
|
||||
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
\defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Extension\PluginInterface;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\LanguageFactoryInterface;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\CMS\User\UserFactoryInterface;
|
||||
use Joomla\Database\DatabaseInterface;
|
||||
use Joomla\DI\Container;
|
||||
use Joomla\DI\ServiceProviderInterface;
|
||||
use Joomla\Event\DispatcherInterface;
|
||||
use Joomla\Plugin\Workflow\Notification\Extension\Notification;
|
||||
|
||||
return new class () implements ServiceProviderInterface {
|
||||
/**
|
||||
* Registers the service provider with a DI container.
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.4.0
|
||||
*/
|
||||
public function register(Container $container): void
|
||||
{
|
||||
$container->set(
|
||||
PluginInterface::class,
|
||||
function (Container $container) {
|
||||
$plugin = new Notification(
|
||||
$container->get(DispatcherInterface::class),
|
||||
(array) PluginHelper::getPlugin('workflow', 'notification'),
|
||||
$container->get(LanguageFactoryInterface::class)
|
||||
);
|
||||
$plugin->setApplication(Factory::getApplication());
|
||||
$plugin->setDatabase($container->get(DatabaseInterface::class));
|
||||
$plugin->setUserFactory($container->get(UserFactoryInterface::class));
|
||||
|
||||
return $plugin;
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
348
plugins/workflow/notification/src/Extension/Notification.php
Normal file
348
plugins/workflow/notification/src/Extension/Notification.php
Normal file
@ -0,0 +1,348 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Plugin
|
||||
* @subpackage Workflow.notification
|
||||
*
|
||||
* @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Plugin\Workflow\Notification\Extension;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Event\Model;
|
||||
use Joomla\CMS\Event\Workflow\WorkflowTransitionEvent;
|
||||
use Joomla\CMS\Form\Form;
|
||||
use Joomla\CMS\Language\LanguageFactoryInterface;
|
||||
use Joomla\CMS\Plugin\CMSPlugin;
|
||||
use Joomla\CMS\User\UserFactoryAwareTrait;
|
||||
use Joomla\CMS\Workflow\WorkflowPluginTrait;
|
||||
use Joomla\CMS\Workflow\WorkflowServiceInterface;
|
||||
use Joomla\Database\DatabaseAwareTrait;
|
||||
use Joomla\Event\DispatcherInterface;
|
||||
use Joomla\Event\SubscriberInterface;
|
||||
use Joomla\Utilities\ArrayHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Workflow Notification Plugin
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
final class Notification extends CMSPlugin implements SubscriberInterface
|
||||
{
|
||||
use WorkflowPluginTrait;
|
||||
use DatabaseAwareTrait;
|
||||
use UserFactoryAwareTrait;
|
||||
|
||||
/**
|
||||
* Load the language file on instantiation.
|
||||
*
|
||||
* @var boolean
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected $autoloadLanguage = true;
|
||||
|
||||
/**
|
||||
* The language factory.
|
||||
*
|
||||
* @var LanguageFactoryInterface
|
||||
* @since 4.4.0
|
||||
*/
|
||||
private $languageFactory;
|
||||
|
||||
/**
|
||||
* Returns an array of events this subscriber will listen to.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
'onContentPrepareForm' => 'onContentPrepareForm',
|
||||
'onWorkflowAfterTransition' => 'onWorkflowAfterTransition',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param DispatcherInterface $dispatcher The dispatcher
|
||||
* @param array $config An optional associative array of configuration settings
|
||||
* @param LanguageFactoryInterface $languageFactory The language factory
|
||||
*
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public function __construct(DispatcherInterface $dispatcher, array $config, LanguageFactoryInterface $languageFactory)
|
||||
{
|
||||
parent::__construct($dispatcher, $config);
|
||||
|
||||
$this->languageFactory = $languageFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* The form event.
|
||||
*
|
||||
* @param Model\PrepareFormEvent $event The event
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function onContentPrepareForm(Model\PrepareFormEvent $event)
|
||||
{
|
||||
$form = $event->getForm();
|
||||
$data = $event->getData();
|
||||
$context = $form->getName();
|
||||
|
||||
// Extend the transition form
|
||||
if ($context === 'com_workflow.transition') {
|
||||
$this->enhanceWorkflowTransitionForm($form, $data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a Notification to defined users a transition is performed
|
||||
*
|
||||
* @param WorkflowTransitionEvent $event The workflow event being processed.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function onWorkflowAfterTransition(WorkflowTransitionEvent $event)
|
||||
{
|
||||
$context = $event->getArgument('extension');
|
||||
$extensionName = $event->getArgument('extensionName');
|
||||
$transition = $event->getArgument('transition');
|
||||
$pks = $event->getArgument('pks');
|
||||
|
||||
if (!$this->isSupported($context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$component = $this->getApplication()->bootComponent($extensionName);
|
||||
|
||||
// Check if send-mail is active
|
||||
if (empty($transition->options['notification_send_mail'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ID of the items whose state has changed.
|
||||
$pks = ArrayHelper::toInteger($pks);
|
||||
|
||||
if (empty($pks)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get UserIds of Receivers
|
||||
$userIds = $this->getUsersFromGroup($transition);
|
||||
|
||||
// The active user
|
||||
$user = $this->getApplication()->getIdentity();
|
||||
|
||||
// Prepare Language for messages
|
||||
$defaultLanguage = ComponentHelper::getParams('com_languages')->get('administrator');
|
||||
$debug = $this->getApplication()->get('debug_lang');
|
||||
|
||||
$modelName = $component->getModelName($context);
|
||||
$model = $component->getMVCFactory()->createModel($modelName, $this->getApplication()->getName(), ['ignore_request' => true]);
|
||||
|
||||
// Don't send the notification to the active user
|
||||
$key = array_search($user->id, $userIds);
|
||||
|
||||
if (\is_int($key)) {
|
||||
unset($userIds[$key]);
|
||||
}
|
||||
|
||||
// Remove users with locked input box from the list of receivers
|
||||
if (!empty($userIds)) {
|
||||
$userIds = $this->removeLocked($userIds);
|
||||
}
|
||||
|
||||
// If there are no receivers, stop here
|
||||
if (empty($userIds)) {
|
||||
$this->getApplication()->enqueueMessage($this->getApplication()->getLanguage()->_('PLG_WORKFLOW_NOTIFICATION_NO_RECEIVER'), 'error');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the model for private messages
|
||||
$model_message = $this->getApplication()->bootComponent('com_messages')
|
||||
->getMVCFactory()->createModel('Message', 'Administrator');
|
||||
|
||||
// Get the title of the stage
|
||||
$model_stage = $this->getApplication()->bootComponent('com_workflow')
|
||||
->getMVCFactory()->createModel('Stage', 'Administrator');
|
||||
|
||||
$toStage = $model_stage->getItem($transition->to_stage_id)->title;
|
||||
|
||||
// Get the name of the transition
|
||||
$model_transition = $this->getApplication()->bootComponent('com_workflow')
|
||||
->getMVCFactory()->createModel('Transition', 'Administrator');
|
||||
|
||||
$transitionName = $model_transition->getItem($transition->id)->title;
|
||||
|
||||
$hasGetItem = method_exists($model, 'getItem');
|
||||
|
||||
foreach ($pks as $pk) {
|
||||
// Get the title of the item which has changed, unknown as fallback
|
||||
$title = $this->getApplication()->getLanguage()->_('PLG_WORKFLOW_NOTIFICATION_NO_TITLE');
|
||||
|
||||
if ($hasGetItem) {
|
||||
$item = $model->getItem($pk);
|
||||
$title = !empty($item->title) ? $item->title : $title;
|
||||
}
|
||||
|
||||
// Send Email to receivers
|
||||
foreach ($userIds as $user_id) {
|
||||
$receiver = $this->getUserFactory()->loadUserById($user_id);
|
||||
|
||||
if ($receiver->authorise('core.manage', 'com_messages')) {
|
||||
// Load language for messaging
|
||||
$lang = $this->languageFactory->createLanguage($user->getParam('admin_language', $defaultLanguage), $debug);
|
||||
$lang->load('plg_workflow_notification');
|
||||
$messageText = sprintf(
|
||||
$lang->_('PLG_WORKFLOW_NOTIFICATION_ON_TRANSITION_MSG'),
|
||||
$title,
|
||||
$lang->_($transitionName),
|
||||
$user->name,
|
||||
$lang->_($toStage)
|
||||
);
|
||||
|
||||
if (!empty($transition->options['notification_text'])) {
|
||||
$messageText .= '<br>' . htmlspecialchars($lang->_($transition->options['notification_text']));
|
||||
}
|
||||
|
||||
$message = [
|
||||
'id' => 0,
|
||||
'user_id_to' => $receiver->id,
|
||||
'subject' => sprintf($lang->_('PLG_WORKFLOW_NOTIFICATION_ON_TRANSITION_SUBJECT'), $title),
|
||||
'message' => $messageText,
|
||||
];
|
||||
|
||||
$model_message->save($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->getApplication()->enqueueMessage($this->getApplication()->getLanguage()->_('PLG_WORKFLOW_NOTIFICATION_SENT'), 'message');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user_ids of receivers
|
||||
*
|
||||
* @param object $data Object containing data about the transition
|
||||
*
|
||||
* @return array $userIds The receivers
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
private function getUsersFromGroup($data): array
|
||||
{
|
||||
$users = [];
|
||||
|
||||
// Single userIds
|
||||
if (!empty($data->options['notification_receivers'])) {
|
||||
$users = ArrayHelper::toInteger($data->options['notification_receivers']);
|
||||
}
|
||||
|
||||
// Usergroups
|
||||
$groups = [];
|
||||
|
||||
if (!empty($data->options['notification_groups'])) {
|
||||
$groups = ArrayHelper::toInteger($data->options['notification_groups']);
|
||||
}
|
||||
|
||||
$users2 = [];
|
||||
|
||||
if (!empty($groups)) {
|
||||
// UserIds from usergroups
|
||||
$model = $this->getApplication()->bootComponent('com_users')
|
||||
->getMVCFactory()->createModel('Users', 'Administrator', ['ignore_request' => true]);
|
||||
|
||||
$model->setState('list.select', 'id');
|
||||
$model->setState('filter.groups', $groups);
|
||||
$model->setState('filter.state', 0);
|
||||
|
||||
// Ids from usergroups
|
||||
$groupUsers = $model->getItems();
|
||||
|
||||
$users2 = ArrayHelper::getColumn($groupUsers, 'id');
|
||||
}
|
||||
|
||||
// Merge userIds from individual entries and userIDs from groups
|
||||
return array_unique(array_merge($users, $users2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current plugin should execute workflow related activities
|
||||
*
|
||||
* @param string $context
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected function isSupported($context)
|
||||
{
|
||||
if (!$this->checkAllowedAndForbiddenlist($context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$parts = explode('.', $context);
|
||||
|
||||
// We need at least the extension + view for loading the table fields
|
||||
if (\count($parts) < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$component = $this->getApplication()->bootComponent($parts[0]);
|
||||
|
||||
if (!$component instanceof WorkflowServiceInterface || !$component->isWorkflowActive($context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove receivers who have locked their message inputbox
|
||||
*
|
||||
* @param array $userIds The userIds which must be checked
|
||||
*
|
||||
* @return array users with active message input box
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
private function removeLocked(array $userIds): array
|
||||
{
|
||||
if (empty($userIds)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$db = $this->getDatabase();
|
||||
|
||||
// Check for locked inboxes would be better to have _cdf settings in the user_object or a filter in users model
|
||||
$query = $db->getQuery(true);
|
||||
|
||||
$query->select($db->quoteName('user_id'))
|
||||
->from($db->quoteName('#__messages_cfg'))
|
||||
->whereIn($db->quoteName('user_id'), $userIds)
|
||||
->where($db->quoteName('cfg_name') . ' = ' . $db->quote('locked'))
|
||||
->where($db->quoteName('cfg_value') . ' = 1');
|
||||
|
||||
$locked = $db->setQuery($query)->loadColumn();
|
||||
|
||||
return array_diff($userIds, $locked);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user