Skip to content

Commit

Permalink
Document adding notification modes
Browse files Browse the repository at this point in the history
  • Loading branch information
trasher committed Jun 29, 2017
1 parent 0cc3c52 commit 79acadc
Show file tree
Hide file tree
Showing 2 changed files with 335 additions and 0 deletions.
1 change: 1 addition & 0 deletions source/plugins/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ If you want to see more advanced examples of what it is possible to do with plug
crontasks
massiveactions
tips
notifications
334 changes: 334 additions & 0 deletions source/plugins/notifications.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,334 @@
Notification modes
------------------

Core GLPI provides two notifications modes as of today:

* email (sends email),
* ajax (send browser notifications if/when user is logged)

It is possible to extends this mechanism in order to create another mode to use. Let's take a tour... We'll take example of a plugin designed to send SMS to the users.

Required configuration
^^^^^^^^^^^^^^^^^^^^^^

A few steps are required to setup the mode. In the ``init`` method (``setup.php`` file); register the mode:

.. code-block:: php
<?php
public function plugin_init_sms {
//[...]
if ($plugin->isActivated('sms')) {
Notification_NotificationTemplate::registerMode(
Notification_NotificationTemplate::MODE_SMS, //mode itself
__('SMS', 'plugin_sms'), //label
'sms' //plugin name
);
}
//[...]
}
.. note::

GLPI will look for classes named like ``Plugin{NAME}Notification{MODE}``.

In the above example; we have used one the the `provided (but not yet used) modes from the core <https://forge.glpi-project.org/apidoc/class-Notification_NotificationTemplate.html#constants>`_. If you need a mode that does not exists, you can of course create yours!

In order to make you new notification active, you will have to declare a ``notifications_{MODE}`` variable in the main configuration: You will add it at install time, and remove it on uninstall... In the ``hook.php`` file:

.. code-block:: php
<?php
function plugin_sms_install() {
Config::setConfigurationValues('core', ['notifications_sms' => 0]);
return true;
}
function plugin_sms_uninstall() {
$config = new Config();
$config->deleteConfigurationValues('core', ['notifications_sms']);
return true;
}
Settings
^^^^^^^^

You will probably need some configuration settings to get your notifications mode to work. You can register and retrieve additional configuration values using core ``Config`` object:

.. code-block:: php
<?php
//set configuration
Config::setConfigurationValues(
'plugin:sms', //context
[ //values
'server' => '',
'port' => ''
]
);
//get configuration
$conf = Config::getConfigurationValues('plugin:sms');
//$conf will be ['server' => '', 'port' => '']
That said, we need to create a class to handle the settings, and a front file to display them. The class must be named ``PluginSmsNotificationSmsSetting`` and must be in the ``inc/notificationsmssetting.class.php``. It have to extends the `NotificationSetting <https://forge.glpi-project.org/apidoc/class-NotificationSetting.html>`_ core class :

.. code-block:: php
<?php
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
/**
* This class manages the sms notifications settings
*/
class PluginSmsNotificationSmsSetting extends NotificationSetting {
static function getTypeName($nb=0) {
return __('SMS followups configuration', 'sms');
}
public function getEnableLabel() {
return __('Enable followups via SMS', 'sms');
}
static public function getMode() {
return Notification_NotificationTemplate::MODE_SMS;
}
function showFormConfig($options = []) {
global $CFG_GLPI;
$conf = Config::getConfigurationValues('plugin:sms');
$params = [
'display' => true
];
$params = array_merge($params, $options);
$out = "<form action='".Toolbox::getItemTypeFormURL(__CLASS__)."' method='post'>";
$out .= Html::hidden('config_context', ['value' => 'plugin:sms']);
$out .= "<div>";
$out .= "<input type='hidden' name='id' value='1'>";
$out .= "<table class='tab_cadre_fixe'>";
$out .= "<tr class='tab_bg_1'><th colspan='4'>"._n('SMS notification', 'SMS notifications', Session::getPluralNumber(), 'sms')."</th></tr>";
if ($CFG_GLPI['notifications_sms']) {
//TODO
$out .= "<tr><td colspan='4'>" . __('SMS notifications are not implemented yet.', 'sms') . "</td></tr>";
} else {
$out .= "<tr><td colspan='4'>" . __('Notifications are disabled.') . " <a href='{$CFG_GLPI['root_doc']}/front/setup.notification.php'>" . _('See configuration') . "</td></tr>";
}
$options['candel'] = false;
if ($CFG_GLPI['notifications_sms']) {
$options['addbuttons'] = array('test_sms_send' => __('Send a test SMS to you', 'sms'));
}
//Ignore display parameter since showFormButtons is now ready :/ (from all but tests)
echo $out;
$this->showFormButtons($options);
}
}
The front form file, located at ``front/notificationsmssetting.form.php`` will be quite simple. It handles the display of the configuration form, update of the values, and test send (if any):

.. code-block:: php
<?php
include ('../../../inc/includes.php');
Session::checkRight("config", UPDATE);
$notificationsms = new PluginSmsNotificationSmsSetting();
if (!empty($_POST["test_sms_send"])) {
PluginSmsNotificationSms::testNotification();
Html::back();
} else if (!empty($_POST["update"])) {
$config = new Config();
$config->update($_POST);
Html::back();
}
Html::header(Notification::getTypeName(Session::getPluralNumber()), $_SERVER['PHP_SELF'], "config", "notification", "config");
$notificationsms->display(array('id' => 1));
Html::footer();
Event
^^^^^

Once the new mode has been enabled; it will try to raise core events. You will need to create an event class named ``PluginSmsNotificationEventSms`` that implements `NotificationEventInterface <https://forge.glpi-project.org/apidoc/class-NotificationEventInterface.html>`_ and extends `NotificationEventAbstract <https://forge.glpi-project.org/apidoc/class-NotificationEventAbstract.html>` in the ``inc/notificationeventsms.php``.

Methods to implement are:

* ``getTargetFieldName``: defines the name of the target field;
* ``getTargetField``: populates if needed the target field to use. For a SMS plugin, it would retrieve the phone number from users table for example;
* ``canCron``: whether notification can be called from a crontask. For the SMS plugins, it would be true. It is set to false for ajax based events; because notifications are requested from user browser;
* ``getAdminData``: as global admin is not a real user; you can define here the data used to send the notification;
* ``getEntityAdminData``: same as the above, but for entities admins rather than global admin;
* ``send``: method that will really send data.

The ``raise`` method declared in the interface is implemented in the abstract class; since it should be used as it for every mode. If you want to do extra process in the ``raise`` method, you should override the ``extraRaise`` method. This is done in the core to add signatures in the mailing for example.

.. note::

Notifications uses the ``QueueNotification`` to store its data. Each notification about to be sent will be stored in the relevant table. Rows are updated once the notification has really be send (set ``is_deleted`` to 1 and update ``sent_time``.

En example class for SMS Events would look like the following:

.. code-block:: php
<?php
class PluginSmsNotificationEventSms implements NotificationEventInterface {
static public function getTargetFieldName() {
return 'phone';
}
static public function getTargetField(&$data) {
$field = self::getTargetFieldName();
if (!isset($data[$field])
&& isset($data['users_id'])) {
// No phone set: get one for user
$user = new user();
$user->getFromDB($data['users_id']);
$phone_fields = ['mobile', 'phone', 'phone2'];
foreach ($phone_fields as $phone_field) {
if (isset($user->fields[$phone_field]) && !empty($user->fields[$phone_field])) {
$data[$field] = $user->fields[$phone_field];
break;
}
}
}
if (!isset($data[$field])) {
//Missing field; set to null
$data[$field] = null;
}
return $field;
}
static public function canCron() {
return true;
}
static public function getAdminData() {
//no phone available for global admin right now
return false;
}
static public function getEntityAdminsData($entity) {
global $DB, $CFG_GLPI;
$iterator = $DB->request([
'FROM' => 'glpi_entities',
'WHERE' => ['id' => $entity]
]);
$admins = [];
while ($row = $iterator->next()) {
$admins[] = [
'language' => $CFG_GLPI['language'],
'phone' => $row['phone_number']
];
}
return $admins;
}
static public function send(array $data) {
//data is an array of notifications to send. Process the array and send real SMS here!
throw new \RuntimeException('Not yet implemented!');
}
}
Notification
^^^^^^^^^^^^

Finally, create a ``NotificationSms`` class that implements the `NotificationInterface <https://forge.glpi-project.org/apidoc/class-NotificationInterface.html>`_ in the ``inc/notificationsms.php`` file.

Methods to implement are:

* ``check``: to validate data (checking if a mail address is well formed, ...);
* ``sendNotification``: to store raised event notification in the ``QueueNotification``;
* ``testNotification``: used from settings to send a test notification.

Again, the SMS example:

.. code-block:: php
<?php
class PluginSmsNotificationSms implements NotificationInterface {
static function check($value, $options = []) {
//Does nothing, but we could check if $value is actually what we expect as a phone number to send SMS.
return true;
}
static function testNotification() {
$instance = new self();
//send a notification to current loged in user
$instance->sendNotification([
'_itemtype' => 'NotificationSms',
'_items_id' => 1,
'_notificationtemplates_id' => 0,
'_entities_id' => 0,
'fromname' => 'TEST',
'subject' => 'Test notification',
'content_text' => "Hello, this is a test notification.",
'to' => Session::getLoginUserID()
]);
}
function sendNotification($options=array()) {
$data = array();
$data['itemtype'] = $options['_itemtype'];
$data['items_id'] = $options['_items_id'];
$data['notificationtemplates_id'] = $options['_notificationtemplates_id'];
$data['entities_id'] = $options['_entities_id'];
$data['sendername'] = $options['fromname'];
$data['name'] = $options['subject'];
$data['body_text'] = $options['content_text'];
$data['recipient'] = $options['to'];
$data['mode'] = Notification_NotificationTemplate::MODE_SMS;
$mailqueue = new QueuedMail();
if (!$mailqueue->add(Toolbox::addslashes_deep($data))) {
Session::addMessageAfterRedirect(__('Error inserting sms notification to queue', 'sms'), true, ERROR);
return false;
} else {
//TRANS to be written in logs %1$s is the to email / %2$s is the subject of the mail
Toolbox::logInFile("notification",
sprintf(__('%1$s: %2$s'),
sprintf(__('An SMS notification to %s was added to queue', 'sms'),
$options['to']),
$options['subject']."\n"));
}
return true;
}
}

0 comments on commit 79acadc

Please sign in to comment.