2001-07-12 01:17:32 +02:00
|
|
|
<?php
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
2011-04-11 11:29:39 +02:00
|
|
|
* EGroupware - InfoLog - Business object
|
2006-10-04 19:40:33 +02:00
|
|
|
*
|
|
|
|
* @link http://www.egroupware.org
|
|
|
|
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
2009-07-15 22:04:17 +02:00
|
|
|
* @author Joerg Lehrke <jlehrke@noc.de>
|
2006-10-04 19:40:33 +02:00
|
|
|
* @package infolog
|
2017-10-20 16:31:41 +02:00
|
|
|
* @copyright (c) 2003-17 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
2006-10-04 19:40:33 +02:00
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
|
|
*/
|
2005-04-06 13:05:57 +02:00
|
|
|
|
2016-04-30 19:05:23 +02:00
|
|
|
use EGroupware\Api;
|
|
|
|
use EGroupware\Api\Link;
|
|
|
|
use EGroupware\Api\Acl;
|
|
|
|
use EGroupware\Api\Vfs;
|
2007-06-13 23:37:05 +02:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
2008-10-07 16:01:33 +02:00
|
|
|
* This class is the BO-layer of InfoLog
|
2006-10-04 19:40:33 +02:00
|
|
|
*/
|
2008-10-07 14:50:14 +02:00
|
|
|
class infolog_bo
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
/**
|
|
|
|
* Undelete right
|
|
|
|
*/
|
|
|
|
const ACL_UNDELETE = Acl::CUSTOM1;
|
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
var $enums;
|
2007-10-05 17:06:27 +02:00
|
|
|
var $status;
|
2005-04-06 13:05:57 +02:00
|
|
|
/**
|
2006-10-04 19:40:33 +02:00
|
|
|
* Instance of our so class
|
2005-04-06 13:05:57 +02:00
|
|
|
*
|
2008-10-07 14:50:14 +02:00
|
|
|
* @var infolog_so
|
2005-04-06 13:05:57 +02:00
|
|
|
*/
|
2006-10-04 19:40:33 +02:00
|
|
|
var $so;
|
2014-02-20 18:46:15 +01:00
|
|
|
/**
|
|
|
|
* Total from last search call
|
|
|
|
* @var int
|
|
|
|
*/
|
|
|
|
var $total;
|
2006-10-04 19:40:33 +02:00
|
|
|
var $vfs;
|
|
|
|
var $vfs_basedir='/infolog';
|
2010-02-09 22:56:39 +01:00
|
|
|
/**
|
|
|
|
* Set Logging
|
|
|
|
*
|
|
|
|
* @var boolean
|
|
|
|
*/
|
|
|
|
var $log = false;
|
2020-10-08 11:24:34 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Access permission cache for current user
|
|
|
|
*/
|
|
|
|
protected static $access_cache = array();
|
|
|
|
|
2010-02-09 22:56:39 +01:00
|
|
|
/**
|
|
|
|
* Cached timezone data
|
|
|
|
*
|
|
|
|
* @var array id => data
|
|
|
|
*/
|
|
|
|
protected static $tz_cache = array();
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
2010-02-04 13:08:03 +01:00
|
|
|
* current time as timestamp in user-time and server-time
|
2008-10-07 14:50:14 +02:00
|
|
|
*
|
2010-03-07 00:06:43 +01:00
|
|
|
* @var int
|
2006-10-04 19:40:33 +02:00
|
|
|
*/
|
|
|
|
var $user_time_now;
|
2010-02-04 13:08:03 +01:00
|
|
|
var $now;
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
|
|
|
* name of timestamps in an InfoLog entry
|
2008-10-07 14:50:14 +02:00
|
|
|
*
|
2006-10-04 19:40:33 +02:00
|
|
|
* @var array
|
|
|
|
*/
|
2011-04-11 11:29:39 +02:00
|
|
|
var $timestamps = array('info_startdate','info_enddate','info_datemodified','info_datecompleted','info_created');
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
|
|
|
* fields the responsible user can change
|
2008-10-07 14:50:14 +02:00
|
|
|
*
|
2006-10-04 19:40:33 +02:00
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
var $responsible_edit=array('info_status','info_percent','info_datecompleted');
|
2011-11-10 13:17:35 +01:00
|
|
|
/**
|
2012-02-24 10:29:27 +01:00
|
|
|
* Fields to exclude from copy, if an entry is copied, the ones below are excluded by default.
|
2011-11-10 13:17:35 +01:00
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
var $copy_excludefields = array('info_id', 'info_uid', 'info_etag', 'caldav_name', 'info_created', 'info_creator', 'info_datemodified', 'info_modifier');
|
2012-02-24 10:29:27 +01:00
|
|
|
/**
|
|
|
|
* Fields to exclude from copy, if a sub-entry is created, the ones below are excluded by default.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
2012-02-24 11:31:43 +01:00
|
|
|
var $sub_excludefields = array('info_id', 'info_uid', 'info_etag', 'caldav_name', 'info_created', 'info_creator', 'info_datemodified', 'info_modifier');
|
|
|
|
/**
|
|
|
|
* Additional fields to $sub_excludefields to exclude, if no config stored
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
var $default_sub_excludefields = array('info_des');
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
|
|
|
* implicit ACL rights of the responsible user: read or edit
|
2008-10-07 14:50:14 +02:00
|
|
|
*
|
2006-10-04 19:40:33 +02:00
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
var $implicit_rights='read';
|
|
|
|
/**
|
|
|
|
* Custom fields read from the infolog config
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
var $customfields=array();
|
2007-03-12 12:27:33 +01:00
|
|
|
/**
|
2008-10-07 14:50:14 +02:00
|
|
|
* Group owners for certain types read from the infolog config
|
2007-03-12 12:27:33 +01:00
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
var $group_owners=array();
|
2007-05-28 23:17:15 +02:00
|
|
|
/**
|
|
|
|
* Current user
|
|
|
|
*
|
|
|
|
* @var int
|
|
|
|
*/
|
|
|
|
var $user;
|
2007-06-13 23:37:05 +02:00
|
|
|
/**
|
2024-04-01 14:09:13 +02:00
|
|
|
* History logging: ''=no, 'history'=history & delete allowed, 'history_admin_delete', 'history_no_delete'
|
2007-06-13 23:37:05 +02:00
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
var $history;
|
2024-04-01 14:09:13 +02:00
|
|
|
/**
|
|
|
|
* @var string "yes": archived entries can not be changed, "but_admins" noone but admins can change archived entries
|
|
|
|
*/
|
|
|
|
var $archived_readonly;
|
2024-04-03 16:01:50 +02:00
|
|
|
/**
|
|
|
|
* @var array fields editable for status archived
|
|
|
|
*/
|
|
|
|
var $archived_editable;
|
2007-06-13 23:37:05 +02:00
|
|
|
/**
|
|
|
|
* Instance of infolog_tracking, only instaciated if needed!
|
|
|
|
*
|
|
|
|
* @var infolog_tracking
|
|
|
|
*/
|
|
|
|
var $tracking;
|
2007-09-13 10:12:56 +02:00
|
|
|
/**
|
|
|
|
* Maximum number of line characters (-_+=~) allowed in a mail, to not stall the layout.
|
2024-07-29 15:57:08 +02:00
|
|
|
* Longer lines / bigger number of these chars are truncated to that max. number or chars.
|
2007-09-13 10:12:56 +02:00
|
|
|
*
|
|
|
|
* @var int
|
|
|
|
*/
|
|
|
|
var $max_line_chars = 40;
|
2021-05-31 10:38:31 +02:00
|
|
|
/**
|
|
|
|
* Limit rows ordered by last modified to last N month to improve performance on huge sites
|
|
|
|
*/
|
|
|
|
public $limit_modified_n_month;
|
2008-01-19 06:36:20 +01:00
|
|
|
|
2009-05-05 14:48:38 +02:00
|
|
|
/**
|
|
|
|
* Available filters
|
|
|
|
*
|
|
|
|
* @var array filter => label pairs
|
|
|
|
*/
|
|
|
|
var $filters = array(
|
2013-05-07 00:08:08 +02:00
|
|
|
'' => 'no Filter',
|
2009-05-05 14:48:38 +02:00
|
|
|
'done' => 'done',
|
|
|
|
'responsible' => 'responsible',
|
|
|
|
'responsible-open-today' => 'responsible open',
|
|
|
|
'responsible-open-overdue' => 'responsible overdue',
|
|
|
|
'responsible-upcoming' => 'responsible upcoming',
|
2010-07-15 12:09:35 +02:00
|
|
|
'responsible-open-upcoming'=> 'responsible open and upcoming',
|
2009-05-05 14:48:38 +02:00
|
|
|
'delegated' => 'delegated',
|
|
|
|
'delegated-open-today' => 'delegated open',
|
|
|
|
'delegated-open-overdue' => 'delegated overdue',
|
|
|
|
'delegated-upcoming' => 'delegated upcomming',
|
2010-07-15 12:09:35 +02:00
|
|
|
'delegated-open-upcoming' => 'delegated open and upcoming',
|
2009-05-05 14:48:38 +02:00
|
|
|
'own' => 'own',
|
|
|
|
'own-open-today' => 'own open',
|
|
|
|
'own-open-overdue' => 'own overdue',
|
|
|
|
'own-upcoming' => 'own upcoming',
|
2010-07-15 12:09:35 +02:00
|
|
|
'own-open-upcoming' => 'own open and upcoming',
|
2014-09-24 00:48:11 +02:00
|
|
|
'private' => 'private',
|
2011-05-02 21:41:21 +02:00
|
|
|
'open-today' => 'open(status)',
|
2009-05-05 14:48:38 +02:00
|
|
|
'open-overdue' => 'overdue',
|
|
|
|
'upcoming' => 'upcoming',
|
2010-07-15 12:09:35 +02:00
|
|
|
'open-upcoming' => 'open and upcoming',
|
2009-11-10 09:11:41 +01:00
|
|
|
'bydate' => 'startdate',
|
2024-04-03 10:10:50 +02:00
|
|
|
'duedate' => 'enddate',
|
|
|
|
'+archived' => 'archived too',
|
2009-05-05 14:48:38 +02:00
|
|
|
);
|
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
|
|
|
* Constructor Infolog BO
|
|
|
|
*
|
|
|
|
* @param int $info_id
|
|
|
|
*/
|
2014-01-28 10:22:12 +01:00
|
|
|
function __construct($info_id = 0)
|
2001-07-12 01:17:32 +02:00
|
|
|
{
|
2006-10-04 19:40:33 +02:00
|
|
|
$this->enums = $this->stock_enums = array(
|
|
|
|
'priority' => array (
|
|
|
|
3 => 'urgent',
|
|
|
|
2 => 'high',
|
|
|
|
1 => 'normal',
|
2008-10-07 14:50:14 +02:00
|
|
|
0 => 'low'
|
2004-03-10 01:58:18 +01:00
|
|
|
),
|
2006-10-04 19:40:33 +02:00
|
|
|
'confirm' => array(
|
|
|
|
'not' => 'not','accept' => 'accept','finish' => 'finish',
|
|
|
|
'both' => 'both' ),
|
|
|
|
'type' => array(
|
|
|
|
'task' => 'task','phone' => 'phone','note' => 'note','email' => 'email'
|
|
|
|
/* ,'confirm' => 'confirm','reject' => 'reject','fax' => 'fax' not implemented so far */ )
|
2004-03-10 01:58:18 +01:00
|
|
|
);
|
2006-10-04 19:40:33 +02:00
|
|
|
$this->status = $this->stock_status = array(
|
|
|
|
'defaults' => array(
|
|
|
|
'task' => 'not-started', 'phone' => 'not-started', 'note' => 'done','email' => 'done'),
|
|
|
|
'task' => array(
|
|
|
|
'offer' => 'offer', // --> NEEDS-ACTION
|
|
|
|
'not-started' => 'not-started', // iCal NEEDS-ACTION
|
|
|
|
'ongoing' => 'ongoing', // iCal IN-PROCESS
|
|
|
|
'done' => 'done', // iCal COMPLETED
|
|
|
|
'cancelled' => 'cancelled', // iCal CANCELLED
|
2007-10-05 17:06:27 +02:00
|
|
|
'billed' => 'billed', // --> DONE
|
|
|
|
'template' => 'template', // --> cancelled
|
|
|
|
'nonactive' => 'nonactive', // --> cancelled
|
2009-07-15 22:04:17 +02:00
|
|
|
'archive' => 'archive' ), // --> cancelled
|
2006-10-04 19:40:33 +02:00
|
|
|
'phone' => array(
|
|
|
|
'not-started' => 'call', // iCal NEEDS-ACTION
|
|
|
|
'ongoing' => 'will-call', // iCal IN-PROCESS
|
|
|
|
'done' => 'done', // iCal COMPLETED
|
|
|
|
'billed' => 'billed' ), // --> DONE
|
|
|
|
'note' => array(
|
|
|
|
'ongoing' => 'ongoing', // iCal has no status on notes
|
2007-06-13 23:37:05 +02:00
|
|
|
'done' => 'done' ),
|
2006-10-04 19:40:33 +02:00
|
|
|
'email' => array(
|
|
|
|
'ongoing' => 'ongoing', // iCal has no status on notes
|
2007-06-13 23:37:05 +02:00
|
|
|
'done' => 'done' ),
|
|
|
|
);
|
2016-04-30 19:05:23 +02:00
|
|
|
if (($config_data = Api\Config::read('infolog')))
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2024-02-06 20:46:43 +01:00
|
|
|
$this->allow_past_due_date = !isset($config_data['allow_past_due_date']) ? 1 : $config_data['allow_past_due_date'];
|
2008-01-19 06:36:20 +01:00
|
|
|
if (isset($config_data['status']) && is_array($config_data['status']))
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2014-01-28 10:22:12 +01:00
|
|
|
foreach(array_keys($config_data['status']) as $key)
|
2003-08-28 16:31:11 +02:00
|
|
|
{
|
2021-10-07 10:14:08 +02:00
|
|
|
if (!isset($this->status[$key]) || !is_array($this->status[$key]))
|
2003-08-28 16:31:11 +02:00
|
|
|
{
|
2006-10-04 19:40:33 +02:00
|
|
|
$this->status[$key] = array();
|
2003-08-28 16:31:11 +02:00
|
|
|
}
|
2010-05-11 14:59:47 +02:00
|
|
|
$this->status[$key] = array_merge($this->status[$key],(array)$config_data['status'][$key]);
|
2003-08-28 16:31:11 +02:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2008-01-19 06:36:20 +01:00
|
|
|
if (isset($config_data['types']) && is_array($config_data['types']))
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
|
|
|
//echo "stock-types:<pre>"; print_r($this->enums['type']); echo "</pre>\n";
|
2008-01-19 06:36:20 +01:00
|
|
|
//echo "config-types:<pre>"; print_r($config_data['types']); echo "</pre>\n";
|
|
|
|
$this->enums['type'] += $config_data['types'];
|
2006-10-04 19:40:33 +02:00
|
|
|
//echo "types:<pre>"; print_r($this->enums['type']); echo "</pre>\n";
|
|
|
|
}
|
2024-02-06 20:46:43 +01:00
|
|
|
if (!empty($config_data['group_owners'])) $this->group_owners = $config_data['group_owners'];
|
2007-03-12 12:27:33 +01:00
|
|
|
|
2016-04-30 19:05:23 +02:00
|
|
|
$this->customfields = Api\Storage\Customfields::get('infolog');
|
2008-01-19 06:36:20 +01:00
|
|
|
if ($this->customfields)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
|
|
|
foreach($this->customfields as $name => $field)
|
2006-03-24 17:10:09 +01:00
|
|
|
{
|
2006-10-04 19:40:33 +02:00
|
|
|
// old infolog customefield record
|
|
|
|
if(empty($field['type']))
|
|
|
|
{
|
|
|
|
if (count($field['values'])) $field['type'] = 'select'; // selectbox
|
|
|
|
elseif ($field['rows'] > 1) $field['type'] = 'textarea'; // textarea
|
|
|
|
elseif (intval($field['len']) > 0) $field['type'] = 'text'; // regular input field
|
|
|
|
else $field['type'] = 'label'; // header-row
|
|
|
|
$field['type2'] = $field['typ'];
|
|
|
|
unset($field['typ']);
|
2008-01-19 06:36:20 +01:00
|
|
|
$this->customfields[$name] = $field;
|
2006-10-04 19:40:33 +02:00
|
|
|
$save_config = true;
|
|
|
|
}
|
2024-07-29 15:57:08 +02:00
|
|
|
// add date-time CFs to timestamps to ensure TZ conversation
|
|
|
|
if ($field['type'] === 'date-time')
|
|
|
|
{
|
|
|
|
$this->timestamps[] = '#'.$field['name'];
|
|
|
|
}
|
2006-03-24 17:10:09 +01:00
|
|
|
}
|
2021-10-07 10:14:08 +02:00
|
|
|
if (!empty($save_config)) Api\Config::save_value('customfields',$this->customfields,'infolog');
|
2001-10-07 22:11:32 +02:00
|
|
|
}
|
2021-10-07 10:14:08 +02:00
|
|
|
if (isset($config_data['responsible_edit']) && is_array($config_data['responsible_edit']))
|
2004-03-13 18:58:37 +01:00
|
|
|
{
|
2008-01-19 06:36:20 +01:00
|
|
|
$this->responsible_edit = array_merge($this->responsible_edit,$config_data['responsible_edit']);
|
2004-03-13 18:58:37 +01:00
|
|
|
}
|
2021-10-07 10:14:08 +02:00
|
|
|
if (isset($config_data['copy_excludefields']) && is_array($config_data['copy_excludefields']))
|
2011-11-10 13:17:35 +01:00
|
|
|
{
|
|
|
|
$this->copy_excludefields = array_merge($this->copy_excludefields,$config_data['copy_excludefields']);
|
|
|
|
}
|
2021-10-07 10:14:08 +02:00
|
|
|
if (!empty($config_data['sub_excludefields']) && is_array($config_data['sub_excludefields']))
|
2012-02-24 10:29:27 +01:00
|
|
|
{
|
|
|
|
$this->sub_excludefields = array_merge($this->sub_excludefields,$config_data['sub_excludefields']);
|
|
|
|
}
|
2012-02-24 11:31:43 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
$this->sub_excludefields = array_merge($this->sub_excludefields,$this->default_sub_excludefields);
|
|
|
|
}
|
2024-02-06 20:46:43 +01:00
|
|
|
if (isset($config_data['implicit_rights']) && $config_data['implicit_rights'] === 'edit')
|
2004-03-13 18:58:37 +01:00
|
|
|
{
|
2006-10-04 19:40:33 +02:00
|
|
|
$this->implicit_rights = 'edit';
|
2004-03-13 18:58:37 +01:00
|
|
|
}
|
2008-01-19 06:36:20 +01:00
|
|
|
$this->history = $config_data['history'];
|
2021-05-31 10:38:31 +02:00
|
|
|
|
2024-04-01 14:09:13 +02:00
|
|
|
if (($this->archived_readonly = $config_data['archived_readonly'] ?? null))
|
|
|
|
{
|
|
|
|
// add "archive" status to all types
|
|
|
|
foreach($this->status as $type => &$statis)
|
|
|
|
{
|
|
|
|
if ($type !== 'defaults' && !isset($statis['archive']))
|
|
|
|
{
|
|
|
|
$statis['archive'] = 'archive';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-04-03 16:01:50 +02:00
|
|
|
$this->archived_editable = $config_data['archived_editable'] ?? null;
|
2024-04-01 14:09:13 +02:00
|
|
|
|
2021-10-07 10:14:08 +02:00
|
|
|
$this->limit_modified_n_month = $config_data['limit_modified_n_month'] ?? null;
|
2001-07-12 01:17:32 +02:00
|
|
|
}
|
2007-04-26 17:42:51 +02:00
|
|
|
// sort types by there translation
|
|
|
|
foreach($this->enums['type'] as $key => $val)
|
|
|
|
{
|
|
|
|
if (($val = lang($key)) != $key.'*') $this->enums['type'][$key] = lang($key);
|
|
|
|
}
|
|
|
|
natcasesort($this->enums['type']);
|
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
$this->user = $GLOBALS['egw_info']['user']['account_id'];
|
|
|
|
|
2010-02-04 13:08:03 +01:00
|
|
|
$this->now = time();
|
2016-04-30 19:05:23 +02:00
|
|
|
$this->user_time_now = Api\DateTime::server2user($this->now,'ts');
|
2006-10-04 19:40:33 +02:00
|
|
|
|
2007-03-12 12:27:33 +01:00
|
|
|
$this->grants = $GLOBALS['egw']->acl->get_grants('infolog',$this->group_owners ? $this->group_owners : true);
|
2009-06-08 18:21:14 +02:00
|
|
|
$this->so = new infolog_so($this->grants);
|
2007-03-12 12:27:33 +01:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
if ($info_id)
|
2003-08-28 16:31:11 +02:00
|
|
|
{
|
2006-10-04 19:40:33 +02:00
|
|
|
$this->read( $info_id );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$this->init();
|
2003-08-28 16:31:11 +02:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2003-08-28 16:31:11 +02:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
|
|
|
* checks if there are customfields for typ $typ
|
|
|
|
*
|
|
|
|
* @param string $type
|
|
|
|
* @return boolean True if there are customfields for $typ, else False
|
|
|
|
*/
|
2016-04-30 19:05:23 +02:00
|
|
|
function has_customfields($type)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2014-01-28 10:22:12 +01:00
|
|
|
foreach($this->customfields as $field)
|
2001-07-15 00:16:16 +02:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
if ((!$type || empty($field['type2']) || in_array($type,is_array($field['type2']) ? $field['type2'] : explode(',',$field['type2']))))
|
2005-10-05 09:50:47 +02:00
|
|
|
{
|
2006-10-04 19:40:33 +02:00
|
|
|
return True;
|
2005-10-05 09:50:47 +02:00
|
|
|
}
|
2002-02-14 21:14:15 +01:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
return False;
|
|
|
|
}
|
2002-02-14 21:14:15 +01:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
2024-04-01 14:09:13 +02:00
|
|
|
* check's if user has the required rights on entry $info_id
|
2006-10-04 19:40:33 +02:00
|
|
|
*
|
2010-03-07 00:06:43 +01:00
|
|
|
* @param int|array $info data or info_id of infolog entry to check
|
2016-04-30 19:05:23 +02:00
|
|
|
* @param int $required_rights ACL::{READ|EDIT|ADD|DELETE}|infolog_bo::ACL_UNDELETE
|
2010-03-15 10:55:16 +01:00
|
|
|
* @param int $other uid to check (if info==0) or 0 to check against $this->user
|
2015-04-17 11:39:22 +02:00
|
|
|
* @param int $user = null user whos rights to check, default current user
|
2006-10-04 19:40:33 +02:00
|
|
|
* @return boolean
|
|
|
|
*/
|
2011-06-26 14:32:06 +02:00
|
|
|
function check_access($info,$required_rights,$other=0,$user=null)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2011-07-07 10:19:31 +02:00
|
|
|
$info_id = is_array($info) ? $info['info_id'] : $info;
|
|
|
|
|
2011-06-26 14:32:06 +02:00
|
|
|
if (!$user) $user = $this->user;
|
|
|
|
if ($user == $this->user)
|
|
|
|
{
|
|
|
|
$grants = $this->grants;
|
2020-10-08 11:24:34 +02:00
|
|
|
if ($info_id) $access =& static::$access_cache[$info_id][$required_rights]; // we only cache the current user!
|
2011-06-26 14:32:06 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$grants = $GLOBALS['egw']->acl->get_grants('infolog',$this->group_owners ? $this->group_owners : true,$user);
|
|
|
|
}
|
2010-03-15 10:55:16 +01:00
|
|
|
if (!$info)
|
|
|
|
{
|
2011-06-26 14:32:06 +02:00
|
|
|
$owner = $other ? $other : $user;
|
|
|
|
$grant = $grants[$owner];
|
|
|
|
return $grant & $required_rights;
|
2010-03-15 10:55:16 +01:00
|
|
|
}
|
|
|
|
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2011-06-26 14:32:06 +02:00
|
|
|
if (!isset($access))
|
2002-05-12 09:14:01 +02:00
|
|
|
{
|
2021-05-18 14:14:21 +02:00
|
|
|
if (!is_array($info) && !($info = $this->so->read(array('info_id' => $info_id)))) return false;
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2024-04-01 14:09:13 +02:00
|
|
|
// handle edit for archived entries
|
|
|
|
if ($info['info_status'] === 'archive' && $this->archived_readonly && $required_rights == ACL::EDIT &&
|
2024-04-01 22:46:13 +02:00
|
|
|
($this->archived_readonly === 'yes' || empty($GLOBALS['egw_info']['user']['apps']['admin'])))
|
2024-04-01 14:09:13 +02:00
|
|
|
{
|
|
|
|
$access = false;
|
|
|
|
}
|
|
|
|
// handle delete for the various history modes
|
|
|
|
elseif ($info['info_status'] === 'deleted' &&
|
2021-05-18 14:14:21 +02:00
|
|
|
($required_rights == Acl::EDIT || // no edit rights for deleted entries
|
|
|
|
$required_rights == Acl::ADD || // no add rights for deleted entries
|
|
|
|
$required_rights == Acl::DELETE && ($this->history == 'history_no_delete' || // no delete at all!
|
|
|
|
$this->history == 'history_admin_delete' && (!isset($GLOBALS['egw_info']['user']['apps']['admin']) || $user!=$this->user)))) // delete only for admins
|
|
|
|
{
|
|
|
|
$access = false;
|
|
|
|
}
|
|
|
|
elseif ($required_rights == self::ACL_UNDELETE)
|
|
|
|
{
|
|
|
|
if ($info['info_status'] != 'deleted')
|
2011-06-26 14:32:06 +02:00
|
|
|
{
|
2021-05-18 14:14:21 +02:00
|
|
|
$access = false; // can only undelete deleted items
|
2011-06-26 14:32:06 +02:00
|
|
|
}
|
2021-05-18 14:14:21 +02:00
|
|
|
else
|
2011-06-26 14:32:06 +02:00
|
|
|
{
|
2021-05-18 14:14:21 +02:00
|
|
|
// undelete requires edit rights
|
|
|
|
$access = $this->so->check_access( $info,Acl::EDIT,$this->implicit_rights == 'edit',$grants,$user );
|
2011-06-26 14:32:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!isset($access))
|
2007-06-13 23:37:05 +02:00
|
|
|
{
|
2011-06-26 14:32:06 +02:00
|
|
|
$access = $this->so->check_access( $info,$required_rights,$this->implicit_rights == 'edit',$grants,$user );
|
2007-06-13 23:37:05 +02:00
|
|
|
}
|
|
|
|
}
|
2011-06-26 14:32:06 +02:00
|
|
|
// else $cached = ' (from cache)';
|
|
|
|
// error_log(__METHOD__."($info_id,$required_rights,$other,$user) returning$cached ".array2string($access));
|
|
|
|
return $access;
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2006-10-24 12:08:21 +02:00
|
|
|
/**
|
2010-03-15 10:55:16 +01:00
|
|
|
* Check if user is responsible for an entry: he or one of his memberships is in responsible
|
2006-10-24 12:08:21 +02:00
|
|
|
*
|
|
|
|
* @param array $info infolog entry as array
|
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
function is_responsible($info)
|
|
|
|
{
|
|
|
|
return $this->so->is_responsible($info);
|
|
|
|
}
|
2003-08-28 16:31:11 +02:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
|
|
|
* init internal data to be empty
|
|
|
|
*/
|
|
|
|
function init()
|
|
|
|
{
|
2020-10-08 11:24:34 +02:00
|
|
|
static::$access_cache = array();
|
2006-10-04 19:40:33 +02:00
|
|
|
$this->so->init();
|
|
|
|
}
|
2003-08-28 16:31:11 +02:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
|
|
|
* convert a link_id value into an info_from text
|
|
|
|
*
|
|
|
|
* @param array &$info infolog entry, key info_from gets set by this function
|
2015-04-17 11:39:22 +02:00
|
|
|
* @param string $not_app = '' app to exclude
|
|
|
|
* @param string $not_id = '' id to exclude
|
2006-10-04 19:40:33 +02:00
|
|
|
* @return boolean True if we have a linked item, False otherwise
|
|
|
|
*/
|
|
|
|
function link_id2from(&$info,$not_app='',$not_id='')
|
|
|
|
{
|
2016-12-09 20:02:02 +01:00
|
|
|
//error_log(__METHOD__ . "(subject='{$info['info_subject']}', link_id='{$info['info_link_id']}', from='{$info['info_from']}', not_app='$not_app', not_id='$not_id')");
|
2008-03-10 22:04:51 +01:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
if ($info['info_link_id'] > 0 &&
|
2008-03-08 22:43:13 +01:00
|
|
|
(isset($info['links']) && ($link = $info['links'][$info['info_link_id']]) || // use supplied links info
|
2016-04-30 19:05:23 +02:00
|
|
|
($link = Link::get_link($info['info_link_id'])) !== False)) // if link not found in supplied links, we always search!
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2008-03-31 17:47:51 +02:00
|
|
|
if (isset($info['links']) && isset($link['app']))
|
2008-03-08 22:43:13 +01:00
|
|
|
{
|
|
|
|
$app = $link['app'];
|
|
|
|
$id = $link['id'];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$nr = $link['link_app1'] == 'infolog' && $link['link_id1'] == $info['info_id'] ? '2' : '1';
|
|
|
|
$app = $link['link_app'.$nr];
|
|
|
|
$id = $link['link_id'.$nr];
|
|
|
|
}
|
2016-04-30 19:05:23 +02:00
|
|
|
$title = Link::title($app,$id);
|
2006-10-04 19:40:33 +02:00
|
|
|
|
|
|
|
if ((string)$info['info_custom_from'] === '') // old entry
|
|
|
|
{
|
2022-04-27 17:48:09 +02:00
|
|
|
$info['info_custom_from'] = (int) ($title !== $info['info_from'] && is_string($title) && @htmlentities($title) !== $info['info_from']);
|
2002-05-12 09:14:01 +02:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
if (!$info['info_custom_from'])
|
2003-07-06 11:01:13 +02:00
|
|
|
{
|
2006-10-04 19:40:33 +02:00
|
|
|
$info['info_from'] = '';
|
|
|
|
$info['info_custom_from'] = 0;
|
2003-07-06 11:01:13 +02:00
|
|
|
}
|
2008-03-08 22:43:13 +01:00
|
|
|
if ($app == $not_app && $id == $not_id)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
|
|
|
return False;
|
|
|
|
}
|
2017-01-16 21:58:52 +01:00
|
|
|
// if link is a project and no other project selected, also add as project
|
2024-02-06 20:46:43 +01:00
|
|
|
if ($app == 'projectmanager' && $id && empty($info['pm_id']))
|
2017-01-16 21:58:52 +01:00
|
|
|
{
|
|
|
|
$info['old_pm_id'] = $info['pm_id'] = $id;
|
|
|
|
}
|
2017-09-15 19:24:06 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// Link might be contact, check others
|
|
|
|
$this->get_pm_id($info);
|
|
|
|
}
|
2017-09-13 18:21:50 +02:00
|
|
|
$info['info_link'] = $info['info_contact'] = array(
|
2008-03-08 22:43:13 +01:00
|
|
|
'app' => $app,
|
|
|
|
'id' => $id,
|
2006-10-04 19:40:33 +02:00
|
|
|
'title' => (!empty($info['info_from']) ? $info['info_from'] : $title),
|
|
|
|
);
|
2002-05-12 09:14:01 +02:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
//echo " title='$title'</p>\n";
|
|
|
|
return $info['blur_title'] = $title;
|
|
|
|
}
|
2017-09-15 19:24:06 +02:00
|
|
|
|
|
|
|
// Set ID to 'none' instead of unset to make it seem like there's a value
|
|
|
|
$info['info_link'] = $info['info_contact'] = $info['info_from'] ? array('id' => 'none', 'title' => $info['info_from']) : null;
|
2008-03-08 22:43:13 +01:00
|
|
|
$info['info_link_id'] = 0; // link might have been deleted
|
|
|
|
$info['info_custom_from'] = (int)!!$info['info_from'];
|
|
|
|
|
2017-12-05 17:44:55 +01:00
|
|
|
$this->get_pm_id($info);
|
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
2017-09-15 19:24:06 +02:00
|
|
|
/**
|
|
|
|
* Find projectmanager ID from linked project(s)
|
|
|
|
*
|
|
|
|
* @param Array $info
|
|
|
|
*/
|
|
|
|
public function get_pm_id(&$info)
|
|
|
|
{
|
|
|
|
$pm_links = Link::get_links('infolog',$info['info_id'],'projectmanager');
|
|
|
|
|
|
|
|
$old_pm_id = is_array($pm_links) ? array_shift($pm_links) : $info['old_pm_id'];
|
|
|
|
if (!isset($info['pm_id']) && $old_pm_id) $info['pm_id'] = $old_pm_id;
|
2017-09-21 19:37:49 +02:00
|
|
|
return $old_pm_id;
|
2017-09-15 19:24:06 +02:00
|
|
|
}
|
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
|
|
|
* Create a subject from a description: truncate it and add ' ...'
|
|
|
|
*/
|
2008-03-08 22:43:13 +01:00
|
|
|
static function subject_from_des($des)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
|
|
|
return substr($des,0,60).' ...';
|
|
|
|
}
|
2003-11-23 14:33:21 +01:00
|
|
|
|
2010-02-09 22:56:39 +01:00
|
|
|
/**
|
|
|
|
* Convert the timestamps from given timezone to another and keep dates.
|
|
|
|
* The timestamps are mostly expected to be in server-time
|
|
|
|
* and $fromTZId is only used to qualify dates.
|
|
|
|
*
|
|
|
|
* @param array $values to modify
|
2015-04-17 11:39:22 +02:00
|
|
|
* @param string $fromTZId = null
|
|
|
|
* @param string $toTZId = false
|
2010-02-09 22:56:39 +01:00
|
|
|
* TZID timezone name e.g. 'UTC'
|
|
|
|
* or NULL for timestamps in user-time
|
|
|
|
* or false for timestamps in server-time
|
2024-05-03 19:55:47 +02:00
|
|
|
* @param string $type 'ts' timestamp, 'object': DateTime objects
|
2010-02-09 22:56:39 +01:00
|
|
|
*/
|
2024-05-03 19:55:47 +02:00
|
|
|
function time2time(&$values, $fromTZId=false, $toTZId=null, $type='ts')
|
2010-02-09 22:56:39 +01:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$tz = Api\DateTime::$server_timezone;
|
2010-02-09 22:56:39 +01:00
|
|
|
|
|
|
|
if ($fromTZId)
|
|
|
|
{
|
|
|
|
if (!isset(self::$tz_cache[$fromTZId]))
|
|
|
|
{
|
|
|
|
self::$tz_cache[$fromTZId] = calendar_timezones::DateTimeZone($fromTZId);
|
|
|
|
}
|
|
|
|
$fromTZ = self::$tz_cache[$fromTZId];
|
|
|
|
}
|
|
|
|
elseif (is_null($fromTZId))
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$tz = Api\DateTime::$user_timezone;
|
|
|
|
$fromTZ = Api\DateTime::$user_timezone;
|
2010-02-09 22:56:39 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$fromTZ = Api\DateTime::$server_timezone;
|
2010-02-09 22:56:39 +01:00
|
|
|
}
|
|
|
|
if ($toTZId)
|
|
|
|
{
|
|
|
|
if (!isset(self::$tz_cache[$toTZId]))
|
|
|
|
{
|
|
|
|
self::$tz_cache[$toTZId] = calendar_timezones::DateTimeZone($toTZId);
|
|
|
|
}
|
|
|
|
$toTZ = self::$tz_cache[$toTZId];
|
|
|
|
}
|
|
|
|
elseif (is_null($toTZId))
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$toTZ = Api\DateTime::$user_timezone;
|
2010-02-09 22:56:39 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$toTZ = Api\DateTime::$server_timezone;
|
2010-02-09 22:56:39 +01:00
|
|
|
}
|
2016-04-30 19:05:23 +02:00
|
|
|
//error_log(__METHOD__.'(values[info_enddate]='.date('Y-m-d H:i:s',$values['info_enddate']).", from=".array2string($fromTZId).", to=".array2string($toTZId).") tz=".$tz->getName().', fromTZ='.$fromTZ->getName().', toTZ='.$toTZ->getName().', userTZ='.Api\DateTime::$user_timezone->getName());
|
2010-02-09 22:56:39 +01:00
|
|
|
foreach($this->timestamps as $key)
|
|
|
|
{
|
|
|
|
if ($values[$key])
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$time = new Api\DateTime($values[$key], $tz);
|
2010-02-09 22:56:39 +01:00
|
|
|
$time->setTimezone($fromTZ);
|
|
|
|
if ($time->format('Hi') == '0000')
|
|
|
|
{
|
|
|
|
// we keep dates the same in new timezone
|
2016-04-30 19:05:23 +02:00
|
|
|
$arr = Api\DateTime::to($time,'array');
|
|
|
|
$time = new Api\DateTime($arr, $toTZ);
|
2010-02-09 22:56:39 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$time->setTimezone($toTZ);
|
|
|
|
}
|
2024-05-03 19:55:47 +02:00
|
|
|
$values[$key] = Api\DateTime::to($time, $type);
|
2010-02-09 22:56:39 +01:00
|
|
|
}
|
|
|
|
}
|
2012-02-22 13:31:00 +01:00
|
|
|
//error_log(__METHOD__.'() --> values[info_enddate]='.date('Y-m-d H:i:s',$values['info_enddate']));
|
2010-02-09 22:56:39 +01:00
|
|
|
}
|
|
|
|
|
2010-02-04 13:08:03 +01:00
|
|
|
/**
|
|
|
|
* convert a date from server to user-time
|
|
|
|
*
|
|
|
|
* @param int $ts timestamp in server-time
|
2015-04-17 11:39:22 +02:00
|
|
|
* @param string $date_format = 'ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time, 'array'=array or string with date-format
|
2010-02-04 13:08:03 +01:00
|
|
|
* @return mixed depending of $date_format
|
|
|
|
*/
|
|
|
|
function date2usertime($ts,$date_format='ts')
|
|
|
|
{
|
|
|
|
if (empty($ts) || $date_format == 'server') return $ts;
|
|
|
|
|
2016-04-30 19:05:23 +02:00
|
|
|
return Api\DateTime::server2user($ts,$date_format);
|
2010-02-04 13:08:03 +01:00
|
|
|
}
|
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
|
|
|
* Read an infolog entry specified by $info_id
|
|
|
|
*
|
2011-04-11 11:29:39 +02:00
|
|
|
* @param int|array $info_id integer id or array with id's or array with column=>value pairs of the entry to read
|
2015-04-17 11:39:22 +02:00
|
|
|
* @param boolean $run_link_id2from = true should link_id2from run, default yes,
|
2024-07-29 15:57:08 +02:00
|
|
|
* need to be set to false if called from link-title to prevent an infinite recursion
|
2015-04-17 11:39:22 +02:00
|
|
|
* @param string $date_format = 'ts' date-formats: 'ts'=timestamp, 'server'=timestamp in server-time,
|
2024-07-29 15:57:08 +02:00
|
|
|
* 'array'=array or string with date-format, 'object' DateTime objects
|
2015-04-17 11:39:22 +02:00
|
|
|
* @param boolean $ignore_acl = false if true, do NOT check access, default false
|
2010-02-04 13:08:03 +01:00
|
|
|
*
|
2010-03-07 00:06:43 +01:00
|
|
|
* @return array|boolean infolog entry, null if not found or false if no permission to read it
|
2006-10-04 19:40:33 +02:00
|
|
|
*/
|
2013-02-06 11:17:36 +01:00
|
|
|
function &read($info_id,$run_link_id2from=true,$date_format='ts',$ignore_acl=false)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2011-04-11 11:29:39 +02:00
|
|
|
//error_log(__METHOD__.'('.array2string($info_id).', '.array2string($run_link_id2from).", '$date_format') ".function_backtrace());
|
2021-05-25 19:35:19 +02:00
|
|
|
if (is_scalar($info_id) || is_array($info_id) && isset($info_id[count($info_id)-1]))
|
2001-07-15 00:16:16 +02:00
|
|
|
{
|
2011-04-11 11:29:39 +02:00
|
|
|
if (is_scalar($info_id) && !is_numeric($info_id))
|
|
|
|
{
|
|
|
|
$info_id = array('info_uid' => $info_id);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$info_id = array('info_id' => $info_id);
|
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2004-03-10 01:58:18 +01:00
|
|
|
|
2016-05-04 21:07:54 +02:00
|
|
|
if (!$info_id || ($data = $this->so->read($info_id)) === False)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2021-10-07 10:14:08 +02:00
|
|
|
$null = null;
|
|
|
|
return $null;
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2007-08-27 15:04:05 +02:00
|
|
|
|
2016-04-30 19:05:23 +02:00
|
|
|
if (!$ignore_acl && !$this->check_access($data,Acl::READ)) // check behind read, to prevent a double read
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2021-10-07 10:14:08 +02:00
|
|
|
$false = False;
|
|
|
|
return $false;
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2002-10-18 00:02:44 +02:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
if ($data['info_subject'] == $this->subject_from_des($data['info_des']))
|
|
|
|
{
|
|
|
|
$data['info_subject'] = '';
|
|
|
|
}
|
2017-01-16 21:58:52 +01:00
|
|
|
if ($run_link_id2from)
|
|
|
|
{
|
|
|
|
$this->link_id2from($data);
|
|
|
|
}
|
2010-02-09 22:56:39 +01:00
|
|
|
// convert server- to user-time
|
2024-05-03 19:55:47 +02:00
|
|
|
if ($date_format !== 'server')
|
2010-02-04 13:08:03 +01:00
|
|
|
{
|
2024-05-03 19:55:47 +02:00
|
|
|
$this->time2time($data, false, null, $date_format);
|
2010-02-09 22:56:39 +01:00
|
|
|
|
2010-02-04 13:08:03 +01:00
|
|
|
// pre-cache title and file access
|
|
|
|
self::set_link_cache($data);
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2008-10-19 13:34:12 +02:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Delete an infolog entry, evtl. incl. it's children / subs
|
|
|
|
*
|
2010-03-07 00:06:43 +01:00
|
|
|
* @param int|array $info_id int id
|
2006-10-04 19:40:33 +02:00
|
|
|
* @param boolean $delete_children should the children be deleted
|
2010-03-07 00:06:43 +01:00
|
|
|
* @param int|boolean $new_parent parent to use for not deleted children if > 0
|
2010-12-08 23:09:59 +01:00
|
|
|
* @param boolean $skip_notification Do not send notification of delete
|
2006-10-04 19:40:33 +02:00
|
|
|
* @return boolean True if delete was successful, False otherwise ($info_id does not exist or no rights)
|
|
|
|
*/
|
2010-12-08 23:09:59 +01:00
|
|
|
function delete($info_id,$delete_children=False,$new_parent=False, $skip_notification=False)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
|
|
|
if (is_array($info_id))
|
|
|
|
{
|
|
|
|
$info_id = (int)(isset($info_id[0]) ? $info_id[0] : (isset($info_id['info_id']) ? $info_id['info_id'] : $info_id['info_id']));
|
|
|
|
}
|
2011-04-11 11:29:39 +02:00
|
|
|
if (($info = $this->so->read(array('info_id' => $info_id), true, 'server')) === False)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
|
|
|
return False;
|
|
|
|
}
|
2016-04-30 19:05:23 +02:00
|
|
|
if (!$this->check_access($info,Acl::DELETE))
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
|
|
|
return False;
|
2001-07-12 01:17:32 +02:00
|
|
|
}
|
2007-06-13 23:37:05 +02:00
|
|
|
// check if we have children and delete or re-parent them
|
|
|
|
if (($children = $this->so->get_children($info_id)))
|
|
|
|
{
|
|
|
|
foreach($children as $id => $owner)
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
if ($delete_children && $this->so->grants[$owner] & Acl::DELETE)
|
2007-06-13 23:37:05 +02:00
|
|
|
{
|
2010-12-08 23:09:59 +01:00
|
|
|
$this->delete($id,$delete_children,$new_parent,$skip_notification); // call ourself recursive to delete the child
|
2007-06-13 23:37:05 +02:00
|
|
|
}
|
|
|
|
else // dont delete or no rights to delete the child --> re-parent it
|
|
|
|
{
|
|
|
|
$this->so->write(array(
|
|
|
|
'info_id' => $id,
|
|
|
|
'info_parent_id' => $new_parent,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$deleted = $info;
|
|
|
|
$deleted['info_status'] = 'deleted';
|
2010-02-05 17:32:30 +01:00
|
|
|
$deleted['info_datemodified'] = time();
|
2007-06-13 23:37:05 +02:00
|
|
|
$deleted['info_modifier'] = $this->user;
|
2001-07-12 01:17:32 +02:00
|
|
|
|
2007-06-13 23:37:05 +02:00
|
|
|
// if we have history switched on and not an already deleted item --> set only status deleted
|
2021-05-18 14:14:21 +02:00
|
|
|
if ($info['info_status'] != 'deleted')
|
2007-06-13 23:37:05 +02:00
|
|
|
{
|
|
|
|
$this->so->write($deleted);
|
2007-06-14 08:16:19 +02:00
|
|
|
|
2016-04-30 19:05:23 +02:00
|
|
|
Link::unlink(0,'infolog',$info_id,'','!file','',true); // keep the file attachments, hide the rest
|
2007-06-13 23:37:05 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$this->so->delete($info_id,false); // we delete the children via bo to get all notifications!
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2016-04-30 19:05:23 +02:00
|
|
|
Link::unlink(0,'infolog',$info_id);
|
2007-06-13 23:37:05 +02:00
|
|
|
}
|
|
|
|
if ($info['info_status'] != 'deleted') // dont notify of final purge of already deleted items
|
|
|
|
{
|
2020-07-23 21:34:08 +02:00
|
|
|
Link::notify_update('infolog',$info_id,$info, 'delete');
|
|
|
|
|
2007-06-13 23:37:05 +02:00
|
|
|
// send email notifications and do the history logging
|
2010-12-08 23:09:59 +01:00
|
|
|
if(!$skip_notification)
|
2007-06-13 23:37:05 +02:00
|
|
|
{
|
2010-12-08 23:09:59 +01:00
|
|
|
if (!is_object($this->tracking))
|
|
|
|
{
|
|
|
|
$this->tracking = new infolog_tracking($this);
|
|
|
|
}
|
|
|
|
$this->tracking->track($deleted,$info,$this->user,true);
|
2007-06-13 23:37:05 +02:00
|
|
|
}
|
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
return True;
|
|
|
|
}
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
|
|
|
* writes the given $values to InfoLog, a new entry gets created if info_id is not set or 0
|
|
|
|
*
|
|
|
|
* checks and asures ACL
|
|
|
|
*
|
2008-10-07 16:01:33 +02:00
|
|
|
* @param array &$values values to write
|
2015-04-17 11:39:22 +02:00
|
|
|
* @param boolean $check_defaults = true check and set certain defaults
|
|
|
|
* @param boolean|int $touch_modified = true touch the modification date and sets the modifier's user-id, 2: only modifier
|
|
|
|
* @param boolean $user2server = true conversion between user- and server-time necessary
|
|
|
|
* @param boolean $skip_notification = false true = do NOT send notification, false (default) = send notifications
|
|
|
|
* @param boolean $throw_exception = false Throw an exception (if required fields are not set)
|
|
|
|
* @param string $purge_cfs = null null=dont, 'ical'=only iCal X-properties (cfs name starting with "#"), 'all'=all cfs
|
2016-09-26 11:40:02 +02:00
|
|
|
* @param boolean $ignore_acl =true
|
2010-02-04 13:08:03 +01:00
|
|
|
*
|
2012-01-29 23:34:43 +01:00
|
|
|
* @return int|boolean info_id on a successfull write or false
|
2006-10-04 19:40:33 +02:00
|
|
|
*/
|
2012-01-29 23:34:43 +01:00
|
|
|
function write(&$values_in, $check_defaults=true, $touch_modified=true, $user2server=true,
|
2016-09-26 11:40:02 +02:00
|
|
|
$skip_notification=false, $throw_exception=false, $purge_cfs=null, $ignore_acl=false)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2011-04-12 13:53:34 +02:00
|
|
|
$values = $values_in;
|
2020-07-23 21:34:08 +02:00
|
|
|
$change_type = 'update';
|
2006-10-04 19:40:33 +02:00
|
|
|
//echo "boinfolog::write()values="; _debug_array($values);
|
2020-07-23 21:34:08 +02:00
|
|
|
if (!$ignore_acl && (!$values['info_id'] && !$this->check_access(0, Acl::EDIT, $values['info_owner']) &&
|
|
|
|
!$this->check_access(0, Acl::ADD, $values['info_owner'])))
|
2010-03-18 11:00:39 +01:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2012-01-26 02:49:56 +01:00
|
|
|
// we need to get the old values to update the links in customfields and for the tracking
|
|
|
|
if ($values['info_id'])
|
|
|
|
{
|
2016-09-29 16:55:25 +02:00
|
|
|
$old = $this->read($values['info_id'], false, 'server', $ignore_acl);
|
2012-01-26 02:49:56 +01:00
|
|
|
}
|
2020-07-23 21:34:08 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
$change_type = 'add';
|
|
|
|
}
|
2015-05-21 17:46:14 +02:00
|
|
|
|
2016-10-03 11:46:42 +02:00
|
|
|
if (($status_only = !$ignore_acl && $values['info_id'] && !$this->check_access($values,Acl::EDIT)))
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
|
|
|
if (!isset($values['info_responsible']))
|
2004-03-13 18:58:37 +01:00
|
|
|
{
|
2012-01-26 02:49:56 +01:00
|
|
|
$responsible = $old['info_responsible'];
|
2004-03-10 01:58:18 +01:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
else
|
2004-03-10 01:58:18 +01:00
|
|
|
{
|
2012-01-26 02:49:56 +01:00
|
|
|
$responsible = $values['info_responsible'];
|
2004-03-10 01:58:18 +01:00
|
|
|
}
|
2016-10-03 11:46:42 +02:00
|
|
|
if (!($status_only = in_array($this->user, (array)$responsible))) // responsible has implicit right to change status
|
2007-04-26 13:24:43 +02:00
|
|
|
{
|
2009-04-23 16:47:26 +02:00
|
|
|
$status_only = !!array_intersect((array)$responsible,array_keys($GLOBALS['egw']->accounts->memberships($this->user)));
|
2007-04-26 13:24:43 +02:00
|
|
|
}
|
2007-06-13 23:37:05 +02:00
|
|
|
if (!$status_only && $values['info_status'] != 'deleted')
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$status_only = $undelete = $this->check_access($values['info_id'],self::ACL_UNDELETE);
|
2007-06-13 23:37:05 +02:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2016-09-26 11:40:02 +02:00
|
|
|
if (!$ignore_acl && ($values['info_id'] && !$this->check_access($values['info_id'],Acl::EDIT) && !$status_only ||
|
|
|
|
!$values['info_id'] && $values['info_id_parent'] && !$this->check_access($values['info_id_parent'],Acl::ADD)))
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2010-03-15 10:55:16 +01:00
|
|
|
return false;
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2016-02-19 09:54:53 +01:00
|
|
|
|
2015-11-17 20:33:52 +01:00
|
|
|
// Make sure status is still valid if the type changes
|
|
|
|
if($old['info_type'] != $values['info_type'] && $values['info_status'])
|
|
|
|
{
|
2016-09-28 11:28:15 +02:00
|
|
|
if (isset($this->status[$values['info_type']]) &&
|
|
|
|
!in_array($values['info_status'], array_keys($this->status[$values['info_type']])))
|
2015-11-17 20:33:52 +01:00
|
|
|
{
|
|
|
|
$values['info_status'] = $this->status['defaults'][$values['info_type']];
|
|
|
|
}
|
|
|
|
}
|
2007-06-13 23:37:05 +02:00
|
|
|
if ($status_only && !$undelete) // make sure only status gets writen
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2008-10-07 14:50:14 +02:00
|
|
|
$set_completed = !$values['info_datecompleted'] && // set date completed of finished job, only if its not already set
|
2016-02-18 01:30:21 +01:00
|
|
|
in_array($values['info_status'],array('done','billed','cancelled'));
|
2006-10-04 19:40:33 +02:00
|
|
|
|
2020-10-19 18:41:47 +02:00
|
|
|
// Old is in server time, so change it to user time or we might move all the dates if tz are different
|
|
|
|
if($user2server)
|
|
|
|
{
|
|
|
|
$this->time2time($old);
|
|
|
|
}
|
|
|
|
|
2012-01-26 02:49:56 +01:00
|
|
|
$values = $old;
|
2020-10-19 18:41:47 +02:00
|
|
|
|
|
|
|
// This one stays in the timezone it's in or we fail the modified check
|
2012-01-26 02:49:56 +01:00
|
|
|
$values['info_datemodified'] = $values_in['info_datemodified'];
|
2020-10-19 18:41:47 +02:00
|
|
|
|
|
|
|
// only overwrite explicitly allowed fields
|
2010-03-07 00:06:43 +01:00
|
|
|
foreach ($this->responsible_edit as $name)
|
2004-03-10 01:58:18 +01:00
|
|
|
{
|
2012-01-26 02:49:56 +01:00
|
|
|
if (isset($values_in[$name])) $values[$name] = $values_in[$name];
|
2004-03-10 01:58:18 +01:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
if ($set_completed)
|
2004-03-10 01:58:18 +01:00
|
|
|
{
|
2010-02-04 13:08:03 +01:00
|
|
|
$values['info_datecompleted'] = $user2server ? $this->user_time_now : $this->now;
|
2009-07-15 22:04:17 +02:00
|
|
|
$values['info_percent'] = 100;
|
2009-04-23 16:47:26 +02:00
|
|
|
$forcestatus = true;
|
|
|
|
$status = 'done';
|
|
|
|
if (isset($values['info_type']) && !in_array($values['info_status'],array('done','billed','cancelled'))) {
|
|
|
|
$forcestatus = false;
|
2010-03-24 09:15:36 +01:00
|
|
|
//echo "set_completed:"; _debug_array($this->status[$values['info_type']]);
|
2009-04-23 16:47:26 +02:00
|
|
|
if (isset($this->status[$values['info_type']]['done'])) {
|
|
|
|
$forcestatus = true;
|
|
|
|
$status = 'done';
|
|
|
|
} elseif (isset($this->status[$values['info_type']]['billed'])) {
|
|
|
|
$forcestatus = true;
|
|
|
|
$status = 'billed';
|
|
|
|
} elseif (isset($this->status[$values['info_type']]['cancelled'])) {
|
|
|
|
$forcestatus = true;
|
|
|
|
$status = 'cancelled';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($forcestatus && !in_array($values['info_status'],array('done','billed','cancelled'))) $values['info_status'] = $status;
|
2004-03-10 01:58:18 +01:00
|
|
|
}
|
2010-03-15 10:55:16 +01:00
|
|
|
$check_defaults = false;
|
2020-07-23 21:34:08 +02:00
|
|
|
$change_type = 'update';
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
|
|
|
if ($check_defaults)
|
|
|
|
{
|
2008-10-07 14:50:14 +02:00
|
|
|
if (!$values['info_datecompleted'] &&
|
2016-02-18 01:30:21 +01:00
|
|
|
(in_array($values['info_status'],array('done','billed'))))
|
2001-07-15 00:16:16 +02:00
|
|
|
{
|
2010-02-04 13:08:03 +01:00
|
|
|
$values['info_datecompleted'] = $user2server ? $this->user_time_now : $this->now; // set date completed to today if status == done
|
2002-10-08 02:10:18 +02:00
|
|
|
}
|
2015-11-30 17:10:23 +01:00
|
|
|
// Check for valid status / percent combinations
|
2006-10-04 19:40:33 +02:00
|
|
|
if (in_array($values['info_status'],array('done','billed')))
|
2002-10-08 02:10:18 +02:00
|
|
|
{
|
2009-07-15 22:04:17 +02:00
|
|
|
$values['info_percent'] = 100;
|
2003-07-06 10:54:13 +02:00
|
|
|
}
|
2015-11-30 17:10:23 +01:00
|
|
|
else if (in_array($values['info_status'], array('not-started')))
|
|
|
|
{
|
|
|
|
$values['info_percent'] = 0;
|
|
|
|
}
|
2017-08-23 10:30:04 +02:00
|
|
|
else if (($values['info_status'] != 'archive' && $values['info_status'] != 'cancelled' &&
|
|
|
|
isset($this->stock_status[$values['info_type']]) && in_array($values['info_status'], $this->stock_status[$values['info_type']])) &&
|
2016-02-18 01:30:21 +01:00
|
|
|
((int)$values['info_percent'] == 100 || $values['info_percent'] == 0))
|
2015-11-30 17:10:23 +01:00
|
|
|
{
|
|
|
|
// We change percent to match status, not status to match percent
|
|
|
|
$values['info_percent'] = 10;
|
|
|
|
}
|
2009-09-04 14:39:23 +02:00
|
|
|
if ((int)$values['info_percent'] == 100 && !in_array($values['info_status'],array('done','billed','cancelled','archive')))
|
2005-02-07 08:09:33 +01:00
|
|
|
{
|
2009-04-23 16:47:26 +02:00
|
|
|
//echo "check_defaults:"; _debug_array($this->status[$values['info_type']]);
|
|
|
|
//$values['info_status'] = 'done';
|
|
|
|
$status = 'done';
|
|
|
|
if (isset($values['info_type'])) {
|
|
|
|
if (isset($this->status[$values['info_type']]['done'])) {
|
2011-06-15 19:32:12 +02:00
|
|
|
$status = 'done';
|
2009-04-23 16:47:26 +02:00
|
|
|
} elseif (isset($this->status[$values['info_type']]['billed'])) {
|
|
|
|
$status = 'billed';
|
|
|
|
} elseif (isset($this->status[$values['info_type']]['cancelled'])) {
|
|
|
|
$status = 'cancelled';
|
|
|
|
} else {
|
|
|
|
// since the comlete stati above do not exist for that type, dont change it
|
|
|
|
$status = $values['info_status'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$values['info_status'] = $status;
|
2005-02-07 08:09:33 +01:00
|
|
|
}
|
2007-04-26 09:56:38 +02:00
|
|
|
if ($values['info_responsible'] && $values['info_status'] == 'offer')
|
2003-07-06 10:54:13 +02:00
|
|
|
{
|
2006-10-04 19:40:33 +02:00
|
|
|
$values['info_status'] = 'not-started'; // have to match if not finished
|
2001-07-15 00:16:16 +02:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
if (isset($values['info_subject']) && empty($values['info_subject']))
|
2003-10-08 01:58:48 +02:00
|
|
|
{
|
2006-10-04 19:40:33 +02:00
|
|
|
$values['info_subject'] = $this->subject_from_des($values['info_des']);
|
2003-10-08 01:58:48 +02:00
|
|
|
}
|
2011-06-08 01:01:49 +02:00
|
|
|
|
|
|
|
// Check required custom fields
|
2012-02-24 10:29:27 +01:00
|
|
|
if($throw_exception)
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$custom = Api\Storage\Customfields::get('infolog');
|
2011-06-08 01:01:49 +02:00
|
|
|
foreach($custom as $c_name => $c_field)
|
|
|
|
{
|
2015-11-17 20:33:52 +01:00
|
|
|
if($c_field['type2']) $type2 = is_array($c_field['type2']) ? $c_field['type2'] : explode(',',$c_field['type2']);
|
2011-06-08 01:01:49 +02:00
|
|
|
if($c_field['needed'] && (!$c_field['type2'] || $c_field['type2'] && in_array($values['info_type'],$type2)))
|
|
|
|
{
|
|
|
|
// Required custom field
|
|
|
|
if(!$values['#'.$c_name])
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
throw new Api\Exception\WrongUserinput(lang('For infolog type %1, %2 is required',lang($values['info_type']),$c_field['label']));
|
2011-06-08 01:01:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2007-03-12 12:27:33 +01:00
|
|
|
if (isset($this->group_owners[$values['info_type']]))
|
|
|
|
{
|
|
|
|
$values['info_owner'] = $this->group_owners[$values['info_type']];
|
2016-09-28 15:50:23 +02:00
|
|
|
if (!$ignore_acl && !($this->grants[$this->group_owners[$values['info_type']]] & Acl::EDIT))
|
2007-03-12 12:27:33 +01:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
if (!$this->check_access($values['info_id'],Acl::EDIT) ||
|
|
|
|
!$values['info_id'] && !$this->check_access($values,Acl::ADD)
|
2011-12-07 16:28:32 +01:00
|
|
|
)
|
2011-12-07 00:30:48 +01:00
|
|
|
{
|
2011-12-07 16:28:32 +01:00
|
|
|
return false; // no edit rights from the group-owner and no implicit rights (delegated and sufficient rights)
|
2011-12-07 00:30:48 +01:00
|
|
|
}
|
|
|
|
}
|
2012-11-13 13:07:10 +01:00
|
|
|
$values['info_access'] = 'public'; // group-owners are allways public
|
2007-03-12 12:27:33 +01:00
|
|
|
}
|
|
|
|
elseif (!$values['info_id'] && !$values['info_owner'] || $GLOBALS['egw']->accounts->get_type($values['info_owner']) == 'g')
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
|
|
|
$values['info_owner'] = $this->so->user;
|
|
|
|
}
|
2010-02-04 13:08:03 +01:00
|
|
|
|
|
|
|
$to_write = $values;
|
|
|
|
if ($user2server)
|
|
|
|
{
|
2010-02-09 22:56:39 +01:00
|
|
|
// convert user- to server-time
|
|
|
|
$this->time2time($to_write, null, false);
|
2010-02-04 13:08:03 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// convert server- to user-time
|
2010-02-09 22:56:39 +01:00
|
|
|
$this->time2time($values);
|
2010-02-04 13:08:03 +01:00
|
|
|
}
|
|
|
|
|
2012-03-09 10:22:15 +01:00
|
|
|
if ($touch_modified && $touch_modified !== 2 || !$values['info_datemodified'])
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
|
|
|
// Should only an entry be updated which includes the original modification date?
|
|
|
|
// Used in the web-GUI to check against a modification by an other user while editing the entry.
|
|
|
|
// It's now disabled for xmlrpc, as otherwise the xmlrpc code need to be changed!
|
2009-07-15 22:04:17 +02:00
|
|
|
$xmlrpc = is_object($GLOBALS['server']) && $GLOBALS['server']->last_method;
|
2010-02-04 13:08:03 +01:00
|
|
|
$check_modified = $values['info_datemodified'] && !$xmlrpc ? $to_write['info_datemodified'] : false;
|
2023-07-11 21:34:06 +02:00
|
|
|
$values['info_datemodified'] = $this->user_time_now;
|
|
|
|
$to_write['info_datemodified'] = $this->now;
|
|
|
|
if($check_modified && isset($values['info_etag']))
|
2021-11-22 17:53:37 +01:00
|
|
|
{
|
|
|
|
++$values['info_etag'];
|
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
|
|
|
if ($touch_modified || !$values['info_modifier'])
|
|
|
|
{
|
2011-04-11 11:29:39 +02:00
|
|
|
$values['info_modifier'] = $to_write['info_modifier'] = $this->so->user;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set created and creator for new entries
|
|
|
|
if (!$values['info_id'])
|
|
|
|
{
|
|
|
|
$values['info_created'] = $this->user_time_now;
|
|
|
|
$to_write['info_created'] = $this->now;
|
|
|
|
$values['info_creator'] = $to_write['info_creator'] = $this->so->user;
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2009-04-23 16:47:26 +02:00
|
|
|
//_debug_array($values);
|
2009-12-07 10:00:58 +01:00
|
|
|
// error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n".array2string($values)."\n",3,'/tmp/infolog');
|
2010-02-04 13:08:03 +01:00
|
|
|
|
2016-10-04 11:30:02 +02:00
|
|
|
if (($info_id = $this->so->write($to_write, $check_modified, $purge_cfs, !isset($old))))
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2021-11-22 17:53:37 +01:00
|
|
|
if(!isset($values['info_type']) || $status_only || empty($values['caldav_name']))
|
2003-10-08 01:58:48 +02:00
|
|
|
{
|
2016-09-29 16:55:25 +02:00
|
|
|
$values = $this->read($info_id, true, 'server', $ignore_acl);
|
2023-07-11 21:34:06 +02:00
|
|
|
$this->time2time($values);
|
2003-10-08 01:58:48 +02:00
|
|
|
}
|
2015-08-18 13:45:59 +02:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
$values['info_id'] = $info_id;
|
2010-02-05 17:32:30 +01:00
|
|
|
$to_write['info_id'] = $info_id;
|
2014-01-28 10:22:12 +01:00
|
|
|
|
2021-11-09 22:02:10 +01:00
|
|
|
// if the info responsible array is not passed, fetch it from old.
|
|
|
|
if(!array_key_exists('info_responsible', $values))
|
2007-06-13 23:37:05 +02:00
|
|
|
{
|
2021-11-09 22:02:10 +01:00
|
|
|
$values['info_responsible'] = $old['info_responsible'];
|
|
|
|
}
|
|
|
|
if(!is_array($values['info_responsible'])) // this should not happen, bug it does ;-)
|
|
|
|
{
|
|
|
|
$values['info_responsible'] = $values['info_responsible'] ? explode(',', $values['info_responsible']) : array();
|
2010-02-05 17:32:30 +01:00
|
|
|
$to_write['info_responsible'] = $values['info_responsible'];
|
2007-06-13 23:37:05 +02:00
|
|
|
}
|
2016-12-05 18:51:17 +01:00
|
|
|
|
|
|
|
// writing links for a new entry
|
2021-11-09 22:02:10 +01:00
|
|
|
if(!$old && is_array($to_write['link_to']['to_id']) && count($to_write['link_to']['to_id']))
|
2016-12-05 18:51:17 +01:00
|
|
|
{
|
|
|
|
//echo "<p>writing links for new entry $info_id</p>\n"; _debug_array($content['link_to']['to_id']);
|
2021-11-09 22:02:10 +01:00
|
|
|
Link::link('infolog', $info_id, $to_write['link_to']['to_id']);
|
2016-12-05 18:51:17 +01:00
|
|
|
$values['link_to']['to_id'] = $info_id;
|
|
|
|
}
|
2021-11-09 22:02:10 +01:00
|
|
|
}
|
2021-11-22 17:53:37 +01:00
|
|
|
if ($values['info_id'] && $info_id)
|
2021-11-09 22:02:10 +01:00
|
|
|
{
|
2017-09-21 19:37:49 +02:00
|
|
|
$this->write_check_links($to_write);
|
2024-08-06 22:33:16 +02:00
|
|
|
if(!$values['info_link_id'] || $values['info_link_id'] != $to_write['info_link_id'] || $old['info_from'] != $to_write['info_from'])
|
2016-12-05 18:51:17 +01:00
|
|
|
{
|
2016-12-09 20:02:02 +01:00
|
|
|
// Just got a link ID, need to save it
|
2021-11-22 17:53:37 +01:00
|
|
|
unset($to_write['info_etag']); // we must not increment it again
|
2016-12-09 20:02:02 +01:00
|
|
|
$this->so->write($to_write);
|
2016-12-05 18:51:17 +01:00
|
|
|
$values['info_link_id'] = $to_write['info_link_id'];
|
2016-12-21 18:02:26 +01:00
|
|
|
$values['info_contact'] = $to_write['info_contact'];
|
2017-09-13 18:21:50 +02:00
|
|
|
$values['info_from'] = $to_write['info_from'];
|
2016-12-21 18:02:26 +01:00
|
|
|
$this->link_id2from($values);
|
2016-12-05 18:51:17 +01:00
|
|
|
}
|
2017-09-21 19:37:49 +02:00
|
|
|
$values['pm_id'] = $to_write['pm_id'];
|
2016-12-05 18:51:17 +01:00
|
|
|
|
|
|
|
if (($info_from_set = ($values['info_link_id'] && isset($values['info_from']) && empty($values['info_from']))))
|
|
|
|
{
|
|
|
|
$values['info_from'] = $to_write['info_from'] = $this->link_id2from($values);
|
|
|
|
}
|
2017-04-06 09:48:44 +02:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
// create (and remove) links in custom fields
|
2016-12-06 16:57:44 +01:00
|
|
|
if(!is_array($old))
|
|
|
|
{
|
|
|
|
$old = array();
|
|
|
|
}
|
2016-05-04 21:07:54 +02:00
|
|
|
Api\Storage\Customfields::update_links('infolog',$values,$old,'info_id');
|
2006-02-04 08:49:47 +01:00
|
|
|
|
2010-09-27 21:18:21 +02:00
|
|
|
// Check for restore of deleted entry, restore held links
|
|
|
|
if($old['info_status'] == 'deleted' && $values['info_status'] != 'deleted')
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
Link::restore('infolog', $info_id);
|
2010-09-27 21:18:21 +02:00
|
|
|
}
|
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
// notify the link-class about the update, as other apps may be subscribt to it
|
2020-07-23 21:34:08 +02:00
|
|
|
Link::notify_update('infolog',$info_id,$values, $change_type);
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2008-10-19 13:34:12 +02:00
|
|
|
// pre-cache the new values
|
|
|
|
self::set_link_cache($values);
|
|
|
|
|
2007-05-28 23:17:15 +02:00
|
|
|
// send email notifications and do the history logging
|
|
|
|
if (!is_object($this->tracking))
|
|
|
|
{
|
2009-06-08 18:21:14 +02:00
|
|
|
$this->tracking = new infolog_tracking($this);
|
2007-05-28 23:17:15 +02:00
|
|
|
}
|
2009-11-23 17:15:16 +01:00
|
|
|
|
2021-11-09 22:02:10 +01:00
|
|
|
if($old && ($missing_fields = array_diff_key($old, $values)))
|
2009-11-23 17:15:16 +01:00
|
|
|
{
|
2013-10-01 13:24:18 +02:00
|
|
|
// Some custom fields (multiselect with nothing selected) will be missing,
|
|
|
|
// and that's OK. Don't put them back.
|
2014-01-28 10:22:12 +01:00
|
|
|
foreach(array_keys($missing_fields) as $field)
|
2013-10-01 13:24:18 +02:00
|
|
|
{
|
|
|
|
if(array_key_exists($field, $values_in))
|
|
|
|
{
|
|
|
|
unset($missing_fields[$field]);
|
|
|
|
}
|
|
|
|
}
|
2021-11-09 22:02:10 +01:00
|
|
|
$values = array_merge($values, $missing_fields);
|
2010-04-12 16:12:58 +02:00
|
|
|
}
|
|
|
|
// Add keys missing in the $to_write array
|
2021-11-09 22:02:10 +01:00
|
|
|
if(($missing_fields = array_diff_key($values, $to_write)))
|
2010-04-12 16:12:58 +02:00
|
|
|
{
|
2021-11-09 22:02:10 +01:00
|
|
|
$to_write = array_merge($to_write, $missing_fields);
|
2009-11-23 17:15:16 +01:00
|
|
|
}
|
2021-11-09 22:02:10 +01:00
|
|
|
$this->tracking->track($to_write, $old, $this->user, $values['info_status'] == 'deleted' || $old['info_status'] == 'deleted',
|
|
|
|
null, $skip_notification
|
|
|
|
);
|
2001-10-07 22:11:32 +02:00
|
|
|
|
2020-10-19 18:41:47 +02:00
|
|
|
// Clear access cache after notifications, it may get modified as notifications switches user
|
|
|
|
unset(static::$access_cache[$info_id]);
|
|
|
|
|
2021-11-09 22:02:10 +01:00
|
|
|
if($info_from_set)
|
|
|
|
{
|
|
|
|
$values['info_from'] = '';
|
|
|
|
}
|
2023-06-07 18:26:59 +02:00
|
|
|
|
2011-04-12 13:53:34 +02:00
|
|
|
// merge changes (keeping extra values from the UI)
|
2021-11-09 22:02:10 +01:00
|
|
|
$values_in = array_merge($values_in, $values);
|
2014-08-26 01:43:32 +02:00
|
|
|
|
|
|
|
// Update modified timestamp of parent
|
2016-10-03 12:21:25 +02:00
|
|
|
if($values['info_id_parent'] && $touch_modified)
|
2014-08-26 01:43:32 +02:00
|
|
|
{
|
2017-11-06 23:16:08 +01:00
|
|
|
$parent = $this->read($values['info_id_parent'], true, 'server', true);
|
2016-10-03 12:21:25 +02:00
|
|
|
$this->write($parent, false, true, false, true, false, null, $ignore_acl);
|
2014-08-26 01:43:32 +02:00
|
|
|
}
|
2011-04-12 13:53:34 +02:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
return $info_id;
|
|
|
|
}
|
2001-07-14 23:44:01 +02:00
|
|
|
|
2016-12-05 18:51:17 +01:00
|
|
|
/**
|
|
|
|
* Check links when writing an infolog entry
|
|
|
|
*
|
|
|
|
* Checks for info_contact properly linked, project properly linked and
|
|
|
|
* adds or removes to correct.
|
|
|
|
*
|
2021-10-15 17:04:29 +02:00
|
|
|
* @param array $values
|
2016-12-05 18:51:17 +01:00
|
|
|
*/
|
2021-10-15 17:04:29 +02:00
|
|
|
protected function write_check_links(array &$values)
|
2016-12-05 18:51:17 +01:00
|
|
|
{
|
2021-10-15 17:36:37 +02:00
|
|
|
if(!$this->check_access($values, Acl::EDIT))
|
2021-10-15 17:04:29 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2016-12-21 18:02:26 +01:00
|
|
|
$old_link_id = (int)$values['info_link_id'];
|
2017-11-06 23:16:08 +01:00
|
|
|
$from = $values['info_from'];
|
|
|
|
|
2017-09-15 19:24:06 +02:00
|
|
|
if($values['info_contact'] && !(
|
|
|
|
is_array($values['info_contact']) && $values['info_contact']['id'] == 'none'
|
|
|
|
) || (
|
|
|
|
is_array($values['info_contact']) && $values['info_contact']['id'] == 'none' &&
|
|
|
|
array_key_exists('search', $values['info_contact'])
|
2021-10-15 17:04:29 +02:00
|
|
|
))
|
2016-12-05 18:51:17 +01:00
|
|
|
{
|
2016-12-22 18:49:08 +01:00
|
|
|
if(is_array($values['info_contact']))
|
2016-12-05 18:51:17 +01:00
|
|
|
{
|
2016-12-22 18:49:08 +01:00
|
|
|
// eTemplate2 returns the array all ready
|
|
|
|
$app = $values['info_contact']['app'];
|
2017-09-13 18:21:50 +02:00
|
|
|
$id = (int)$values['info_contact']['id'];
|
|
|
|
$from = $values['info_contact']['search'];
|
2016-12-22 18:49:08 +01:00
|
|
|
}
|
2021-10-15 17:04:29 +02:00
|
|
|
else if($values['info_contact'])
|
2016-12-22 18:49:08 +01:00
|
|
|
{
|
|
|
|
list($app, $id) = explode(':', $values['info_contact'], 2);
|
|
|
|
}
|
|
|
|
// if project has been removed, but is still info_contact --> also remove it
|
|
|
|
if ($app == 'projectmanager' && $id && $id == $values['old_pm_id'] && !$values['pm_id'])
|
|
|
|
{
|
2017-02-02 17:22:54 +01:00
|
|
|
unset($values['info_link_id'], $id, $values['info_contact']);
|
2016-12-22 18:49:08 +01:00
|
|
|
}
|
2017-09-13 18:21:50 +02:00
|
|
|
else if ($app && $id)
|
2016-12-22 18:49:08 +01:00
|
|
|
{
|
|
|
|
if(!is_array($values['link_to']))
|
|
|
|
{
|
|
|
|
$values['link_to'] = array();
|
|
|
|
}
|
|
|
|
$values['info_link_id'] = (int)($info_link_id = Link::link(
|
|
|
|
'infolog',
|
|
|
|
$values['info_id'],
|
|
|
|
$app,$id
|
|
|
|
));
|
2017-09-13 18:21:50 +02:00
|
|
|
$values['info_from'] = Link::title($app, $id);
|
2017-12-08 20:54:10 +01:00
|
|
|
if($values['pm_id'])
|
|
|
|
{
|
|
|
|
// They just changed the contact, don't clear the project
|
|
|
|
unset($old_link_id);
|
|
|
|
}
|
2017-09-13 18:21:50 +02:00
|
|
|
}
|
|
|
|
else if ($from)
|
|
|
|
{
|
|
|
|
$values['info_from'] = $from;
|
2016-12-22 18:49:08 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unset($values['info_link_id']);
|
2017-09-13 18:21:50 +02:00
|
|
|
$values['info_from'] = null;
|
2016-12-05 18:51:17 +01:00
|
|
|
}
|
2016-12-21 18:02:26 +01:00
|
|
|
}
|
2017-02-02 17:22:54 +01:00
|
|
|
else if ($values['pm_id'] && $values['info_id'] && !$values['old_pm_id'])
|
|
|
|
{
|
|
|
|
// Set for new entry with no contact
|
|
|
|
$app = 'projectmanager';
|
|
|
|
$id = $values['pm_id'];
|
|
|
|
$values['info_link_id'] = (int)($info_link_id = Link::link(
|
|
|
|
'infolog',
|
|
|
|
$values['info_id'],
|
|
|
|
$app,$id
|
|
|
|
));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unset($values['info_link_id']);
|
2017-11-06 23:16:08 +01:00
|
|
|
unset($values['info_contact']);
|
|
|
|
$values['info_from'] = $from ? $from : null;
|
2017-09-15 19:24:06 +02:00
|
|
|
}
|
|
|
|
if($values['info_id'] && $values['old_pm_id'] !== $values['pm_id'])
|
|
|
|
{
|
2017-09-26 18:30:15 +02:00
|
|
|
Link::unlink(0,'infolog',$values['info_id'],0,'projectmanager',$values['old_pm_id']);
|
2017-09-15 19:24:06 +02:00
|
|
|
// Project has changed, but link is not to project
|
|
|
|
if($values['pm_id'])
|
|
|
|
{
|
|
|
|
$link_id = Link::link('infolog', $values['info_id'], 'projectmanager', $values['pm_id']);
|
2021-11-09 22:02:10 +01:00
|
|
|
if(!$values['info_link_id'] || !Link::get_link($values['info_link_id']))
|
2017-09-15 19:24:06 +02:00
|
|
|
{
|
|
|
|
$values['info_link_id'] = $link_id;
|
|
|
|
}
|
|
|
|
}
|
2017-09-21 19:37:49 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// Project removed, but primary link is not to project
|
|
|
|
$values['pm_id'] = null;
|
|
|
|
}
|
2017-02-02 17:22:54 +01:00
|
|
|
}
|
2016-12-21 18:02:26 +01:00
|
|
|
if ($old_link_id && $old_link_id != $values['info_link_id'])
|
|
|
|
{
|
|
|
|
$link = Link::get_link($old_link_id);
|
|
|
|
// remove selected project, if removed link is that project
|
|
|
|
if($link['link_app2'] == 'projectmanager' && $link['link_id2'] == $values['old_pm_id'])
|
2016-12-05 18:51:17 +01:00
|
|
|
{
|
2016-12-21 18:02:26 +01:00
|
|
|
unset($values['pm_id'], $values['old_pm_id']);
|
2016-12-05 18:51:17 +01:00
|
|
|
}
|
2016-12-21 18:02:26 +01:00
|
|
|
Link::unlink($old_link_id);
|
|
|
|
}
|
2017-12-05 17:44:55 +01:00
|
|
|
// if linked to a project and no other project selected, also add as project
|
|
|
|
$links = Link::get_links('infolog', $values['info_id'], 'projectmanager');
|
|
|
|
if (!$values['pm_id'] && count($links))
|
2016-12-21 18:02:26 +01:00
|
|
|
{
|
2017-12-05 17:44:55 +01:00
|
|
|
$values['old_pm_id'] = $values['pm_id'] = array_pop($links);
|
2016-12-05 18:51:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
2008-10-19 13:34:12 +02:00
|
|
|
* Query the number of children / subs for one or more info_id's
|
2006-10-04 19:40:33 +02:00
|
|
|
*
|
2008-10-19 13:34:12 +02:00
|
|
|
* @param int|array $info_id id
|
|
|
|
* @return int|array number of subs
|
2006-10-04 19:40:33 +02:00
|
|
|
*/
|
|
|
|
function anzSubs( $info_id )
|
|
|
|
{
|
|
|
|
return $this->so->anzSubs( $info_id );
|
|
|
|
}
|
2006-08-23 21:03:25 +02:00
|
|
|
|
2021-05-31 10:38:31 +02:00
|
|
|
/**
|
|
|
|
* Total returned, if search used limit modified optimization
|
|
|
|
*/
|
|
|
|
const LIMIT_MODIFIED_TOTAL = 9999;
|
|
|
|
/**
|
|
|
|
* Set 2^N to automatic retry N times, if limit modified optimization did not return enough rows
|
|
|
|
*/
|
|
|
|
const LIMIT_MODIFIED_RETRY = 8;
|
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
|
|
|
* searches InfoLog for a certain pattern in $query
|
|
|
|
*
|
|
|
|
* @param $query[order] column-name to sort after
|
|
|
|
* @param $query[sort] sort-order DESC or ASC
|
|
|
|
* @param $query[filter] string with combination of acl-, date- and status-filters, eg. 'own-open-today' or ''
|
|
|
|
* @param $query[cat_id] category to use or 0 or unset
|
|
|
|
* @param $query[search] pattern to search, search is done in info_from, info_subject and info_des
|
|
|
|
* @param $query[action] / $query[action_id] if only entries linked to a specified app/entry show be used
|
|
|
|
* @param &$query[start], &$query[total] nextmatch-parameters will be used and set if query returns less entries
|
|
|
|
* @param $query[col_filter] array with column-name - data pairs, data == '' means no filter (!)
|
2016-09-26 11:40:02 +02:00
|
|
|
* @param boolean $no_acl =false true: ignore all acl
|
2006-10-04 19:40:33 +02:00
|
|
|
* @return array with id's as key of the matching log-entries
|
|
|
|
*/
|
2016-09-26 11:40:02 +02:00
|
|
|
function &search(&$query, $no_acl=false)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2011-04-11 11:29:39 +02:00
|
|
|
//error_log(__METHOD__.'('.array2string($query).')');
|
2011-11-24 18:56:05 +01:00
|
|
|
|
|
|
|
if($query['filter'] == 'bydate')
|
|
|
|
{
|
|
|
|
if (is_int($query['startdate'])) $query['col_filter'][] = 'info_startdate >= '.$GLOBALS['egw']->db->quote($query['startdate']);
|
|
|
|
if (is_int($query['enddate'])) $query['col_filter'][] = 'info_startdate <= '.$GLOBALS['egw']->db->quote($query['enddate']+(60*60*24)-1);
|
|
|
|
}
|
2014-03-06 23:12:50 +01:00
|
|
|
elseif ($query['filter'] == 'duedate')
|
|
|
|
{
|
|
|
|
if (is_int($query['startdate'])) $query['col_filter'][] = 'info_enddate >= '.$GLOBALS['egw']->db->quote($query['startdate']);
|
|
|
|
if (is_int($query['enddate'])) $query['col_filter'][] = 'info_enddate <= '.$GLOBALS['egw']->db->quote($query['enddate']+(60*60*24)-1);
|
|
|
|
}
|
2014-09-24 00:48:11 +02:00
|
|
|
elseif ($query['filter'] == 'private')
|
|
|
|
{
|
|
|
|
$query['col_filter'][] = 'info_access = ' . $GLOBALS['egw']->db->quote('private');
|
|
|
|
}
|
2010-03-16 08:00:56 +01:00
|
|
|
if (!isset($query['date_format']) || $query['date_format'] != 'server')
|
2010-02-04 13:08:03 +01:00
|
|
|
{
|
2010-03-16 08:00:56 +01:00
|
|
|
if (isset($query['col_filter']))
|
2010-03-15 19:05:33 +01:00
|
|
|
{
|
2010-03-16 08:00:56 +01:00
|
|
|
foreach ($this->timestamps as $key)
|
|
|
|
{
|
|
|
|
if (!empty($query['col_filter'][$key]))
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$query['col_filter'][$key] = Api\DateTime::user2server($query['col_filter'][$key],'ts');
|
2010-03-16 08:00:56 +01:00
|
|
|
}
|
|
|
|
}
|
2010-03-15 19:05:33 +01:00
|
|
|
}
|
2010-02-04 13:08:03 +01:00
|
|
|
}
|
2010-03-07 00:06:43 +01:00
|
|
|
|
2021-05-31 10:38:31 +02:00
|
|
|
$q = $query;
|
|
|
|
unset($q['limit_modified_n_month']);
|
|
|
|
for($n = 1; $n <= self::LIMIT_MODIFIED_RETRY; $n *= 2)
|
|
|
|
{
|
2021-05-31 17:11:58 +02:00
|
|
|
// apply modified limit only if requested AND we're sorting by modified AND NOT (searching, CRM-view, ...)
|
|
|
|
if (!empty($query['limit_modified_n_month']) && empty($query['search']) && // no search
|
|
|
|
empty($query['action']) && empty($query['action_id']) && empty($query['info_id']) && // no CRM view
|
2021-05-31 10:38:31 +02:00
|
|
|
$query['order'] === 'info_datemodified' && $query['sort'] === 'DESC' &&
|
|
|
|
isset($query['start']))
|
|
|
|
{
|
|
|
|
$q['col_filter'][99] = 'info_datemodified > '.
|
|
|
|
(new Api\DateTime((-$n*$query['limit_modified_n_month']).' month'))->format('server');
|
|
|
|
}
|
|
|
|
$ret = $this->so->search($q, $no_acl);
|
2021-05-31 17:11:58 +02:00
|
|
|
$this->total = $query['total'] = $q['total'];
|
2021-05-31 10:38:31 +02:00
|
|
|
if (!isset($q['col_filter'][99]) || count($ret) >= $query['num_rows'])
|
|
|
|
{
|
|
|
|
if (isset($q['col_filter'][99]))
|
|
|
|
{
|
2021-05-31 17:11:58 +02:00
|
|
|
$this->total = $query['total'] = self::LIMIT_MODIFIED_TOTAL;
|
2021-05-31 10:38:31 +02:00
|
|
|
}
|
|
|
|
break; // --> no modified limit, or got enough rows
|
|
|
|
}
|
|
|
|
// last retry without limit
|
|
|
|
if (2*$n === self::LIMIT_MODIFIED_RETRY)
|
|
|
|
{
|
|
|
|
unset($q['col_filter'][99], $query['limit_modified_n_month']);
|
|
|
|
}
|
|
|
|
}
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2008-10-19 13:34:12 +02:00
|
|
|
if (is_array($ret))
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2010-03-07 00:06:43 +01:00
|
|
|
foreach ($ret as $id => &$data)
|
2006-08-23 21:03:25 +02:00
|
|
|
{
|
2016-09-26 11:40:02 +02:00
|
|
|
if (!$no_acl && !$this->check_access($data,Acl::READ))
|
2006-08-23 21:03:25 +02:00
|
|
|
{
|
2010-02-09 22:56:39 +01:00
|
|
|
unset($ret[$id]);
|
|
|
|
continue;
|
2006-08-23 21:03:25 +02:00
|
|
|
}
|
2010-02-09 22:56:39 +01:00
|
|
|
// convert system- to user-time
|
2010-03-07 00:06:43 +01:00
|
|
|
foreach ($this->timestamps as $key)
|
2010-02-04 13:08:03 +01:00
|
|
|
{
|
2010-02-09 22:56:39 +01:00
|
|
|
if ($data[$key])
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$time = new Api\DateTime($data[$key], Api\DateTime::$server_timezone);
|
2010-03-16 08:00:56 +01:00
|
|
|
if (!isset($query['date_format']) || $query['date_format'] != 'server')
|
2010-02-09 22:56:39 +01:00
|
|
|
{
|
2010-03-16 08:00:56 +01:00
|
|
|
if ($time->format('Hi') == '0000')
|
|
|
|
{
|
|
|
|
// we keep dates the same in user-time
|
2016-04-30 19:05:23 +02:00
|
|
|
$arr = Api\DateTime::to($time,'array');
|
|
|
|
$time = new Api\DateTime($arr, Api\DateTime::$user_timezone);
|
2010-03-16 08:00:56 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$time->setTimezone(Api\DateTime::$user_timezone);
|
2010-03-16 08:00:56 +01:00
|
|
|
}
|
2010-02-09 22:56:39 +01:00
|
|
|
}
|
2016-04-30 19:05:23 +02:00
|
|
|
$data[$key] = Api\DateTime::to($time,'ts');
|
2010-02-09 22:56:39 +01:00
|
|
|
}
|
2010-02-04 13:08:03 +01:00
|
|
|
}
|
2008-10-19 13:34:12 +02:00
|
|
|
// pre-cache title and file access
|
|
|
|
self::set_link_cache($data);
|
2006-08-23 21:03:25 +02:00
|
|
|
}
|
2005-11-12 14:25:59 +01:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
//echo "<p>boinfolog::search(".print_r($query,True).")=<pre>".print_r($ret,True)."</pre>\n";
|
|
|
|
return $ret;
|
|
|
|
}
|
2002-09-02 10:57:35 +02:00
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
2011-09-28 14:37:06 +02:00
|
|
|
* Query ctag for infolog
|
|
|
|
*
|
2015-04-17 11:39:22 +02:00
|
|
|
* @param array $filter = array('filter'=>'own','info_type'=>'task')
|
2011-09-28 14:37:06 +02:00
|
|
|
* @return string
|
|
|
|
*/
|
2011-09-29 08:17:42 +02:00
|
|
|
public function getctag(array $filter=array('filter'=>'own','info_type'=>'task'))
|
2011-09-28 14:37:06 +02:00
|
|
|
{
|
|
|
|
$filter += array(
|
|
|
|
'order' => 'info_datemodified',
|
|
|
|
'sort' => 'DESC',
|
|
|
|
'date_format' => 'server',
|
|
|
|
'start' => 0,
|
|
|
|
'num_rows' => 1,
|
|
|
|
);
|
2012-09-24 10:53:41 +02:00
|
|
|
// we need to query deleted entries too for a ctag!
|
|
|
|
$filter['filter'] .= '+deleted';
|
2011-09-28 14:37:06 +02:00
|
|
|
|
|
|
|
$result =& $this->search($filter);
|
|
|
|
|
|
|
|
if (empty($result)) return 'EGw-empty-wGE';
|
|
|
|
|
|
|
|
$entry = array_shift($result);
|
|
|
|
|
2011-10-11 19:30:15 +02:00
|
|
|
return $entry['info_datemodified'];
|
2011-09-28 14:37:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2006-10-04 19:40:33 +02:00
|
|
|
* imports a mail identified by uid as infolog
|
|
|
|
*
|
|
|
|
* @author Cornelius Weiss <nelius@cwtech.de>
|
|
|
|
* @todo search if infolog with from and subject allready exists ->appned body & inform user
|
2015-04-15 13:23:59 +02:00
|
|
|
* @param array $_addresses array of addresses
|
|
|
|
* - array (email,name)
|
2006-10-04 19:40:33 +02:00
|
|
|
* @param string $_subject
|
|
|
|
* @param string $_message
|
|
|
|
* @param array $_attachments
|
|
|
|
* @param string $_date
|
|
|
|
* @return array $content array for uiinfolog
|
|
|
|
*/
|
2015-04-15 13:23:59 +02:00
|
|
|
function import_mail($_addresses,$_subject,$_message,$_attachments,$_date)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2021-11-20 08:36:35 +01:00
|
|
|
$names = $emails = [];
|
2015-04-15 13:23:59 +02:00
|
|
|
foreach($_addresses as $address)
|
2002-09-02 10:57:35 +02:00
|
|
|
{
|
2015-04-15 13:23:59 +02:00
|
|
|
$names[] = $address['name'];
|
|
|
|
$emails[] =$address['email'];
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2015-08-18 13:45:59 +02:00
|
|
|
|
2007-09-13 10:12:56 +02:00
|
|
|
$type = isset($this->enums['type']['email']) ? 'email' : 'note';
|
2007-09-13 11:17:47 +02:00
|
|
|
$status = isset($this->status['defaults'][$type]) ? $this->status['defaults'][$type] : 'done';
|
2006-10-04 19:40:33 +02:00
|
|
|
$info = array(
|
|
|
|
'info_id' => 0,
|
2007-09-13 10:12:56 +02:00
|
|
|
'info_type' => $type,
|
2021-11-20 08:36:35 +01:00
|
|
|
'info_from' => implode(', ', $names) . implode(', ', $emails),
|
2006-10-04 19:40:33 +02:00
|
|
|
'info_subject' => $_subject,
|
|
|
|
'info_des' => $_message,
|
2016-04-30 19:05:23 +02:00
|
|
|
'info_startdate' => Api\DateTime::server2user($_date),
|
2007-09-13 11:17:47 +02:00
|
|
|
'info_status' => $status,
|
2006-10-04 19:40:33 +02:00
|
|
|
'info_priority' => 1,
|
2007-09-13 11:17:47 +02:00
|
|
|
'info_percent' => $status == 'done' ? 100 : 0,
|
2006-10-04 19:40:33 +02:00
|
|
|
'referer' => false,
|
|
|
|
'link_to' => array(
|
|
|
|
'to_app' => 'infolog',
|
|
|
|
'to_id' => 0,
|
|
|
|
),
|
|
|
|
);
|
2015-01-23 15:25:40 +01:00
|
|
|
if ($GLOBALS['egw_info']['user']['preferences']['infolog']['cat_add_default']) $info['info_cat'] = $GLOBALS['egw_info']['user']['preferences']['infolog']['cat_add_default'];
|
2006-10-04 19:40:33 +02:00
|
|
|
// find the addressbookentry to link with
|
2016-04-30 19:05:23 +02:00
|
|
|
$addressbook = new Api\Contacts();
|
2006-10-04 19:40:33 +02:00
|
|
|
$contacts = array();
|
2015-04-15 13:23:59 +02:00
|
|
|
foreach ($emails as $mailadr)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
|
|
|
$contacts = array_merge($contacts,(array)$addressbook->search(
|
|
|
|
array(
|
|
|
|
'email' => $mailadr,
|
|
|
|
'email_home' => $mailadr
|
2023-08-16 22:56:16 +02:00
|
|
|
), ['id', 'account_id'], '', '', '', false, 'OR', false, null, '', false
|
|
|
|
)
|
|
|
|
);
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2006-10-17 09:13:12 +02:00
|
|
|
if (!$contacts || !is_array($contacts) || !is_array($contacts[0]))
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2017-09-13 18:21:50 +02:00
|
|
|
$info['msg'] = lang('Attention: No Contact with address %1 found.',$info['info_from']);
|
2006-10-17 09:13:12 +02:00
|
|
|
$info['info_custom_from'] = true; // show the info_from line and NOT only the link
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2008-10-07 14:50:14 +02:00
|
|
|
else
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2024-06-25 23:50:27 +02:00
|
|
|
// Remove all accounts
|
|
|
|
$contacts = array_filter($contacts, function ($v)
|
|
|
|
{
|
|
|
|
return empty($v['account_id']);
|
|
|
|
});
|
|
|
|
|
2006-10-17 09:13:12 +02:00
|
|
|
// create the first address as info_contact
|
2024-06-25 23:50:27 +02:00
|
|
|
if(count($contacts) > 0)
|
|
|
|
{
|
|
|
|
$contact = array_shift($contacts);
|
|
|
|
$info['info_contact'] = 'addressbook:' . $contact['id'];
|
|
|
|
}
|
2023-08-16 22:56:16 +02:00
|
|
|
// create the rest as "ordinary" links, skipping accounts
|
2006-10-17 09:13:12 +02:00
|
|
|
foreach ($contacts as $contact)
|
2002-09-02 10:57:35 +02:00
|
|
|
{
|
2024-06-25 23:50:27 +02:00
|
|
|
Link::link('infolog', $info['link_to']['to_id'], 'addressbook', $contact['id']);
|
2002-09-02 10:57:35 +02:00
|
|
|
}
|
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
if (is_array($_attachments))
|
2003-09-07 18:55:36 +02:00
|
|
|
{
|
2006-10-04 19:40:33 +02:00
|
|
|
foreach ($_attachments as $attachment)
|
2003-09-07 18:55:36 +02:00
|
|
|
{
|
2015-04-15 13:23:59 +02:00
|
|
|
if($attachment['egw_data'])
|
2009-06-22 16:46:10 +02:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
Link::link('infolog',$info['link_to']['to_id'],Link::DATA_APPNAME, $attachment);
|
2006-10-17 09:13:12 +02:00
|
|
|
}
|
2015-08-27 12:12:55 +02:00
|
|
|
else if(is_readable($attachment['tmp_name']) ||
|
2016-04-30 19:05:23 +02:00
|
|
|
(Vfs::is_readable($attachment['tmp_name']) && parse_url($attachment['tmp_name'], PHP_URL_SCHEME) === 'vfs'))
|
2015-04-17 11:39:22 +02:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
Link::link('infolog',$info['link_to']['to_id'],'file', $attachment);
|
2015-04-17 11:39:22 +02:00
|
|
|
}
|
2003-09-07 18:55:36 +02:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
2008-10-07 14:50:14 +02:00
|
|
|
return $info;
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get title for an infolog entry identified by $info
|
2008-10-07 14:50:14 +02:00
|
|
|
*
|
2006-10-04 19:40:33 +02:00
|
|
|
* Is called as hook to participate in the linking
|
|
|
|
*
|
2010-03-07 00:06:43 +01:00
|
|
|
* @param int|array $info int info_id or array with infolog entry
|
|
|
|
* @return string|boolean string with the title, null if $info not found, false if no perms to view
|
2006-10-04 19:40:33 +02:00
|
|
|
*/
|
2010-02-04 13:08:03 +01:00
|
|
|
function link_title($info)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
|
|
|
if (!is_array($info))
|
|
|
|
{
|
|
|
|
$info = $this->read( $info,false );
|
|
|
|
}
|
|
|
|
if (!$info)
|
|
|
|
{
|
|
|
|
return $info;
|
|
|
|
}
|
2010-08-23 13:44:30 +02:00
|
|
|
$title = !empty($info['info_subject']) ? $info['info_subject'] :self::subject_from_des($info['info_descr']);
|
|
|
|
return $title.($GLOBALS['egw_info']['user']['preferences']['infolog']['show_id']?' (#'.$info['info_id'].')':'');
|
2008-03-08 22:43:13 +01:00
|
|
|
}
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2008-03-08 22:43:13 +01:00
|
|
|
/**
|
|
|
|
* Return multiple titles fetched by a single query
|
|
|
|
*
|
|
|
|
* @param array $ids
|
|
|
|
*/
|
2010-02-04 13:08:03 +01:00
|
|
|
function link_titles(array $ids)
|
2008-03-08 22:43:13 +01:00
|
|
|
{
|
|
|
|
$titles = array();
|
2021-03-28 20:48:55 +02:00
|
|
|
$params = array(
|
2008-03-08 22:43:13 +01:00
|
|
|
'col_filter' => array('info_id' => $ids),
|
2021-03-28 20:48:55 +02:00
|
|
|
);
|
|
|
|
foreach ($this->search($params) as $info)
|
2008-03-08 22:43:13 +01:00
|
|
|
{
|
2008-04-01 17:46:06 +02:00
|
|
|
$titles[$info['info_id']] = $this->link_title($info);
|
2008-03-08 22:43:13 +01:00
|
|
|
}
|
2010-03-07 00:06:43 +01:00
|
|
|
foreach (array_diff($ids,array_keys($titles)) as $id)
|
2008-03-08 22:43:13 +01:00
|
|
|
{
|
|
|
|
$titles[$id] = false; // we assume every not returned entry to be not readable, as we notify the link class about all deletes
|
|
|
|
}
|
|
|
|
return $titles;
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* query infolog for entries matching $pattern
|
|
|
|
*
|
|
|
|
* Is called as hook to participate in the linking
|
|
|
|
*
|
|
|
|
* @param string $pattern pattern to search
|
2009-12-08 22:47:49 +01:00
|
|
|
* @param array $options Array of options for the search
|
2006-10-04 19:40:33 +02:00
|
|
|
* @return array with info_id - title pairs of the matching entries
|
|
|
|
*/
|
2010-02-04 13:08:03 +01:00
|
|
|
function link_query($pattern, Array &$options = array())
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
|
|
|
$query = array(
|
|
|
|
'search' => $pattern,
|
2009-12-08 22:47:49 +01:00
|
|
|
'start' => $options['start'],
|
|
|
|
'num_rows' => $options['num_rows'],
|
2006-10-04 19:40:33 +02:00
|
|
|
'subs' => true,
|
|
|
|
);
|
|
|
|
$ids = $this->search($query);
|
2009-12-08 22:47:49 +01:00
|
|
|
$options['total'] = $query['total'];
|
2006-10-04 19:40:33 +02:00
|
|
|
$content = array();
|
|
|
|
if (is_array($ids))
|
|
|
|
{
|
2014-01-28 10:22:12 +01:00
|
|
|
foreach(array_keys($ids) as $id)
|
2003-09-14 12:25:05 +02:00
|
|
|
{
|
2006-10-04 19:40:33 +02:00
|
|
|
$content[$id] = $this->link_title($id);
|
2003-09-14 12:25:05 +02:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
|
|
|
return $content;
|
|
|
|
}
|
2003-09-14 12:25:05 +02:00
|
|
|
|
2008-10-07 14:50:14 +02:00
|
|
|
/**
|
2011-06-26 15:11:00 +02:00
|
|
|
* Check access to the file store
|
2008-10-07 14:50:14 +02:00
|
|
|
*
|
2008-10-19 13:34:12 +02:00
|
|
|
* @param int|array $id id of entry or entry array
|
2016-04-30 19:05:23 +02:00
|
|
|
* @param int $check Acl::READ for read and Acl::EDIT for write or delete access
|
2015-04-17 11:39:22 +02:00
|
|
|
* @param string $rel_path = null currently not used in InfoLog
|
|
|
|
* @param int $user = null for which user to check, default current user
|
2008-10-07 14:50:14 +02:00
|
|
|
* @return boolean true if access is granted or false otherwise
|
|
|
|
*/
|
2011-06-26 14:32:06 +02:00
|
|
|
function file_access($id,$check,$rel_path=null,$user=null)
|
2008-10-07 14:50:14 +02:00
|
|
|
{
|
2014-01-28 10:22:12 +01:00
|
|
|
unset($rel_path); // not used
|
2011-06-26 14:32:06 +02:00
|
|
|
return $this->check_access($id,$check,0,$user);
|
2008-10-07 14:50:14 +02:00
|
|
|
}
|
|
|
|
|
2008-10-19 13:34:12 +02:00
|
|
|
/**
|
|
|
|
* Set the cache of the link class (title, file_access) for the given infolog entry
|
|
|
|
*
|
|
|
|
* @param array $info
|
|
|
|
*/
|
|
|
|
function set_link_cache(array $info)
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
Link::set_cache('infolog',$info['info_id'],
|
2008-10-19 13:34:12 +02:00
|
|
|
$this->link_title($info),
|
2022-05-12 15:16:16 +02:00
|
|
|
$this->file_access($info,Acl::EDIT) ? Acl::READ|Acl::EDIT :
|
2016-04-30 19:05:23 +02:00
|
|
|
($this->file_access($info,Acl::READ) ? Acl::READ : 0));
|
2008-10-19 13:34:12 +02:00
|
|
|
}
|
|
|
|
|
2006-10-04 19:40:33 +02:00
|
|
|
/**
|
|
|
|
* hook called be calendar to include events or todos in the cal-dayview
|
|
|
|
*
|
|
|
|
* @param int $args[year], $args[month], $args[day] date of the events
|
|
|
|
* @param int $args[owner] owner of the events
|
|
|
|
* @param string $args[location] calendar_include_{events|todos}
|
|
|
|
* @return array of events (array with keys starttime, endtime, title, view, icon, content)
|
|
|
|
*/
|
|
|
|
function cal_to_include($args)
|
|
|
|
{
|
|
|
|
//echo "<p>cal_to_include("; print_r($args); echo ")</p>\n";
|
|
|
|
$user = (int) $args['owner'];
|
|
|
|
if ($user <= 0 && !checkdate($args['month'],$args['day'],$args['year']))
|
|
|
|
{
|
|
|
|
return False;
|
|
|
|
}
|
2016-04-30 19:05:23 +02:00
|
|
|
Api\Translation::add_app('infolog');
|
2006-10-04 19:40:33 +02:00
|
|
|
|
|
|
|
$do_events = $args['location'] == 'calendar_include_events';
|
|
|
|
$to_include = array();
|
|
|
|
$date_wanted = sprintf('%04d/%02d/%02d',$args['year'],$args['month'],$args['day']);
|
|
|
|
$query = array(
|
2017-03-23 16:00:13 +01:00
|
|
|
'order' => $args['order'] ? $args['order'] : 'info_startdate',
|
|
|
|
'sort' => $args['sort'] ? $args['sort'] : ($do_events ? 'ASC' : 'DESC'),
|
2006-10-04 19:40:33 +02:00
|
|
|
'filter'=> "user$user".($do_events ? 'date' : 'opentoday').$date_wanted,
|
|
|
|
'start' => 0,
|
|
|
|
);
|
2015-04-13 21:08:54 +02:00
|
|
|
if ($GLOBALS['egw_info']['user']['preferences']['infolog']['cal_show'] || $GLOBALS['egw_info']['user']['preferences']['infolog']['cal_show'] === '0')
|
2007-10-09 11:39:40 +02:00
|
|
|
{
|
|
|
|
$query['col_filter']['info_type'] = explode(',',$GLOBALS['egw_info']['user']['preferences']['infolog']['cal_show']);
|
|
|
|
}
|
|
|
|
elseif ($this->customfields && !$GLOBALS['egw_info']['user']['preferences']['infolog']['cal_show_custom'])
|
2006-10-24 13:58:14 +02:00
|
|
|
{
|
|
|
|
$query['col_filter']['info_type'] = array('task','phone','note','email');
|
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
while ($infos = $this->search($query))
|
|
|
|
{
|
2010-03-07 00:06:43 +01:00
|
|
|
foreach ($infos as $info)
|
2003-09-07 18:55:36 +02:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$start = new Api\DateTime($info['info_startdate'],Api\DateTime::$user_timezone);
|
2016-05-04 21:07:54 +02:00
|
|
|
$title = ($do_events ? $start->format(false).' ' : '').
|
2006-10-04 19:40:33 +02:00
|
|
|
$info['info_subject'];
|
2016-04-30 19:05:23 +02:00
|
|
|
$view = Link::view('infolog',$info['info_id']);
|
2014-01-28 10:22:12 +01:00
|
|
|
$size = null;
|
2016-04-30 19:05:23 +02:00
|
|
|
$edit = Link::edit('infolog',$info['info_id'], $size);
|
2010-12-10 21:04:59 +01:00
|
|
|
$edit['size'] = $size;
|
2006-10-04 19:40:33 +02:00
|
|
|
$content=array();
|
2015-12-28 18:59:47 +01:00
|
|
|
$status = $this->status[$info['info_type']][$info['info_status']];
|
|
|
|
$icons = array();
|
|
|
|
foreach(array(
|
|
|
|
$info['info_type'] => 'navbar',
|
|
|
|
$status => 'status'
|
|
|
|
) as $icon => $default)
|
2003-09-07 18:55:36 +02:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$icons[Api\Image::find('infolog',$icon) ? $icon : $default] = $icon;
|
2003-09-07 18:55:36 +02:00
|
|
|
}
|
2016-04-30 19:05:23 +02:00
|
|
|
$content[] = Api\Html::a_href($title,$view);
|
|
|
|
$html = Api\Html::table(array(1 => $content));
|
2006-10-04 19:40:33 +02:00
|
|
|
|
|
|
|
$to_include[] = array(
|
|
|
|
'starttime' => $info['info_startdate'],
|
|
|
|
'endtime' => ($info['info_enddate'] ? $info['info_enddate'] : $info['info_startdate']),
|
|
|
|
'title' => $title,
|
|
|
|
'view' => $view,
|
2010-12-10 21:04:59 +01:00
|
|
|
'edit' => $edit,
|
2006-10-04 19:40:33 +02:00
|
|
|
'icons' => $icons,
|
2014-01-28 10:22:12 +01:00
|
|
|
'content' => $html,
|
2006-10-04 19:40:33 +02:00
|
|
|
);
|
2003-09-07 18:55:36 +02:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
if ($query['total'] <= ($query['start']+=count($infos)))
|
2004-03-10 01:58:18 +01:00
|
|
|
{
|
2006-10-04 19:40:33 +02:00
|
|
|
break; // no more availible
|
2004-03-10 01:58:18 +01:00
|
|
|
}
|
2006-10-04 19:40:33 +02:00
|
|
|
}
|
|
|
|
//echo "boinfolog::cal_to_include("; print_r($args); echo ")<pre>"; print_r($to_include); echo "</pre>\n";
|
|
|
|
return $to_include;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-06-19 16:44:13 +02:00
|
|
|
* Returm InfoLog (custom) information for projectmanager: status icon, type icon, css class
|
2006-10-04 19:40:33 +02:00
|
|
|
*
|
|
|
|
* @param array $args array with id's in $args['infolog']
|
2012-06-19 16:44:13 +02:00
|
|
|
* @return array with id => array with values for keys 'status', 'icon', 'class'
|
2006-10-04 19:40:33 +02:00
|
|
|
*/
|
|
|
|
function pm_icons($args)
|
|
|
|
{
|
|
|
|
if (isset($args['infolog']) && count($args['infolog']))
|
|
|
|
{
|
2012-06-19 16:44:13 +02:00
|
|
|
$query = array(
|
|
|
|
'col_filter' => array('info_id' => $args['infolog']),
|
|
|
|
'subs' => true,
|
2016-12-15 18:24:14 +01:00
|
|
|
'cols' => 'main.info_id,info_type,info_status,info_percent,info_id_parent',
|
2012-06-19 16:44:13 +02:00
|
|
|
);
|
2014-01-28 10:22:12 +01:00
|
|
|
$infos = array();
|
2012-06-19 16:44:13 +02:00
|
|
|
foreach($this->search($query) as $row)
|
2006-10-04 19:40:33 +02:00
|
|
|
{
|
2012-06-19 16:44:13 +02:00
|
|
|
$infos[$row['info_id']] = array(
|
|
|
|
'status' => $row['info_type'] != 'phone' && $row['info_status'] == 'ongoing' ?
|
|
|
|
$row['info_percent'].'%' : 'infolog/'.$this->status[$row['info_type']][$row['info_status']],
|
2014-11-03 18:12:44 +01:00
|
|
|
'status_icon' => $row['info_type'] != 'phone' && $row['info_status'] == 'ongoing' ?
|
|
|
|
'ongoing' : 'infolog/'.$row['info_status'],
|
2013-09-19 14:52:50 +02:00
|
|
|
'class' => $row['info_id_parent'] ? 'infolog_rowHasParent' : null,
|
2012-06-19 16:44:13 +02:00
|
|
|
);
|
2016-04-30 19:05:23 +02:00
|
|
|
if (Api\Image::find('infolog', $icon=$row['info_type'].'_element') ||
|
|
|
|
Api\Image::find('infolog', $icon=$row['info_type']))
|
2006-02-04 08:49:47 +01:00
|
|
|
{
|
2012-06-19 16:44:13 +02:00
|
|
|
$infos[$row['info_id']]['icon'] = 'infolog/'.$icon;
|
2006-02-04 08:49:47 +01:00
|
|
|
}
|
|
|
|
}
|
2016-07-21 21:18:49 +02:00
|
|
|
$anzSubs = $this->anzSubs(array_keys($infos));
|
|
|
|
if($anzSubs && is_array($anzSubs))
|
2012-06-19 16:44:13 +02:00
|
|
|
{
|
2016-07-21 21:18:49 +02:00
|
|
|
foreach($anzSubs as $info_id => $subs)
|
|
|
|
{
|
|
|
|
if ($subs) $infos[$info_id]['class'] .= ' infolog_rowHasSubs';
|
|
|
|
}
|
2012-06-19 16:44:13 +02:00
|
|
|
}
|
2006-02-04 08:49:47 +01:00
|
|
|
}
|
2012-06-19 16:44:13 +02:00
|
|
|
return $infos;
|
2001-07-12 01:17:32 +02:00
|
|
|
}
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
|
2007-12-11 10:29:50 +01:00
|
|
|
var $categories;
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
|
2009-11-19 11:40:54 +01:00
|
|
|
/**
|
|
|
|
* Find existing categories in database by name or add categories that do not exist yet
|
|
|
|
* currently used for ical/sif import
|
|
|
|
*
|
|
|
|
* @param array $catname_list names of the categories which should be found or added
|
2015-04-17 11:39:22 +02:00
|
|
|
* @param int $info_id = -1 match against existing infolog and expand the returned category ids
|
2009-11-19 11:40:54 +01:00
|
|
|
* by the ones the user normally does not see due to category permissions - used to preserve categories
|
|
|
|
* @return array category ids (found, added and preserved categories)
|
|
|
|
*/
|
|
|
|
function find_or_add_categories($catname_list, $info_id=-1)
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
{
|
2007-12-11 10:29:50 +01:00
|
|
|
if (!is_object($this->categories))
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$this->categories = new Api\Categories($this->user,'infolog');
|
2009-11-19 11:40:54 +01:00
|
|
|
}
|
2010-02-09 22:56:39 +01:00
|
|
|
$old_cats_preserve = array();
|
|
|
|
if ($info_id && $info_id > 0)
|
2009-11-19 11:40:54 +01:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
// preserve Api\Categories without users read access
|
2009-11-19 11:40:54 +01:00
|
|
|
$old_infolog = $this->read($info_id);
|
|
|
|
$old_categories = explode(',',$old_infolog['info_cat']);
|
2010-03-07 00:06:43 +01:00
|
|
|
if (is_array($old_categories) && count($old_categories) > 0)
|
2009-11-19 11:40:54 +01:00
|
|
|
{
|
2010-03-07 00:06:43 +01:00
|
|
|
foreach ($old_categories as $cat_id)
|
2009-11-19 11:40:54 +01:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
if ($cat_id && !$this->categories->check_perms(Acl::READ, $cat_id))
|
2009-11-19 11:40:54 +01:00
|
|
|
{
|
|
|
|
$old_cats_preserve[] = $cat_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$cat_id_list = array();
|
2010-03-07 00:06:43 +01:00
|
|
|
foreach ((array)$catname_list as $cat_name)
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
{
|
|
|
|
$cat_name = trim($cat_name);
|
2007-12-11 10:29:50 +01:00
|
|
|
$cat_id = $this->categories->name2id($cat_name, 'X-');
|
2009-12-01 11:24:55 +01:00
|
|
|
|
2007-12-11 10:29:50 +01:00
|
|
|
if (!$cat_id)
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
{
|
2009-11-19 11:40:54 +01:00
|
|
|
// some SyncML clients (mostly phones) add an X- to the category names
|
|
|
|
if (strncmp($cat_name, 'X-', 2) == 0)
|
|
|
|
{
|
|
|
|
$cat_name = substr($cat_name, 2);
|
|
|
|
}
|
2009-07-15 22:04:17 +02:00
|
|
|
$cat_id = $this->categories->add(array('name' => $cat_name, 'descr' => $cat_name, 'access' => 'private'));
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
}
|
|
|
|
|
2007-12-11 10:29:50 +01:00
|
|
|
if ($cat_id)
|
|
|
|
{
|
|
|
|
$cat_id_list[] = $cat_id;
|
|
|
|
}
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
}
|
2009-12-01 11:24:55 +01:00
|
|
|
|
2010-02-09 22:56:39 +01:00
|
|
|
if (count($old_cats_preserve) > 0)
|
2009-11-19 11:40:54 +01:00
|
|
|
{
|
|
|
|
$cat_id_list = array_merge($old_cats_preserve, $cat_id_list);
|
|
|
|
}
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
|
|
|
|
if (count($cat_id_list) > 1)
|
|
|
|
{
|
2007-12-11 10:29:50 +01:00
|
|
|
$cat_id_list = array_unique($cat_id_list);
|
2009-11-19 11:40:54 +01:00
|
|
|
// disable sorting until infolog supports multiple categories
|
|
|
|
// to make sure that the preserved category takes precedence over a new one from the client
|
|
|
|
/* sort($cat_id_list, SORT_NUMERIC); */
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
}
|
2009-11-19 11:40:54 +01:00
|
|
|
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
return $cat_id_list;
|
|
|
|
}
|
|
|
|
|
2007-12-11 07:57:15 +01:00
|
|
|
/**
|
|
|
|
* Get names for categories specified by their id's
|
|
|
|
*
|
|
|
|
* @param array|string $cat_id_list array or comma-sparated list of id's
|
|
|
|
* @return array with names
|
|
|
|
*/
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
function get_categories($cat_id_list)
|
|
|
|
{
|
2007-12-11 10:29:50 +01:00
|
|
|
if (!is_object($this->categories))
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$this->categories = new Api\Categories($this->user,'infolog');
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
}
|
|
|
|
|
2007-12-11 10:29:50 +01:00
|
|
|
if (!is_array($cat_id_list))
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
{
|
2007-12-11 10:29:50 +01:00
|
|
|
$cat_id_list = explode(',',$cat_id_list);
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
}
|
|
|
|
$cat_list = array();
|
2007-12-11 10:29:50 +01:00
|
|
|
foreach($cat_id_list as $cat_id)
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
if ($cat_id && $this->categories->check_perms(Acl::READ, $cat_id) &&
|
2009-11-19 11:40:54 +01:00
|
|
|
($cat_name = $this->categories->id2name($cat_id)) && $cat_name != '--')
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
{
|
2009-11-19 11:40:54 +01:00
|
|
|
$cat_list[] = $cat_name;
|
SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 12:29:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $cat_list;
|
|
|
|
}
|
|
|
|
|
2007-06-10 11:21:04 +02:00
|
|
|
/**
|
|
|
|
* Send all async infolog notification
|
|
|
|
*
|
|
|
|
* Called via the async service job 'infolog-async-notification'
|
|
|
|
*/
|
|
|
|
function async_notification()
|
|
|
|
{
|
|
|
|
if (!($users = $this->so->users_with_open_entries()))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2009-11-19 12:38:37 +01:00
|
|
|
//error_log(__METHOD__."() users with open entries: ".implode(', ',$users));
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2007-06-10 11:21:04 +02:00
|
|
|
$save_account_id = $GLOBALS['egw_info']['user']['account_id'];
|
|
|
|
$save_prefs = $GLOBALS['egw_info']['user']['preferences'];
|
|
|
|
foreach($users as $user)
|
|
|
|
{
|
|
|
|
if (!($email = $GLOBALS['egw']->accounts->id2name($user,'account_email'))) continue;
|
|
|
|
// create the enviroment for $user
|
|
|
|
$this->user = $GLOBALS['egw_info']['user']['account_id'] = $user;
|
2016-02-19 09:54:53 +01:00
|
|
|
$GLOBALS['egw']->preferences->__construct($user);
|
2007-06-10 11:21:04 +02:00
|
|
|
$GLOBALS['egw_info']['user']['preferences'] = $GLOBALS['egw']->preferences->read_repository();
|
2016-02-19 09:54:53 +01:00
|
|
|
$GLOBALS['egw']->acl->__construct($user);
|
2007-06-10 11:21:04 +02:00
|
|
|
$this->grants = $GLOBALS['egw']->acl->get_grants('infolog',$this->group_owners ? $this->group_owners : true);
|
2009-06-08 18:21:14 +02:00
|
|
|
$this->so = new infolog_so($this->grants); // so caches it's filters
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2007-06-10 11:21:04 +02:00
|
|
|
$notified_info_ids = array();
|
|
|
|
foreach(array(
|
|
|
|
'notify_due_responsible' => 'open-responsible-enddate',
|
|
|
|
'notify_due_delegated' => 'open-delegated-enddate',
|
|
|
|
'notify_start_responsible' => 'open-responsible-date',
|
|
|
|
'notify_start_delegated' => 'open-delegated-date',
|
|
|
|
) as $pref => $filter)
|
|
|
|
{
|
|
|
|
if (!($pref_value = $GLOBALS['egw_info']['user']['preferences']['infolog'][$pref])) continue;
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2007-06-10 11:21:04 +02:00
|
|
|
$filter .= date('Y-m-d',time()+24*60*60*(int)$pref_value);
|
2009-11-19 12:38:37 +01:00
|
|
|
//error_log(__METHOD__."() checking with filter '$filter' ($pref_value) for user $user ($email)");
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2014-06-17 12:39:12 +02:00
|
|
|
$params = array('filter' => $filter, 'custom_fields' => true, 'subs' => true);
|
2007-06-10 11:21:04 +02:00
|
|
|
foreach($this->so->search($params) as $info)
|
|
|
|
{
|
|
|
|
// check if we already send a notification for that infolog entry, eg. starting and due on same day
|
|
|
|
if (in_array($info['info_id'],$notified_info_ids)) continue;
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2009-07-15 22:04:17 +02:00
|
|
|
if (is_null($this->tracking) || $this->tracking->user != $user)
|
2007-06-10 11:21:04 +02:00
|
|
|
{
|
2009-07-15 22:04:17 +02:00
|
|
|
$this->tracking = new infolog_tracking($this);
|
2007-06-10 11:21:04 +02:00
|
|
|
}
|
|
|
|
switch($pref)
|
|
|
|
{
|
|
|
|
case 'notify_due_responsible':
|
2010-05-20 18:13:55 +02:00
|
|
|
$info['prefix'] = lang('Due %1',$this->enums['type'][$info['info_type']]);
|
2007-06-10 11:21:04 +02:00
|
|
|
$info['message'] = lang('%1 you are responsible for is due at %2',$this->enums['type'][$info['info_type']],
|
2010-02-05 17:32:30 +01:00
|
|
|
$this->tracking->datetime($info['info_enddate'],false));
|
2007-06-10 11:21:04 +02:00
|
|
|
break;
|
|
|
|
case 'notify_due_delegated':
|
2010-05-20 18:13:55 +02:00
|
|
|
$info['prefix'] = lang('Due %1',$this->enums['type'][$info['info_type']]);
|
2007-06-10 11:21:04 +02:00
|
|
|
$info['message'] = lang('%1 you delegated is due at %2',$this->enums['type'][$info['info_type']],
|
2010-02-05 17:32:30 +01:00
|
|
|
$this->tracking->datetime($info['info_enddate'],false));
|
2007-06-10 11:21:04 +02:00
|
|
|
break;
|
|
|
|
case 'notify_start_responsible':
|
2010-05-20 18:13:55 +02:00
|
|
|
$info['prefix'] = lang('Starting %1',$this->enums['type'][$info['info_type']]);
|
2007-06-10 11:21:04 +02:00
|
|
|
$info['message'] = lang('%1 you are responsible for is starting at %2',$this->enums['type'][$info['info_type']],
|
2010-02-05 17:32:30 +01:00
|
|
|
$this->tracking->datetime($info['info_startdate'],null));
|
2007-06-10 11:21:04 +02:00
|
|
|
break;
|
|
|
|
case 'notify_start_delegated':
|
2010-05-20 18:13:55 +02:00
|
|
|
$info['prefix'] = lang('Starting %1',$this->enums['type'][$info['info_type']]);
|
2007-06-10 11:21:04 +02:00
|
|
|
$info['message'] = lang('%1 you delegated is starting at %2',$this->enums['type'][$info['info_type']],
|
2010-02-05 17:32:30 +01:00
|
|
|
$this->tracking->datetime($info['info_startdate'],null));
|
2007-06-10 11:21:04 +02:00
|
|
|
break;
|
|
|
|
}
|
2009-11-19 12:38:37 +01:00
|
|
|
//error_log("notifiying $user($email) about $info[info_subject]: $info[message]");
|
2009-07-15 22:04:17 +02:00
|
|
|
$this->tracking->send_notification($info,null,$email,$user,$pref);
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2007-06-10 11:21:04 +02:00
|
|
|
$notified_info_ids[] = $info['info_id'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-02-06 14:21:21 +01:00
|
|
|
|
2007-06-10 11:21:04 +02:00
|
|
|
$GLOBALS['egw_info']['user']['account_id'] = $save_account_id;
|
|
|
|
$GLOBALS['egw_info']['user']['preferences'] = $save_prefs;
|
|
|
|
}
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2007-10-05 17:06:27 +02:00
|
|
|
/** conversion of infolog status to vtodo status
|
|
|
|
* @private
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
var $_status2vtodo = array(
|
|
|
|
'offer' => 'NEEDS-ACTION',
|
|
|
|
'not-started' => 'NEEDS-ACTION',
|
|
|
|
'ongoing' => 'IN-PROCESS',
|
|
|
|
'done' => 'COMPLETED',
|
|
|
|
'cancelled' => 'CANCELLED',
|
|
|
|
'billed' => 'COMPLETED',
|
|
|
|
'template' => 'CANCELLED',
|
|
|
|
'nonactive' => 'CANCELLED',
|
|
|
|
'archive' => 'CANCELLED',
|
2009-07-15 22:04:17 +02:00
|
|
|
'deferred' => 'NEEDS-ACTION',
|
|
|
|
'waiting' => 'IN-PROCESS',
|
2007-10-05 17:06:27 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
/** conversion of vtodo status to infolog status
|
|
|
|
* @private
|
2008-10-07 14:50:14 +02:00
|
|
|
* @var array
|
2007-10-05 17:06:27 +02:00
|
|
|
*/
|
|
|
|
var $_vtodo2status = array(
|
|
|
|
'NEEDS-ACTION' => 'not-started',
|
2009-07-15 22:04:17 +02:00
|
|
|
'NEEDS ACTION' => 'not-started',
|
2007-10-05 17:06:27 +02:00
|
|
|
'IN-PROCESS' => 'ongoing',
|
2009-07-15 22:04:17 +02:00
|
|
|
'IN PROCESS' => 'ongoing',
|
2007-10-05 17:06:27 +02:00
|
|
|
'COMPLETED' => 'done',
|
|
|
|
'CANCELLED' => 'cancelled',
|
|
|
|
);
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2007-10-05 17:06:27 +02:00
|
|
|
/**
|
|
|
|
* Converts an infolog status into a vtodo status
|
|
|
|
*
|
|
|
|
* @param string $status see $this->status
|
|
|
|
* @return string {CANCELLED|NEEDS-ACTION|COMPLETED|IN-PROCESS}
|
|
|
|
*/
|
|
|
|
function status2vtodo($status)
|
|
|
|
{
|
|
|
|
return isset($this->_status2vtodo[$status]) ? $this->_status2vtodo[$status] : 'NEEDS-ACTION';
|
|
|
|
}
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2007-10-05 17:06:27 +02:00
|
|
|
/**
|
|
|
|
* Converts a vtodo status into an infolog status using the optional X-INFOLOG-STATUS
|
2008-10-07 14:50:14 +02:00
|
|
|
*
|
2007-10-05 17:06:27 +02:00
|
|
|
* X-INFOLOG-STATUS is only used, if translated to the vtodo-status gives the identical vtodo status
|
|
|
|
* --> the user did not changed it
|
|
|
|
*
|
2016-04-30 19:05:23 +02:00
|
|
|
* @param string $_vtodo_status {CANCELLED|NEEDS-ACTION|COMPLETED|IN-PROCESS}
|
2007-10-05 17:06:27 +02:00
|
|
|
* @param string $x_infolog_status preserved original infolog status
|
|
|
|
* @return string
|
|
|
|
*/
|
2016-04-30 19:05:23 +02:00
|
|
|
function vtodo2status($_vtodo_status,$x_infolog_status=null)
|
2007-10-05 17:06:27 +02:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
$vtodo_status = strtoupper($_vtodo_status);
|
2007-10-05 17:06:27 +02:00
|
|
|
|
|
|
|
if ($x_infolog_status && $this->status2vtodo($x_infolog_status) == $vtodo_status)
|
|
|
|
{
|
|
|
|
$status = $x_infolog_status;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$status = isset($this->_vtodo2status[$vtodo_status]) ? $this->_vtodo2status[$vtodo_status] : 'not-started';
|
|
|
|
}
|
|
|
|
return $status;
|
|
|
|
}
|
2008-10-07 14:50:14 +02:00
|
|
|
|
2012-05-22 19:39:28 +02:00
|
|
|
/**
|
|
|
|
* Get status of a single or all types
|
|
|
|
*
|
|
|
|
* As status value can have different translations depending on type, we list all translations
|
|
|
|
*
|
2015-04-17 11:39:22 +02:00
|
|
|
* @param string $type = null
|
|
|
|
* @param array &$icons = null on return name of icons
|
2012-05-22 19:39:28 +02:00
|
|
|
* @return array value => (commaseparated) translations
|
|
|
|
*/
|
|
|
|
function get_status($type=null, array &$icons=null)
|
|
|
|
{
|
|
|
|
// if filtered by type, show only the stati of the filtered type
|
|
|
|
if ($type && isset($this->status[$type]))
|
|
|
|
{
|
|
|
|
$statis = $icons = $this->status[$type];
|
|
|
|
}
|
|
|
|
else // show all stati
|
|
|
|
{
|
|
|
|
$statis = $icons = array();
|
|
|
|
foreach($this->status as $t => $stati)
|
|
|
|
{
|
|
|
|
if ($t === 'defaults') continue;
|
|
|
|
foreach($stati as $val => $label)
|
|
|
|
{
|
|
|
|
$statis[$val][$label] = lang($label);
|
|
|
|
if (!isset($icons[$val])) $icons[$val] = $label;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
foreach($statis as $val => &$labels)
|
|
|
|
{
|
|
|
|
$labels = implode(', ', $labels);
|
|
|
|
}
|
|
|
|
}
|
2021-07-07 11:21:45 +02:00
|
|
|
// always add deleted status
|
|
|
|
$statis['deleted'] = 'deleted';
|
|
|
|
|
2012-05-22 19:39:28 +02:00
|
|
|
return $statis;
|
|
|
|
}
|
|
|
|
|
2007-10-05 17:06:27 +02:00
|
|
|
/**
|
|
|
|
* Activates an InfoLog entry (setting it's status from template or inactive depending on the completed percentage)
|
|
|
|
*
|
|
|
|
* @param array $info
|
|
|
|
* @return string new status
|
|
|
|
*/
|
|
|
|
function activate($info)
|
|
|
|
{
|
|
|
|
switch((int)$info['info_percent'])
|
|
|
|
{
|
|
|
|
case 0: return 'not-started';
|
|
|
|
case 100: return 'done';
|
|
|
|
}
|
|
|
|
return 'ongoing';
|
|
|
|
}
|
2009-07-15 22:04:17 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the Parent ID of an InfoLog entry
|
|
|
|
*
|
|
|
|
* @param string $_guid
|
|
|
|
* @return string parentID
|
|
|
|
*/
|
|
|
|
function getParentID($_guid)
|
|
|
|
{
|
|
|
|
#Horde::logMessage("getParentID($_guid)", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
|
|
|
|
|
|
$parentID = False;
|
|
|
|
$myfilter = array('col_filter' => array('info_uid'=>$_guid)) ;
|
2014-01-28 10:22:12 +01:00
|
|
|
if ($_guid && ($found=$this->search($myfilter)) && ($uidmatch = array_shift($found)))
|
|
|
|
{
|
2009-07-15 22:04:17 +02:00
|
|
|
$parentID = $uidmatch['info_id'];
|
2014-01-28 10:22:12 +01:00
|
|
|
}
|
2009-07-15 22:04:17 +02:00
|
|
|
return $parentID;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Try to find a matching db entry
|
2010-02-09 22:56:39 +01:00
|
|
|
* This expects timestamps to be in server-time.
|
2009-07-15 22:04:17 +02:00
|
|
|
*
|
2010-02-09 22:56:39 +01:00
|
|
|
* @param array $infoData the infolog data we try to find
|
2015-04-17 11:39:22 +02:00
|
|
|
* @param boolean $relax = false if asked to relax, we only match against some key fields
|
|
|
|
* @param string $tzid = null timezone, null => user time
|
2010-02-09 22:56:39 +01:00
|
|
|
*
|
|
|
|
* @return array of infolog_ids of matching entries
|
2009-07-15 22:04:17 +02:00
|
|
|
*/
|
2010-02-09 22:56:39 +01:00
|
|
|
function findInfo($infoData, $relax=false, $tzid=null)
|
2009-07-15 22:04:17 +02:00
|
|
|
{
|
2010-02-09 22:56:39 +01:00
|
|
|
$foundInfoLogs = array();
|
|
|
|
$filter = array();
|
|
|
|
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '('. ($relax ? 'RELAX, ': 'EXACT, ') . $tzid . ')[InfoData]:'
|
|
|
|
. array2string($infoData));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($infoData['info_id']
|
|
|
|
&& ($egwData = $this->read($infoData['info_id'], true, 'server')))
|
2009-07-15 22:04:17 +02:00
|
|
|
{
|
2010-02-09 22:56:39 +01:00
|
|
|
// we only do a simple consistency check
|
2010-03-07 00:06:43 +01:00
|
|
|
if (!$relax || strpos($egwData['info_subject'], $infoData['info_subject']) === 0)
|
2009-12-01 11:24:55 +01:00
|
|
|
{
|
2010-02-09 22:56:39 +01:00
|
|
|
return array($egwData['info_id']);
|
2009-12-01 11:24:55 +01:00
|
|
|
}
|
2010-02-09 22:56:39 +01:00
|
|
|
if (!$relax) return array();
|
2009-12-01 11:24:55 +01:00
|
|
|
}
|
2010-02-09 22:56:39 +01:00
|
|
|
unset($infoData['info_id']);
|
2009-07-15 22:04:17 +02:00
|
|
|
|
2010-02-09 22:56:39 +01:00
|
|
|
if (!$relax && !empty($infoData['info_uid']))
|
|
|
|
{
|
|
|
|
$filter = array('col_filter' => array('info_uid' => $infoData['info_uid']));
|
|
|
|
foreach($this->so->search($filter) as $egwData)
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
if (!$this->check_access($egwData,Acl::READ)) continue;
|
2010-02-09 22:56:39 +01:00
|
|
|
$foundInfoLogs[$egwData['info_id']] = $egwData['info_id'];
|
2009-07-15 22:04:17 +02:00
|
|
|
}
|
2010-02-09 22:56:39 +01:00
|
|
|
return $foundInfoLogs;
|
2009-07-15 22:04:17 +02:00
|
|
|
}
|
2010-02-09 22:56:39 +01:00
|
|
|
unset($infoData['info_uid']);
|
2009-07-15 22:04:17 +02:00
|
|
|
|
2010-02-09 22:56:39 +01:00
|
|
|
if (empty($infoData['info_des']))
|
2009-07-15 22:04:17 +02:00
|
|
|
{
|
2010-02-09 22:56:39 +01:00
|
|
|
$description = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// ignore meta information appendices
|
|
|
|
$description = trim(preg_replace('/\s*\[[A-Z_]+:.*\].*/im', '', $infoData['info_des']));
|
|
|
|
$text = trim(preg_replace('/\s*\[[A-Z_]+:.*\]/im', '', $infoData['info_des']));
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. "()[description]: $description");
|
|
|
|
}
|
|
|
|
// Avoid quotation problems
|
2014-01-28 10:22:12 +01:00
|
|
|
$matches = null;
|
2010-02-09 22:56:39 +01:00
|
|
|
if (preg_match_all('/[\x20-\x7F]*/m', $text, $matches, PREG_SET_ORDER))
|
2009-07-15 22:04:17 +02:00
|
|
|
{
|
2010-02-09 22:56:39 +01:00
|
|
|
$text = '';
|
|
|
|
foreach ($matches as $chunk)
|
|
|
|
{
|
|
|
|
if (strlen($text) < strlen($chunk[0]))
|
|
|
|
{
|
|
|
|
$text = $chunk[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. "()[search]: $text");
|
|
|
|
}
|
|
|
|
$filter['search'] = $text;
|
2009-07-15 22:04:17 +02:00
|
|
|
}
|
|
|
|
}
|
2010-02-09 22:56:39 +01:00
|
|
|
$this->time2time($infoData, $tzid, false);
|
2009-07-15 22:04:17 +02:00
|
|
|
|
2010-02-09 22:56:39 +01:00
|
|
|
$filter['col_filter'] = $infoData;
|
2009-07-15 22:04:17 +02:00
|
|
|
// priority does not need to match
|
2010-02-09 22:56:39 +01:00
|
|
|
unset($filter['col_filter']['info_priority']);
|
|
|
|
// we ignore description and location first
|
|
|
|
unset($filter['col_filter']['info_des']);
|
|
|
|
unset($filter['col_filter']['info_location']);
|
2009-07-15 22:04:17 +02:00
|
|
|
|
2010-02-09 22:56:39 +01:00
|
|
|
foreach ($this->so->search($filter) as $itemID => $egwData)
|
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
if (!$this->check_access($egwData,Acl::READ)) continue;
|
2009-07-15 22:04:17 +02:00
|
|
|
|
2010-02-09 22:56:39 +01:00
|
|
|
switch ($infoData['info_type'])
|
|
|
|
{
|
|
|
|
case 'task':
|
|
|
|
if (!empty($egwData['info_location']))
|
|
|
|
{
|
|
|
|
$egwData['info_location'] = str_replace("\r\n", "\n", $egwData['info_location']);
|
|
|
|
}
|
|
|
|
if (!$relax &&
|
|
|
|
!empty($infoData['info_location']) && (empty($egwData['info_location'])
|
|
|
|
|| strpos($egwData['info_location'], $infoData['info_location']) !== 0))
|
|
|
|
{
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '()[location mismatch]: '
|
|
|
|
. $infoData['info_location'] . ' <> ' . $egwData['info_location']);
|
|
|
|
}
|
2018-12-11 12:45:17 +01:00
|
|
|
continue 2; // +1 for switch
|
2010-02-09 22:56:39 +01:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
if (!empty($egwData['info_des']))
|
|
|
|
{
|
|
|
|
$egwData['info_des'] = str_replace("\r\n", "\n", $egwData['info_des']);
|
|
|
|
}
|
|
|
|
if (!$relax && ($description && empty($egwData['info_des'])
|
|
|
|
|| !empty($egwData['info_des']) && empty($infoData['info_des'])
|
|
|
|
|| strpos($egwData['info_des'], $description) === false))
|
|
|
|
{
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '()[description mismatch]: '
|
|
|
|
. $infoData['info_des'] . ' <> ' . $egwData['info_des']);
|
|
|
|
}
|
2018-12-11 12:45:17 +01:00
|
|
|
continue 2; // +1 for switch
|
2010-02-09 22:56:39 +01:00
|
|
|
}
|
|
|
|
// no further criteria to match
|
|
|
|
$foundInfoLogs[$egwData['info_id']] = $egwData['info_id'];
|
2009-07-15 22:04:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-09 22:56:39 +01:00
|
|
|
if (!$relax && !empty($foundInfoLogs))
|
|
|
|
{
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '()[FOUND]:' . array2string($foundInfoLogs));
|
|
|
|
}
|
|
|
|
return $foundInfoLogs;
|
2009-07-15 22:04:17 +02:00
|
|
|
}
|
|
|
|
|
2010-02-09 22:56:39 +01:00
|
|
|
if ($relax)
|
|
|
|
{
|
|
|
|
unset($filter['search']);
|
|
|
|
}
|
2009-07-15 22:04:17 +02:00
|
|
|
|
2010-02-09 22:56:39 +01:00
|
|
|
// search for matches by date only
|
2009-07-15 22:04:17 +02:00
|
|
|
unset($filter['col_filter']['info_startdate']);
|
2010-02-09 22:56:39 +01:00
|
|
|
unset($filter['col_filter']['info_enddate']);
|
2009-07-15 22:04:17 +02:00
|
|
|
unset($filter['col_filter']['info_datecompleted']);
|
2010-02-09 22:56:39 +01:00
|
|
|
// Some devices support lesser stati
|
|
|
|
unset($filter['col_filter']['info_status']);
|
2009-07-15 22:04:17 +02:00
|
|
|
|
|
|
|
// try tasks without category
|
|
|
|
unset($filter['col_filter']['info_cat']);
|
|
|
|
|
2010-02-04 13:08:03 +01:00
|
|
|
// Horde::logMessage("findVTODO Filter\n"
|
|
|
|
// . print_r($filter, true),
|
|
|
|
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
2010-02-09 22:56:39 +01:00
|
|
|
foreach ($this->so->search($filter) as $itemID => $egwData)
|
2010-02-04 13:08:03 +01:00
|
|
|
{
|
2016-04-30 19:05:23 +02:00
|
|
|
if (!$this->check_access($egwData,Acl::READ)) continue;
|
2010-02-04 13:08:03 +01:00
|
|
|
// Horde::logMessage("findVTODO Trying\n"
|
2010-02-09 22:56:39 +01:00
|
|
|
// . print_r($egwData, true),
|
2010-02-04 13:08:03 +01:00
|
|
|
// __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
2010-02-09 22:56:39 +01:00
|
|
|
if (isset($infoData['info_cat'])
|
|
|
|
&& isset($egwData['info_cat']) && $egwData['info_cat']
|
|
|
|
&& $infoData['info_cat'] != $egwData['info_cat'])
|
|
|
|
{
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '()[category mismatch]: '
|
|
|
|
. $infoData['info_cat'] . ' <> ' . $egwData['info_cat']);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (isset($infoData['info_startdate']) && $infoData['info_startdate'])
|
2010-02-04 13:08:03 +01:00
|
|
|
{
|
2010-02-09 22:56:39 +01:00
|
|
|
// We got a startdate from client
|
|
|
|
if (isset($egwData['info_startdate']) && $egwData['info_startdate'])
|
|
|
|
{
|
|
|
|
// We compare the date only
|
2016-04-30 19:05:23 +02:00
|
|
|
$taskTime = new Api\DateTime($infoData['info_startdate'],Api\DateTime::$server_timezone);
|
|
|
|
$egwTime = new Api\DateTime($egwData['info_startdate'],Api\DateTime::$server_timezone);
|
2010-02-09 22:56:39 +01:00
|
|
|
if ($taskTime->format('Ymd') != $egwTime->format('Ymd'))
|
|
|
|
{
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '()[start mismatch]: '
|
|
|
|
. $taskTime->format('Ymd') . ' <> ' . $egwTime->format('Ymd'));
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elseif (!$relax)
|
|
|
|
{
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '()[start mismatch]');
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2009-07-15 22:04:17 +02:00
|
|
|
}
|
2010-02-09 22:56:39 +01:00
|
|
|
if ($infoData['info_type'] == 'task')
|
2010-02-04 13:08:03 +01:00
|
|
|
{
|
2010-02-09 22:56:39 +01:00
|
|
|
if (isset($infoData['info_status']) && isset($egwData['info_status'])
|
|
|
|
&& $egwData['info_status'] == 'done'
|
|
|
|
&& $infoData['info_status'] != 'done' ||
|
|
|
|
$egwData['info_status'] != 'done'
|
|
|
|
&& $infoData['info_status'] == 'done')
|
|
|
|
{
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '()[status mismatch]: '
|
|
|
|
. $infoData['info_status'] . ' <> ' . $egwData['info_status']);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (isset($infoData['info_enddate']) && $infoData['info_enddate'])
|
|
|
|
{
|
|
|
|
// We got a enddate from client
|
|
|
|
if (isset($egwData['info_enddate']) && $egwData['info_enddate'])
|
|
|
|
{
|
|
|
|
// We compare the date only
|
2016-04-30 19:05:23 +02:00
|
|
|
$taskTime = new Api\DateTime($infoData['info_enddate'],Api\DateTime::$server_timezone);
|
|
|
|
$egwTime = new Api\DateTime($egwData['info_enddate'],Api\DateTime::$server_timezone);
|
2010-02-09 22:56:39 +01:00
|
|
|
if ($taskTime->format('Ymd') != $egwTime->format('Ymd'))
|
|
|
|
{
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '()[DUE mismatch]: '
|
|
|
|
. $taskTime->format('Ymd') . ' <> ' . $egwTime->format('Ymd'));
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elseif (!$relax)
|
|
|
|
{
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '()[DUE mismatch]');
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isset($infoData['info_datecompleted']) && $infoData['info_datecompleted'])
|
|
|
|
{
|
|
|
|
// We got a completed date from client
|
|
|
|
if (isset($egwData['info_datecompleted']) && $egwData['info_datecompleted'])
|
|
|
|
{
|
|
|
|
// We compare the date only
|
2016-04-30 19:05:23 +02:00
|
|
|
$taskTime = new Api\DateTime($infoData['info_datecompleted'],Api\DateTime::$server_timezone);
|
|
|
|
$egwTime = new Api\DateTime($egwData['info_datecompleted'],Api\DateTime::$server_timezone);
|
2010-02-09 22:56:39 +01:00
|
|
|
if ($taskTime->format('Ymd') != $egwTime->format('Ymd'))
|
|
|
|
{
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '()[completed mismatch]: '
|
|
|
|
. $taskTime->format('Ymd') . ' <> ' . $egwTime->format('Ymd'));
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elseif (!$relax)
|
|
|
|
{
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '()[completed mismatch]');
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elseif (!$relax && isset($egwData['info_datecompleted']) && $egwData['info_datecompleted'])
|
|
|
|
{
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '()[completed mismatch]');
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2009-07-15 22:04:17 +02:00
|
|
|
}
|
2010-02-09 22:56:39 +01:00
|
|
|
$foundInfoLogs[$itemID] = $itemID;
|
|
|
|
}
|
|
|
|
if ($this->log)
|
|
|
|
{
|
|
|
|
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__
|
|
|
|
. '()[FOUND]:' . array2string($foundInfoLogs));
|
|
|
|
}
|
|
|
|
return $foundInfoLogs;
|
2009-07-15 22:04:17 +02:00
|
|
|
}
|
2022-03-09 14:42:29 +01:00
|
|
|
}
|