581 lines
19 KiB
PHP
581 lines
19 KiB
PHP
<?php
|
|
/**
|
|
* ---------------------------------------------------------------------
|
|
* GLPI - Gestionnaire Libre de Parc Informatique
|
|
* Copyright (C) 2015-2020 Teclib' and contributors.
|
|
*
|
|
* http://glpi-project.org
|
|
*
|
|
* based on GLPI - Gestionnaire Libre de Parc Informatique
|
|
* Copyright (C) 2003-2014 by the INDEPNET Development Team.
|
|
*
|
|
* ---------------------------------------------------------------------
|
|
*
|
|
* LICENSE
|
|
*
|
|
* This file is part of GLPI.
|
|
*
|
|
* GLPI is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* GLPI is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GLPI. If not, see <http://www.gnu.org/licenses/>.
|
|
* ---------------------------------------------------------------------
|
|
*/
|
|
|
|
if (!defined('GLPI_ROOT')) {
|
|
die("Sorry. You can't access this file directly");
|
|
}
|
|
|
|
/**
|
|
* NotificationTemplate Class
|
|
**/
|
|
class NotificationTemplate extends CommonDBTM {
|
|
|
|
// From CommonDBTM
|
|
public $dohistory = true;
|
|
|
|
//Signature to add to the template
|
|
public $signature = '';
|
|
|
|
//Store templates for each language
|
|
public $templates_by_languages = [];
|
|
|
|
static $rightname = 'config';
|
|
|
|
|
|
|
|
static function getTypeName($nb = 0) {
|
|
return _n('Notification template', 'Notification templates', $nb);
|
|
}
|
|
|
|
|
|
static function canCreate() {
|
|
return static::canUpdate();
|
|
}
|
|
|
|
|
|
/**
|
|
* @since 0.85
|
|
**/
|
|
static function canPurge() {
|
|
return static::canUpdate();
|
|
}
|
|
|
|
|
|
function defineTabs($options = []) {
|
|
|
|
$ong = [];
|
|
$this->addDefaultFormTab($ong);
|
|
$this->addStandardTab('NotificationTemplateTranslation', $ong, $options);
|
|
$this->addStandardTab('Notification_NotificationTemplate', $ong, $options);
|
|
$this->addStandardTab('Log', $ong, $options);
|
|
|
|
return $ong;
|
|
}
|
|
|
|
|
|
/**
|
|
* Reset already computed templates
|
|
**/
|
|
function resetComputedTemplates() {
|
|
$this->templates_by_languages = [];
|
|
}
|
|
|
|
|
|
function showForm($ID, $options = []) {
|
|
global $CFG_GLPI;
|
|
|
|
if (!Config::canUpdate()) {
|
|
return false;
|
|
}
|
|
|
|
$spotted = false;
|
|
|
|
if (empty($ID)) {
|
|
if ($this->getEmpty()) {
|
|
$spotted = true;
|
|
}
|
|
|
|
} else {
|
|
if ($this->getFromDB($ID)) {
|
|
$spotted = true;
|
|
}
|
|
}
|
|
|
|
$this->showFormHeader($options);
|
|
|
|
echo "<tr class='tab_bg_1'><td>" . __('Name') . "</td>";
|
|
echo "<td colspan='3'>";
|
|
Html::autocompletionTextField($this, "name");
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>" . _n('Type', 'Types', 1) . "</td><td colspan='3'>";
|
|
Dropdown::showItemTypes('itemtype', $CFG_GLPI["notificationtemplates_types"],
|
|
['value' => ($this->fields['itemtype']
|
|
?$this->fields['itemtype'] :'Ticket')]);
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>".__('Comments')."</td>";
|
|
echo "<td colspan='3'>";
|
|
echo "<textarea cols='60' rows='5' name='comment' >".$this->fields["comment"]."</textarea>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>".__('CSS')."</td>";
|
|
echo "<td colspan='3'>";
|
|
echo "<textarea cols='60' rows='5' name='css' >".$this->fields["css"]."</textarea></td></tr>";
|
|
|
|
$this->showFormButtons($options);
|
|
return true;
|
|
}
|
|
|
|
|
|
function rawSearchOptions() {
|
|
$tab = [];
|
|
|
|
$tab[] = [
|
|
'id' => 'common',
|
|
'name' => __('Characteristics')
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '1',
|
|
'table' => $this->getTable(),
|
|
'field' => 'name',
|
|
'name' => __('Name'),
|
|
'datatype' => 'itemlink',
|
|
'massiveaction' => false,
|
|
'autocomplete' => true,
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '4',
|
|
'table' => $this->getTable(),
|
|
'field' => 'itemtype',
|
|
'name' => _n('Type', 'Types', 1),
|
|
'datatype' => 'itemtypename',
|
|
'itemtype_list' => 'notificationtemplates_types',
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '16',
|
|
'table' => $this->getTable(),
|
|
'field' => 'comment',
|
|
'name' => __('Comments'),
|
|
'datatype' => 'text'
|
|
];
|
|
|
|
return $tab;
|
|
}
|
|
|
|
|
|
/**
|
|
* Display templates available for an itemtype
|
|
*
|
|
* @param $name the dropdown name
|
|
* @param $itemtype display templates for this itemtype only
|
|
* @param $value the dropdown's default value (0 by default)
|
|
**/
|
|
static function dropdownTemplates($name, $itemtype, $value = 0) {
|
|
self::dropdown([
|
|
'name' => $name,
|
|
'value' => $value,
|
|
'comment' => 1,
|
|
'condition' => ['itemtype' => addslashes($itemtype)]
|
|
]);
|
|
}
|
|
|
|
|
|
/**
|
|
* @param $options
|
|
**/
|
|
function getAdditionnalProcessOption($options) {
|
|
|
|
//Additionnal option can be given for template processing
|
|
//For the moment, only option to see private tasks & followups is available
|
|
if (!empty($options)
|
|
&& isset($options['sendprivate'])) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param $target NotificationTarget object
|
|
* @param $user_infos array
|
|
* @param $event
|
|
* @param $options array
|
|
*
|
|
* @return id of the template in templates_by_languages / false if computation failed
|
|
**/
|
|
function getTemplateByLanguage(NotificationTarget $target, $user_infos = [],
|
|
$event = '', $options = []) {
|
|
|
|
$lang = [];
|
|
$language = $user_infos['language'];
|
|
|
|
if (isset($user_infos['additionnaloption'])) {
|
|
$additionnaloption = $user_infos['additionnaloption'];
|
|
} else {
|
|
$additionnaloption = [];
|
|
}
|
|
|
|
$tid = $language;
|
|
$tid .= serialize($additionnaloption);
|
|
|
|
$tid = sha1($tid);
|
|
|
|
if (!isset($this->templates_by_languages[$tid])) {
|
|
$generated_by = __('Automatically generated by GLPI');
|
|
|
|
//Switch to the desired language
|
|
$bak_dropdowntranslations = (isset($_SESSION['glpi_dropdowntranslations']) ? $_SESSION['glpi_dropdowntranslations'] : null);
|
|
$_SESSION['glpi_dropdowntranslations'] = DropdownTranslation::getAvailableTranslations($language);
|
|
Session::loadLanguage($language);
|
|
$bak_language = $_SESSION["glpilanguage"];
|
|
$_SESSION["glpilanguage"] = $language;
|
|
|
|
//If event is raised by a plugin, load it in order to get the language file available
|
|
if ($plug = isPluginItemType(get_class($target->obj))) {
|
|
Plugin::loadLang(strtolower($plug['plugin']), $language);
|
|
}
|
|
|
|
//Get template's language data for in this language
|
|
$options['additionnaloption'] = $additionnaloption;
|
|
$data = &$target->getForTemplate($event, $options);
|
|
|
|
$footer_string = Html::entity_decode_deep(__('Automatically generated by GLPI'));
|
|
|
|
$add_header = Html::entity_decode_deep($target->getContentHeader());
|
|
$add_footer = Html::entity_decode_deep($target->getContentFooter());
|
|
|
|
if ($template_datas = $this->getByLanguage($language)) {
|
|
//Template processing
|
|
|
|
// Decode html chars to have clean text
|
|
$template_datas['content_text']
|
|
= Html::entity_decode_deep($template_datas['content_text']);
|
|
$data = Html::entity_decode_deep($data);
|
|
|
|
$template_datas['subject'] = Html::entity_decode_deep($template_datas['subject']);
|
|
$this->signature = Html::entity_decode_deep($this->signature);
|
|
|
|
$lang['subject'] = $target->getSubjectPrefix($event) .
|
|
self::process($template_datas['subject'], $data);
|
|
$lang['content_html'] = '';
|
|
|
|
//If no html content, then send only in text
|
|
if (!empty($template_datas['content_html'])) {
|
|
$signature_html = Html::entities_deep($this->signature);
|
|
$signature_html = Html::nl2br_deep($signature_html);
|
|
|
|
$template_datas['content_html'] = self::process(
|
|
$template_datas['content_html'],
|
|
self::getDataForHtml($target, $data)
|
|
);
|
|
|
|
$lang['content_html'] =
|
|
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
|
|
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>".
|
|
"<html>
|
|
<head>
|
|
<META http-equiv='Content-Type' content='text/html; charset=utf-8'>
|
|
<title>".Html::entities_deep($lang['subject'])."</title>
|
|
<style type='text/css'>
|
|
".$this->fields['css']."
|
|
</style>
|
|
</head>
|
|
<body>\n".(!empty($add_header)?$add_header."\n<br><br>":'').
|
|
$template_datas['content_html'].
|
|
"<br><br>-- \n<br>".$signature_html.
|
|
"<br>$footer_string".
|
|
"<br><br>\n".(!empty($add_footer)?$add_footer."\n<br><br>":'').
|
|
"\n</body></html>";
|
|
}
|
|
|
|
$lang['content_text']
|
|
= (!empty($add_header)?$add_header."\n\n":''). Html::clean(self::process($template_datas['content_text'],
|
|
$data)."\n\n-- \n".$this->signature.
|
|
"\n".Html::entity_decode_deep($generated_by))."\n\n".$add_footer;
|
|
$this->templates_by_languages[$tid] = $lang;
|
|
|
|
// Restore default language
|
|
$_SESSION["glpilanguage"] = $bak_language;
|
|
Session::loadLanguage();
|
|
if ($bak_dropdowntranslations !== null) {
|
|
$_SESSION['glpi_dropdowntranslations'] = $bak_dropdowntranslations;
|
|
} else {
|
|
unset($_SESSION['glpi_dropdowntranslations']);
|
|
}
|
|
if ($plug = isPluginItemType(get_class($target->obj))) {
|
|
Plugin::loadLang(strtolower($plug['plugin']));
|
|
}
|
|
}
|
|
}
|
|
if (isset($this->templates_by_languages[$tid])) {
|
|
return $tid;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param $string
|
|
* @param $data
|
|
**/
|
|
static function process($string, $data) {
|
|
|
|
$offset = $new_offset = 0;
|
|
//Template processed
|
|
$output = "";
|
|
|
|
$cleandata = [];
|
|
// clean data for strtr
|
|
foreach ($data as $field => $value) {
|
|
if (!is_array($value)) {
|
|
$cleandata[$field] = $value;
|
|
}
|
|
}
|
|
|
|
//Remove all
|
|
$string = Toolbox::unclean_cross_side_scripting_deep($string);
|
|
|
|
//First of all process the FOREACH tag
|
|
if (preg_match_all("/##FOREACH[ ]?(FIRST|LAST)?[ ]?([0-9]*)?[ ]?([a-z-0-9\._]*)##/i",
|
|
$string, $out)) {
|
|
|
|
foreach ($out[3] as $id => $tag_infos) {
|
|
$regex = "/".$out[0][$id]."(.*)##ENDFOREACH".$tag_infos."##/Uis";
|
|
|
|
if (preg_match($regex, $string, $tag_out)
|
|
&& isset($data[$tag_infos])
|
|
&& is_array($data[$tag_infos])) {
|
|
|
|
$data_lang_foreach = $cleandata;
|
|
unset($data_lang_foreach[$tag_infos]);
|
|
|
|
//Manage FIRST & LAST statement
|
|
$foreachvalues = $data[$tag_infos];
|
|
if (!empty($foreachvalues)) {
|
|
if (isset($out[1][$id]) && ($out[1][$id] != '')) {
|
|
|
|
if ($out[1][$id] == 'FIRST') {
|
|
$foreachvalues = array_reverse($foreachvalues);
|
|
}
|
|
|
|
if (isset($out[2][$id]) && $out[2][$id]) {
|
|
$foreachvalues = array_slice($foreachvalues, 0, $out[2][$id]);
|
|
} else {
|
|
$foreachvalues = array_slice($foreachvalues, 0, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
$output_foreach_string = "";
|
|
foreach ($foreachvalues as $line) {
|
|
foreach ($line as $field => $value) {
|
|
if (!is_array($value)) {
|
|
$data_lang_foreach[$field] = $value;
|
|
}
|
|
}
|
|
$tmp = self::processIf($tag_out[1], $data_lang_foreach);
|
|
$output_foreach_string .= strtr($tmp, $data_lang_foreach);
|
|
}
|
|
$string = str_replace($tag_out[0], $output_foreach_string, $string);
|
|
|
|
} else {
|
|
$string = str_replace($tag_out, '', $string);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Now process IF statements
|
|
$string = self::processIf($string, $cleandata);
|
|
$string = strtr($string, $cleandata);
|
|
|
|
return $string;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param $string
|
|
* @param $data
|
|
**/
|
|
static function processIf($string, $data) {
|
|
|
|
if (preg_match_all("/##IF([a-z-0-9\._]*)[=]?(.*?)##/i", $string, $out)) {
|
|
foreach ($out[1] as $key => $tag_infos) {
|
|
$if_field = $tag_infos;
|
|
//Get the field tag value (if one)
|
|
$regex_if = "/##IF".$if_field."[=]?.*##(.*)##ENDIF".$if_field."##/Uis";
|
|
//Get the else tag value (if one)
|
|
$regex_else = "/##ELSE".$if_field."[=]?.*##(.*)##ENDELSE".$if_field."##/Uis";
|
|
|
|
$condition_ok = false;
|
|
|
|
if (empty($out[2][$key]) && !strlen($out[2][$key])) { // No = : check if ot empty or not null
|
|
|
|
if (isset($data['##'.$if_field.'##'])
|
|
&& $data['##'.$if_field.'##'] != '0'
|
|
&& $data['##'.$if_field.'##'] != ''
|
|
&& $data['##'.$if_field.'##'] != ' '
|
|
&& !is_null($data['##'.$if_field.'##'])) {
|
|
|
|
$condition_ok = true;
|
|
|
|
}
|
|
} else { // check exact match
|
|
if (isset($data['##'.$if_field.'##'])) {
|
|
// Data value: the value for the field in the database
|
|
$data_value = Html::entity_decode_deep($data['##'.$if_field.'##']);
|
|
|
|
// Condition value: the expected value needed to validate the condition
|
|
$condition_value = Html::entity_decode_deep($out[2][$key]);
|
|
|
|
// Special case for data returned by Dropdown::getYesNo, we
|
|
// need to use the localized value in the comparison
|
|
$to_translate = ["Yes", "No"];
|
|
if (in_array($condition_value, $to_translate)) {
|
|
$condition_value = __($condition_value);
|
|
}
|
|
|
|
// Compare data value and condition value
|
|
$condition_ok = $condition_value == $data_value;
|
|
}
|
|
}
|
|
|
|
// Force only one replacement to permit multiple use of the same condition
|
|
if ($condition_ok) { // Do IF
|
|
$string = preg_replace($regex_if, "\\1", $string, 1);
|
|
$string = preg_replace($regex_else, "", $string, 1);
|
|
|
|
} else { // Do ELSE
|
|
$string = preg_replace($regex_if, "", $string, 1);
|
|
$string = preg_replace($regex_else, "\\1", $string, 1);
|
|
}
|
|
}
|
|
}
|
|
return $string;
|
|
}
|
|
|
|
/**
|
|
* Convert notification data to HTML format.
|
|
*
|
|
* @param NotificationTarget $target
|
|
* @param array $data
|
|
* @return array
|
|
*/
|
|
private static function getDataForHtml(NotificationTarget $target, array $data) {
|
|
$dataForHtml = [];
|
|
|
|
foreach ($data as $tag => $value) {
|
|
if (is_array($value)) {
|
|
$dataForHtml[$tag] = self::getDataForHtml($target, $value);
|
|
} else if (!in_array($tag, $target->html_tags)) {
|
|
$dataForHtml[$tag] = Html::nl2br_deep(Html::entities_deep($value));
|
|
} else {
|
|
$dataForHtml[$tag] = $value;
|
|
}
|
|
}
|
|
|
|
return $dataForHtml;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param $signature
|
|
**/
|
|
function setSignature($signature) {
|
|
$this->signature = $signature;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param $language
|
|
**/
|
|
function getByLanguage($language) {
|
|
global $DB;
|
|
|
|
$iterator = $DB->request([
|
|
'FROM' => 'glpi_notificationtemplatetranslations',
|
|
'WHERE' => [
|
|
'notificationtemplates_id' => $this->getField('id'),
|
|
'language' => [$language, '']
|
|
],
|
|
'ORDER' => 'language DESC',
|
|
'LIMIT' => 1
|
|
]);
|
|
if (count($iterator)) {
|
|
return $iterator->next();
|
|
}
|
|
|
|
//No template found at all!
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param NotificationTarget $target Target instance
|
|
* @param string $tid template computed id
|
|
* @param mixed $to Recipient
|
|
* @param array $user_infos Extra user infos
|
|
* @param array $options Options
|
|
*
|
|
* @return array
|
|
**/
|
|
function getDataToSend(NotificationTarget $target, $tid, $to, array $user_infos, array $options) {
|
|
|
|
$language = $user_infos['language'];
|
|
$user_name = $user_infos['username'];
|
|
|
|
$sender = $target->getSender();
|
|
$replyto = $target->getReplyTo($options);
|
|
|
|
$mailing_options['to'] = $to;
|
|
$mailing_options['toname'] = $user_name;
|
|
$mailing_options['from'] = $sender['email'];
|
|
$mailing_options['fromname'] = $sender['name'];
|
|
$mailing_options['replyto'] = $replyto['email'];
|
|
$mailing_options['replytoname'] = $replyto['name'];
|
|
$mailing_options['messageid'] = $target->getMessageID();
|
|
|
|
$template_data = $this->templates_by_languages[$tid];
|
|
$mailing_options['subject'] = $template_data['subject'];
|
|
$mailing_options['content_html'] = $template_data['content_html'];
|
|
$mailing_options['content_text'] = $template_data['content_text'];
|
|
$mailing_options['items_id'] = method_exists($target->obj, "getField")
|
|
? $target->obj->getField('id')
|
|
: 0;
|
|
if (isset($target->obj->documents)) {
|
|
$mailing_options['documents'] = $target->obj->documents;
|
|
}
|
|
|
|
return $mailing_options;
|
|
}
|
|
|
|
|
|
function cleanDBonPurge() {
|
|
|
|
$this->deleteChildrenAndRelationsFromDb(
|
|
[
|
|
Notification_NotificationTemplate::class,
|
|
NotificationTemplateTranslation::class,
|
|
]
|
|
);
|
|
|
|
// QueuedNotification does not extends CommonDBConnexity
|
|
$queued = new QueuedNotification();
|
|
$queued->deleteByCriteria(['notificationtemplates_id' => $this->fields['id']]);
|
|
}
|
|
|
|
}
|