mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-26 01:43:47 +01:00
* CalDAV/Calendar: fix not working snozzing of alarms in Thunderbird
Caused by triggered alarms were - so far - immediatly deleted, now we keep them around for an other day, so TB get them in the update iCal after PUTing its X-MOZ-SNOOZE-TIME-<timestampt>
This commit is contained in:
parent
77aa6cae4e
commit
af6c2a0f25
@ -9,7 +9,6 @@
|
|||||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
* @package api
|
* @package api
|
||||||
* @access public
|
* @access public
|
||||||
* @version $Id$
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace EGroupware\Api;
|
namespace EGroupware\Api;
|
||||||
@ -30,12 +29,22 @@ class Asyncservice
|
|||||||
*/
|
*/
|
||||||
var $db;
|
var $db;
|
||||||
var $db_table = 'egw_async';
|
var $db_table = 'egw_async';
|
||||||
var $debug = 0;
|
/**
|
||||||
|
* Enable logging to PHP error_log
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
var $debug = false;
|
||||||
/**
|
/**
|
||||||
* Line in crontab set by constructor with absolute path
|
* Line in crontab set by constructor with absolute path
|
||||||
*/
|
*/
|
||||||
var $cronline = '/api/asyncservices.php default';
|
var $cronline = '/api/asyncservices.php default';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time to keep expired jobs marked as "keep", until they got finally deleted
|
||||||
|
*/
|
||||||
|
const DEFAULT_KEEP_TIME = 86400; // 1day
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* constructor of the class
|
* constructor of the class
|
||||||
*/
|
*/
|
||||||
@ -57,7 +66,7 @@ class Asyncservice
|
|||||||
/**
|
/**
|
||||||
* calculates the next run of the timer and puts that with the rest of the data in the db for later execution.
|
* calculates the next run of the timer and puts that with the rest of the data in the db for later execution.
|
||||||
*
|
*
|
||||||
* @param int/array $times unix timestamp or array('min','hour','dow','day','month','year') with execution time.
|
* @param int|array $times unix timestamp or array('min','hour','dow','day','month','year') with execution time.
|
||||||
* Repeated events are possible to shedule by setting the array only partly, eg.
|
* Repeated events are possible to shedule by setting the array only partly, eg.
|
||||||
* array('day' => 1) for first day in each month 0am or array('min' => '* /5', 'hour' => '9-17')
|
* array('day' => 1) for first day in each month 0am or array('min' => '* /5', 'hour' => '9-17')
|
||||||
* for every 5mins in the time from 9am to 5pm.
|
* for every 5mins in the time from 9am to 5pm.
|
||||||
@ -67,16 +76,28 @@ class Asyncservice
|
|||||||
* '<app>.<class>.<public function>'.
|
* '<app>.<class>.<public function>'.
|
||||||
* @param mixed $data =null This data is passed back when the method is called. If it is an array,
|
* @param mixed $data =null This data is passed back when the method is called. If it is an array,
|
||||||
* EGroupware will add the rest of the job parameters like id, next (sheduled exec time), times, ...
|
* EGroupware will add the rest of the job parameters like id, next (sheduled exec time), times, ...
|
||||||
|
* Integer value for key "keep" (in seconds) can be used to NOT delete the job automatically, after it was triggered.
|
||||||
|
* Async service with set a async_next value of 0 and key "keep_time" with timestamp on how long to keep the entry around.
|
||||||
* @param int $account_id account_id, under which the methode should be called or False for the actual user
|
* @param int $account_id account_id, under which the methode should be called or False for the actual user
|
||||||
* @param boolean $debug =false
|
* @param boolean $debug =false
|
||||||
|
* @param boolean $allow_past =false allow to set alarms in the past eg. with times===0 to not trigger it in next run
|
||||||
* @return boolean False if $id already exists, else True
|
* @return boolean False if $id already exists, else True
|
||||||
*/
|
*/
|
||||||
function set_timer($times,$id,$method,$data=null,$account_id=False,$debug=false)
|
function set_timer($times, $id, $method, $data=null, $account_id=False, $debug=false, $allow_past=false)
|
||||||
{
|
{
|
||||||
if (empty($id) || empty($method) || $this->read($id) ||
|
if (empty($id) || empty($method) || $this->read($id) ||
|
||||||
!($next = $this->next_run($times,$debug)))
|
!($next = $this->next_run($times,$debug)))
|
||||||
{
|
{
|
||||||
return False;
|
// allow to set "keep" alarms in the past ($next === false)
|
||||||
|
if ($next === false && !is_array($times) && $allow_past)
|
||||||
|
{
|
||||||
|
$next = $times;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($this->debug) error_log(__METHOD__."(".array2string($times).", '$id', '$method', ".array2string($data).", $account_id, $debug, $allow_past) returning FALSE");
|
||||||
|
return False;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ($account_id === False)
|
if ($account_id === False)
|
||||||
{
|
{
|
||||||
@ -92,6 +113,7 @@ class Asyncservice
|
|||||||
);
|
);
|
||||||
$this->write($job);
|
$this->write($job);
|
||||||
|
|
||||||
|
if ($this->debug) error_log(__METHOD__."(".array2string($times).", '$id', '$method', ".array2string($data).", $account_id, $debug, $allow_past) returning TRUE");
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +133,7 @@ class Asyncservice
|
|||||||
{
|
{
|
||||||
if ($this->debug)
|
if ($this->debug)
|
||||||
{
|
{
|
||||||
echo "<p>next_run("; print_r($times); echo ",'$debug', " . date('Y-m-d H:i', $now) . ")</p>\n";
|
error_log(__METHOD__."(".array2string($times).", '$debug', " . date('Y-m-d H:i', $now) . ")");
|
||||||
$debug = True; // enable syntax-error messages too
|
$debug = True; // enable syntax-error messages too
|
||||||
}
|
}
|
||||||
if(is_null($now)) {
|
if(is_null($now)) {
|
||||||
@ -179,7 +201,7 @@ class Asyncservice
|
|||||||
foreach($units as $u => $date_pattern)
|
foreach($units as $u => $date_pattern)
|
||||||
{
|
{
|
||||||
++$n;
|
++$n;
|
||||||
if ($this->debug) { echo "<p>n=$n, $u: isset(times[$u]="; print_r($times[$u]); echo ")=".(isset($times[$u])?'True':'False')."</p>\n"; }
|
if ($this->debug) error_log("n=$n, $u: isset(times[$u]=".array2string($times[$u]).")=".(isset($times[$u])?'True':'False'));
|
||||||
if (isset($times[$u]))
|
if (isset($times[$u]))
|
||||||
{
|
{
|
||||||
if(is_array($times[$u])) {
|
if(is_array($times[$u])) {
|
||||||
@ -197,7 +219,7 @@ class Asyncservice
|
|||||||
|
|
||||||
if (count($arr) != 2 || !is_numeric($min) || !is_numeric($max) || $min > $max)
|
if (count($arr) != 2 || !is_numeric($min) || !is_numeric($max) || $min > $max)
|
||||||
{
|
{
|
||||||
if ($debug) echo "<p>Syntax error in $u='$t', allowed is 'min-max', min <= max, min='$min', max='$max'</p>\n";
|
if ($debug) error_log("Syntax error in $u='$t', allowed is 'min-max', min <= max, min='$min', max='$max'");
|
||||||
|
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
@ -215,7 +237,7 @@ class Asyncservice
|
|||||||
if (!(is_numeric($one) && count($arr) == 1 ||
|
if (!(is_numeric($one) && count($arr) == 1 ||
|
||||||
count($arr) == 2 && is_numeric($inc)))
|
count($arr) == 2 && is_numeric($inc)))
|
||||||
{
|
{
|
||||||
if ($debug) echo "<p>Syntax error in $u='$t', allowed is a number or '{*|range}/inc', inc='$inc'</p>\n";
|
if ($debug) error_log("Syntax error in $u='$t', allowed is a number or '{*|range}/inc', inc='$inc'");
|
||||||
|
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
@ -233,7 +255,7 @@ class Asyncservice
|
|||||||
}
|
}
|
||||||
elseif (count($arr) != 2 || $min > $max)
|
elseif (count($arr) != 2 || $min > $max)
|
||||||
{
|
{
|
||||||
if ($debug) echo "<p>Syntax error in $u='$t', allowed is '{*|min-max}/inc', min='$min',max='$max', inc='$inc'</p>\n";
|
if ($debug) error_log("Syntax error in $u='$t', allowed is '{*|min-max}/inc', min='$min',max='$max', inc='$inc'");
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
for ($i = $min; $i <= $max; $i += $inc)
|
for ($i = $min; $i <= $max; $i += $inc)
|
||||||
@ -256,7 +278,7 @@ class Asyncservice
|
|||||||
$times[$u][$min_unit[$u]] = True;
|
$times[$u][$min_unit[$u]] = True;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->debug) { echo "enumerated times=<pre>"; print_r($times); echo "</pre>\n"; }
|
if ($this->debug) error_log("enumerated times=".array2string($times));
|
||||||
|
|
||||||
// now we have the times enumerated, lets find the first not expired one
|
// now we have the times enumerated, lets find the first not expired one
|
||||||
//
|
//
|
||||||
@ -274,7 +296,7 @@ class Asyncservice
|
|||||||
if (isset($found[$u]))
|
if (isset($found[$u]))
|
||||||
{
|
{
|
||||||
$future = $future || $found[$u] > $unit_now;
|
$future = $future || $found[$u] > $unit_now;
|
||||||
if ($this->debug) echo "--> already have a $u = ".$found[$u].", future='$future'<br>\n";
|
if ($this->debug) error_log("--> already have a $u = ".$found[$u].", future='$future'");
|
||||||
continue; // already set
|
continue; // already set
|
||||||
}
|
}
|
||||||
foreach(array_keys($times[$u]) as $unit_value)
|
foreach(array_keys($times[$u]) as $unit_value)
|
||||||
@ -304,18 +326,18 @@ class Asyncservice
|
|||||||
$nexts = array_keys($units);
|
$nexts = array_keys($units);
|
||||||
if (!isset($nexts[count($found)-1]))
|
if (!isset($nexts[count($found)-1]))
|
||||||
{
|
{
|
||||||
if ($this->debug) echo "<p>Nothing found, exiting !!!</p>\n";
|
if ($this->debug) error_log("Nothing found, exiting !!!");
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
$next = $nexts[count($found)-1];
|
$next = $nexts[count($found)-1];
|
||||||
$over = $found[$next];
|
$over = $found[$next];
|
||||||
unset($found[$next]);
|
unset($found[$next]);
|
||||||
if ($this->debug) echo "<p>Have to try the next $next, $u's are over for $next=$over !!!</p>\n";
|
if ($this->debug) error_log("Have to try the next $next, $u's are over for $next=$over !!!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->debug) { echo "<p>next="; print_r($found); echo "</p>\n"; }
|
if ($this->debug) error_log("next=".array2string($found));
|
||||||
|
|
||||||
return mktime($found['hour'],$found['min'],0,$found['month'],$found['day'],$found['year']);
|
return mktime($found['hour'],$found['min'],0,$found['month'],$found['day'],$found['year']);
|
||||||
}
|
}
|
||||||
@ -377,7 +399,7 @@ class Asyncservice
|
|||||||
);
|
);
|
||||||
// as the async_next column is used as a semaphore we only update it,
|
// as the async_next column is used as a semaphore we only update it,
|
||||||
// if it is 0 (semaphore released) or older then 10min to recover from failed or crashed attempts
|
// if it is 0 (semaphore released) or older then 10min to recover from failed or crashed attempts
|
||||||
if ($exists) $where = array('async_next=0 OR async_next<'.(time()-600));
|
if ($exists) $where = array('(async_next=0 OR async_next<'.(time()-600).')');
|
||||||
}
|
}
|
||||||
//echo "last_run=<pre>"; print_r($last_run); echo "</pre>\n";
|
//echo "last_run=<pre>"; print_r($last_run); echo "</pre>\n";
|
||||||
return $this->write($last_run, !!$exists, $where) > 0;
|
return $this->write($last_run, !!$exists, $where) > 0;
|
||||||
@ -442,9 +464,31 @@ class Asyncservice
|
|||||||
{
|
{
|
||||||
$job['data'] += array_diff_key($job,array('data' => false));
|
$job['data'] += array_diff_key($job,array('data' => false));
|
||||||
}
|
}
|
||||||
// update job before running it, to cope with jobs taking longer then async-frequency
|
|
||||||
if (($job['next'] = $this->next_run($job['times'])))
|
if ($this->debug) error_log(__METHOD__."() processing job ".array2string($job));
|
||||||
|
|
||||||
|
// purge keeped jobs, if they are due
|
||||||
|
if (is_array($job['data']) && !empty($job['data']['keep_time']))
|
||||||
{
|
{
|
||||||
|
if ($job['data']['keep_time'] <= time())
|
||||||
|
{
|
||||||
|
error_log(__METHOD__."() finally deleting job ".array2string($job));
|
||||||
|
$this->delete($job['id']);
|
||||||
|
}
|
||||||
|
if ($this->debug) error_log(__METHOD__."() keeping job ".array2string($job));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update job before running it, to cope with jobs taking longer then async-frequency
|
||||||
|
if (($job['next'] = $this->next_run($job['times'])) ||
|
||||||
|
// keep jobs with keep set (eg. calendar alarms) around
|
||||||
|
is_array($job['data']) && !empty($job['data']['keep']))
|
||||||
|
{
|
||||||
|
if (!$job['next'])
|
||||||
|
{
|
||||||
|
$job['next'] = $job['data']['keep_time'] = time() + ((int)$job['data']['keep'] > 1 ? $job['data']['keep'] : self::DEFAULT_KEEP_TIME);
|
||||||
|
if ($this->debug) error_log(__METHOD__."() setting keep_time to ".date('Y-m-d H:i:s', $job['data']['keep_time']).' for job '.array2string($job));
|
||||||
|
}
|
||||||
$this->write($job, True);
|
$this->write($job, True);
|
||||||
}
|
}
|
||||||
else // no further runs
|
else // no further runs
|
||||||
@ -453,6 +497,7 @@ class Asyncservice
|
|||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if ($this->debug) error_log(__METHOD__."() running job ".array2string($job));
|
||||||
ExecMethod($job['method'],$job['data']);
|
ExecMethod($job['method'],$job['data']);
|
||||||
}
|
}
|
||||||
catch(Exception $e)
|
catch(Exception $e)
|
||||||
@ -562,6 +607,7 @@ class Asyncservice
|
|||||||
*/
|
*/
|
||||||
function delete($id)
|
function delete($id)
|
||||||
{
|
{
|
||||||
|
if ($this->debug) error_log(__METHOD__."('$id') ".function_backtrace());
|
||||||
$this->db->delete($this->db_table,array('async_id' => $id),__LINE__,__FILE__);
|
$this->db->delete($this->db_table,array('async_id' => $id),__LINE__,__FILE__);
|
||||||
|
|
||||||
return $this->db->affected_rows();
|
return $this->db->affected_rows();
|
||||||
@ -659,7 +705,7 @@ class Asyncservice
|
|||||||
$n = 0;
|
$n = 0;
|
||||||
while ($line = fgets($crontab,256))
|
while ($line = fgets($crontab,256))
|
||||||
{
|
{
|
||||||
if ($this->debug) echo 'line '.++$n.": $line<br>\n";
|
if ($this->debug) error_log(__METHOD__.'() line '.++$n.": $line");
|
||||||
$parts = explode(' ',$line,6);
|
$parts = explode(' ',$line,6);
|
||||||
|
|
||||||
if ($line{0} == '#' || count($parts) < 6 || ($parts[5]{0} != '/' && substr($parts[5],0,3) != 'php'))
|
if ($line{0} == '#' || count($parts) < 6 || ($parts[5]{0} != '/' && substr($parts[5],0,3) != 'php'))
|
||||||
|
@ -120,6 +120,11 @@ class calendar_so
|
|||||||
*/
|
*/
|
||||||
const STATUS_SORT = "CASE cal_status WHEN 'U' THEN 1 WHEN 'T' THEN 2 WHEN 'A' THEN 3 WHEN 'R' THEN 4 ELSE 0 END ASC";
|
const STATUS_SORT = "CASE cal_status WHEN 'U' THEN 1 WHEN 'T' THEN 2 WHEN 'A' THEN 3 WHEN 'R' THEN 4 ELSE 0 END ASC";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time to keep alarms in async table to allow eg. alarm snozzing
|
||||||
|
*/
|
||||||
|
const ALARM_KEEP_TIME = 86400;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cached timezone data
|
* Cached timezone data
|
||||||
*
|
*
|
||||||
@ -2400,11 +2405,18 @@ ORDER BY cal_user_type, cal_usre_id
|
|||||||
$this->async->cancel_timer($id);
|
$this->async->cancel_timer($id);
|
||||||
}
|
}
|
||||||
$alarm['cal_id'] = $cal_id; // we need the back-reference
|
$alarm['cal_id'] = $cal_id; // we need the back-reference
|
||||||
|
// do not deleted async-job, as we need it for alarm snozzing
|
||||||
|
$alarm['keep'] = self::ALARM_KEEP_TIME;
|
||||||
|
// past alarms need NOT to be triggered, but kept around for a while to allow alarm snozzing
|
||||||
|
if ($alarm['time'] < time())
|
||||||
|
{
|
||||||
|
$alarm['time'] = $alarm['keep_time'] = time()+self::ALARM_KEEP_TIME;
|
||||||
|
}
|
||||||
// add an alarm uid, if none is given
|
// add an alarm uid, if none is given
|
||||||
if (empty($alarm['uid']) && class_exists('Horde_Support_Uuid')) $alarm['uid'] = (string)new Horde_Support_Uuid;
|
if (empty($alarm['uid']) && class_exists('Horde_Support_Uuid')) $alarm['uid'] = (string)new Horde_Support_Uuid;
|
||||||
//error_log(__METHOD__.__LINE__.' Save Alarm for CalID:'.$cal_id.'->'.array2string($alarm).'-->'.$id.'#'.function_backtrace());
|
//error_log(__METHOD__.__LINE__.' Save Alarm for CalID:'.$cal_id.'->'.array2string($alarm).'-->'.$id.'#'.function_backtrace());
|
||||||
// allways store job with the alarm owner as job-owner to get eg. the correct from address
|
// allways store job with the alarm owner as job-owner to get eg. the correct from address
|
||||||
if (!$this->async->set_timer($alarm['time'],$id,'calendar.calendar_boupdate.send_alarm',$alarm,$alarm['owner']))
|
if (!$this->async->set_timer($alarm['time'], $id, 'calendar.calendar_boupdate.send_alarm', $alarm, $alarm['owner'], false, true))
|
||||||
{
|
{
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user