mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-21 16:22:20 +02:00
First version of Notify on expiration
SVN:trunk[6919]
This commit is contained in:
281
main.combodo-notify-on-expiration.php
Normal file
281
main.combodo-notify-on-expiration.php
Normal file
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
// Copyright (C) 2012-2018 Combodo SARL
|
||||
//
|
||||
// This program 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; version 3 of the License.
|
||||
//
|
||||
// This program 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 this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
/**
|
||||
* Module combodo-notify-on-expiration
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @author Vincent Dumas <vincent.dumas@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Class NotifyOnExpirationExec
|
||||
*/
|
||||
class NotifyOnExpiration implements iScheduledProcess
|
||||
{
|
||||
const MODULE_CODE = 'combodo-notify-on-expiration';
|
||||
const MODULE_SETTING_ENABLED = 'enabled';
|
||||
const MODULE_SETTING_DEBUG = 'debug';
|
||||
const MODULE_SETTING_WEEKDAYS = 'week_days';
|
||||
const MODULE_SETTING_TIME = 'time';
|
||||
|
||||
const DEFAULT_MODULE_SETTING_ENABLED = true;
|
||||
const DEFAULT_MODULE_SETTING_DEBUG = false;
|
||||
const DEFAULT_MODULE_SETTING_WEEKDAYS = 'monday, tuesday, wednesday, thursday, friday, saturday, sunday';
|
||||
const DEFAULT_MODULE_SETTING_TIME = '03:00';
|
||||
|
||||
protected $bDebug;
|
||||
|
||||
/**
|
||||
* NotifyOnExpiration constructor.
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
$this->bDebug = (bool) MetaModel::GetModuleSetting(static::MODULE_CODE, static::MODULE_SETTING_DEBUG, static::DEFAULT_MODULE_SETTING_DEBUG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives the exact time at which the process must be run next time
|
||||
*
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function GetNextOccurrence()
|
||||
{
|
||||
$bEnabled = MetaModel::GetConfig()->GetModuleSetting(static::MODULE_CODE, static::MODULE_SETTING_ENABLED, static::DEFAULT_MODULE_SETTING_ENABLED);
|
||||
if (!$bEnabled)
|
||||
{
|
||||
$oRet = new DateTime('3000-01-01');
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1st - Interpret the list of days as ordered numbers (monday = 1)
|
||||
//
|
||||
$aDays = $this->InterpretWeekDays();
|
||||
|
||||
// 2nd - Find the next active week day
|
||||
//
|
||||
$sRunTime = MetaModel::GetConfig()->GetModuleSetting(static::MODULE_CODE, static::MODULE_SETTING_TIME, static::DEFAULT_MODULE_SETTING_TIME);
|
||||
if (!preg_match('/^([01]?\d|2[0-3]):[0-5]?\d(:[0-5]?\d)?$/', $sRunTime, $aMatches))
|
||||
{
|
||||
throw new Exception(static::MODULE_CODE.": wrong format for setting 'time' (found '$sRunTime')");
|
||||
}
|
||||
$oNow = new DateTime();
|
||||
$iNextPos = false;
|
||||
for ($iDay = $oNow->format('N') ; $iDay <= 7 ; $iDay++)
|
||||
{
|
||||
$iNextPos = array_search($iDay, $aDays);
|
||||
if ($iNextPos !== false)
|
||||
{
|
||||
if (($iDay > $oNow->format('N')) || ($oNow->format('H:i') < $sRunTime))
|
||||
{
|
||||
break;
|
||||
}
|
||||
$iNextPos = false; // necessary on sundays
|
||||
}
|
||||
}
|
||||
|
||||
// 3rd - Compute the result
|
||||
//
|
||||
if ($iNextPos === false)
|
||||
{
|
||||
// Jump to the first day within the next week
|
||||
$iFirstDayOfWeek = $aDays[0];
|
||||
$iDayMove = $oNow->format('N') - $iFirstDayOfWeek;
|
||||
$oRet = clone $oNow;
|
||||
$oRet->modify('-'.$iDayMove.' days');
|
||||
$oRet->modify('+1 weeks');
|
||||
}
|
||||
else
|
||||
{
|
||||
$iNextDayOfWeek = $aDays[$iNextPos];
|
||||
$iMove = $iNextDayOfWeek - $oNow->format('N');
|
||||
$oRet = clone $oNow;
|
||||
$oRet->modify('+'.$iMove.' days');
|
||||
}
|
||||
$oRet->setTime((int)$aMatches[1], (int) $aMatches[2]);
|
||||
}
|
||||
return $oRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function Process($iTimeLimit)
|
||||
{
|
||||
$aReport = array(
|
||||
'reached_deadline' => 0,
|
||||
'triggered' => array(),
|
||||
'not_triggered' => array(),
|
||||
);
|
||||
|
||||
$oRulesSearch = DBObjectSearch::FromOQL('SELECT ExpirationRule WHERE status = "active"');
|
||||
$oRulesSet = new DBObjectSet($oRulesSearch);
|
||||
|
||||
$this->Trace('Processing '.$oRulesSet->Count().' active expiration rules...');
|
||||
|
||||
$iTotalProcessedObjectsCount = 0;
|
||||
while($oRule = $oRulesSet->Fetch())
|
||||
{
|
||||
$iRuleProcessedObjectsCount = 0;
|
||||
$this->Trace('Processing rule "'.$oRule->Get('friendlyname').'" (#'.$oRule->GetKey().')...');
|
||||
|
||||
try
|
||||
{
|
||||
// Retrieving rule's params
|
||||
$sClass = $oRule->Get('class');
|
||||
$oSearch = $oRule->GetFilter();
|
||||
$this->Trace('|- Parameters:');
|
||||
$this->Trace('| |- Class: '.$sClass);
|
||||
$this->Trace('| |- OQL scope: '.$oSearch->ToOQL(true));
|
||||
|
||||
// Prepare the Rule information to be passed to the notification
|
||||
$aRuleContext = $oRule->ToArgs('rule');
|
||||
|
||||
// Get applicable Triggers for this object class
|
||||
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oTriggerSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnExpirationRule AS t WHERE t.target_class IN ('$sClassList')"));
|
||||
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$this->Trace('|- Objects:');
|
||||
/** @var $oToTrigger DBObject */
|
||||
while ((time() < $iTimeLimit) && $oToTrigger = $oSet->Fetch())
|
||||
{
|
||||
// Catching exceptions so the process don't get stucked on this object
|
||||
try
|
||||
{
|
||||
$aReport['reached_deadline']++;
|
||||
//
|
||||
// $aContext['ruleName'] = $oRule->Get('name');
|
||||
// Combine the current object :this and :rule to be available in the notification
|
||||
$aContext = $oToTrigger->ToArgs('this');
|
||||
$aContext = array_merge($aContext, $aRuleContext);
|
||||
while ($oTrigger = $oTriggerSet->Fetch())
|
||||
{
|
||||
$oTrigger->DoActivate($aContext);
|
||||
}
|
||||
// The same set of Triggers is reused for each object returned by the Rule as they all belongs to the same class
|
||||
$oTriggerSet->Rewind();
|
||||
|
||||
$iRuleProcessedObjectsCount++;
|
||||
$iTotalProcessedObjectsCount++;
|
||||
|
||||
$aReport['triggered'][] = $oToTrigger->Get('friendlyname');
|
||||
$this->Trace('| |- [OK] '.$sClass.' #'.$oToTrigger->GetKey());
|
||||
|
||||
} // Trigger was NOT applied because of an exception, which is NOT normal
|
||||
catch (Exception $e)
|
||||
{
|
||||
$aReport['not_triggered'][] = $oToClose->Get('friendlyname');
|
||||
$this->Trace('| |- [KO] /!\\ '.$sClass.' #'.$oToTrigger->GetKey().' exception raised! Error message: '.$e->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
$this->Trace('|- Processed rule "'.$oRule->Get('friendlyname').'" (#'.$oRule->GetKey().') : '.$iRuleProcessedObjectsCount.' out of '.$oSet->Count().'.');
|
||||
|
||||
// Info to help understand why not all objects have been processed during this batch.
|
||||
if (time() >= $iTimeLimit)
|
||||
{
|
||||
$this->Trace('Stopped because time limit exceeded!');
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$this->Trace('Skipping rule as there was an exception! ('.$e->getMessage().')');
|
||||
}
|
||||
}
|
||||
|
||||
// Report
|
||||
if($aReport['reached_deadline'] === 0)
|
||||
{
|
||||
return 'No object to process';
|
||||
}
|
||||
else
|
||||
{
|
||||
$iClosedCount = count($aReport['triggered']);
|
||||
$iNotClosedCount = count($aReport['not_triggered']);
|
||||
|
||||
$sReport = $aReport['reached_deadline'] . " objects reached triggering date";
|
||||
$sReport .= " - ".$iClosedCount." were triggered";
|
||||
if($iClosedCount > 0)
|
||||
{
|
||||
$sReport .= " (".implode(", ", $aReport['triggered']).")";
|
||||
}
|
||||
$sReport .= " - ".$iNotClosedCount." were not triggered";
|
||||
if($iNotClosedCount > 0)
|
||||
{
|
||||
$sReport .= " (".implode(", ", $aReport['not_triggered']).")";
|
||||
}
|
||||
return $sReport;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpret current setting for the week days
|
||||
*
|
||||
* Note: This comes from itop-backup scheduled task.
|
||||
*
|
||||
* @returns array of int (monday = 1)
|
||||
*/
|
||||
public function InterpretWeekDays()
|
||||
{
|
||||
static $aWEEKDAYTON = array('monday' => 1, 'tuesday' => 2, 'wednesday' => 3, 'thursday' => 4, 'friday' => 5, 'saturday' => 6, 'sunday' => 7);
|
||||
$aDays = array();
|
||||
$sWeekDays = MetaModel::GetConfig()->GetModuleSetting(static::MODULE_CODE, static::MODULE_SETTING_WEEKDAYS, static::DEFAULT_MODULE_SETTING_WEEKDAYS);
|
||||
if ($sWeekDays != '')
|
||||
{
|
||||
$aWeekDaysRaw = explode(',', $sWeekDays);
|
||||
foreach ($aWeekDaysRaw as $sWeekDay)
|
||||
{
|
||||
$sWeekDay = strtolower(trim($sWeekDay));
|
||||
if (array_key_exists($sWeekDay, $aWEEKDAYTON))
|
||||
{
|
||||
$aDays[] = $aWEEKDAYTON[$sWeekDay];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(static::MODULE_CODE.": wrong format for setting 'week_days' (found '$sWeekDay')");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($aDays) == 0)
|
||||
{
|
||||
throw new Exception(static::MODULE_CODE.": missing setting 'week_days'");
|
||||
}
|
||||
$aDays = array_unique($aDays);
|
||||
sort($aDays);
|
||||
return $aDays;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a $sMessage in the CRON output.
|
||||
*
|
||||
* @param string $sMessage
|
||||
*/
|
||||
protected function Trace($sMessage)
|
||||
{
|
||||
// In the CRON output
|
||||
if ($this->bDebug)
|
||||
{
|
||||
echo $sMessage."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user