mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-23 16:33:17 +01:00
* InfoLog/CalDAV: store unsupported iCal properties like custom fields incl. history logging, thought they are not displayed unless you explicitly add a custom field from them (prefixed with one #)
r37832: fixed fatal error calling widgetExists on a non-object r37837: storing unsupported (valarm-)components like unsupported (X-)properties r37854: need to load custom fields now allways, as x-props and unsupported components are stored there
This commit is contained in:
parent
fe98471d18
commit
3dc0e31fa9
@ -355,7 +355,7 @@ abstract class bo_tracking
|
||||
}
|
||||
foreach($changed_fields as $name)
|
||||
{
|
||||
$status = $this->field2history[$name];
|
||||
$status = isset($this->field2history[$name]) ? $this->field2history[$name] : $name;
|
||||
//error_log(__METHOD__.__LINE__." Name $name,".' Status:'.array2string($status));
|
||||
if (is_array($status)) // 1:N relation --> remove common rows
|
||||
{
|
||||
@ -423,6 +423,13 @@ abstract class bo_tracking
|
||||
//echo "<p>$name: ".array2string($data[$name]).' != '.array2string($old[$name])."</p>\n";
|
||||
}
|
||||
}
|
||||
foreach($data as $name => $value)
|
||||
{
|
||||
if ($name[0] == '#' && $name[1] == '#' && $value !== $old[$name])
|
||||
{
|
||||
$changed_fields[] = $name;
|
||||
}
|
||||
}
|
||||
//error_log(__METHOD__."() changed_fields=".array2string($changed_fields));
|
||||
return $changed_fields;
|
||||
}
|
||||
|
@ -46,6 +46,94 @@ class historylog_widget
|
||||
// 'historylog-helper' => '',
|
||||
);
|
||||
|
||||
static $status_widgets;
|
||||
|
||||
/**
|
||||
* pre-processing of the historylog-helper
|
||||
*
|
||||
* @param mixed &$value value / existing content, can be modified
|
||||
* @param array &$cell array with the widget, can be modified for ui-independent widgets
|
||||
* @return boolean true if extra label is allowed, false otherwise
|
||||
*/
|
||||
private function pre_process_helper(&$value, &$cell, etemplate $tmpl)
|
||||
{
|
||||
if (empty($value) && (string)$value !== '0')
|
||||
{
|
||||
$cell = etemplate::empty_cell();
|
||||
return true;
|
||||
}
|
||||
//echo $value.'/'.$cell['size']; _debug_array(self::$status_widgets);
|
||||
$type = isset(self::$status_widgets[$cell['size']]) ? self::$status_widgets[$cell['size']] : 'label';
|
||||
$options = '';
|
||||
if (!is_array($type) && strpos($type,':') !== false)
|
||||
{
|
||||
list($type,$options) = explode(':',$type,2);
|
||||
}
|
||||
// For all select-cats, show missing entries as IDs
|
||||
if($type == 'select-cat')
|
||||
{
|
||||
list($rows,$type1,$type2,$type3,$type4,$type5,$type6) = explode(',',$options);
|
||||
$type6 = 2;
|
||||
$options = implode(',',array($rows,$type1,$type2,$type3,$type4,$type5,$type6));
|
||||
}
|
||||
$cell = etemplate::empty_cell($type,$cell['name'],array('readonly' => true,'size' => $options));
|
||||
// display unsupported iCal properties, which have multiple values or attributes, or multiple components
|
||||
if ($type === 'label' && $value[1] === ':' && ($values = unserialize($value)))
|
||||
{
|
||||
if (isset($values['values']))
|
||||
{
|
||||
foreach((array)$values['params'] as $name => $val)
|
||||
{
|
||||
$values['values'][] = $name.': '.$val;
|
||||
}
|
||||
$values = $values['values'];
|
||||
}
|
||||
$value = implode("\n", $values);
|
||||
}
|
||||
elseif (is_array($type))
|
||||
{
|
||||
list($t) = explode(':',$type[0]);
|
||||
if (isset($type[0]) && // numeric indexed array --> multiple values of 1:N releation
|
||||
$tmpl->widgetExists($t))
|
||||
{
|
||||
$cell['type'] = 'vbox';
|
||||
$cell['size'] = '0,,0,0';
|
||||
$value = explode(bo_tracking::ONE2N_SEPERATOR,$value);
|
||||
foreach($type as $n => $t)
|
||||
{
|
||||
$opt = '';
|
||||
if(is_array($t))
|
||||
{
|
||||
$sel_options = $t;
|
||||
$t = 'select';
|
||||
}
|
||||
else
|
||||
{
|
||||
list($t,$opt) = explode(':',$t);
|
||||
}
|
||||
$child = etemplate::empty_cell($t,$cell['name']."[$n]",array('readonly' => true,'no_lang' => true,'size' => $opt));
|
||||
$child['sel_options'] = $sel_options;
|
||||
etemplate::add_child($cell,$child);
|
||||
unset($sel_options);
|
||||
unset($child);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$cell['sel_options'] = $cell['type'];
|
||||
$cell['type'] = 'select';
|
||||
}
|
||||
}
|
||||
// For all times, show time in user time
|
||||
elseif ($type == 'date-time' && $value)
|
||||
{
|
||||
$value = egw_time::server2user($value);
|
||||
}
|
||||
if ($cell['type'] == 'label') $cell['no_lang'] = 'true';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* pre-processing of the history logging extension
|
||||
*
|
||||
@ -59,74 +147,13 @@ class historylog_widget
|
||||
*/
|
||||
function pre_process($name,&$value,&$cell,&$readonlys,&$extension_data,etemplate $tmpl)
|
||||
{
|
||||
static $status_widgets;
|
||||
|
||||
if ($cell['type'] == 'historylog-helper')
|
||||
switch ($cell['type'])
|
||||
{
|
||||
if (empty($value) && (string)$value !== '0')
|
||||
{
|
||||
$cell = etemplate::empty_cell();
|
||||
return true;
|
||||
}
|
||||
//echo $value.'/'.$cell['size']; _debug_array($status_widgets);
|
||||
$type = isset($status_widgets[$cell['size']]) ? $status_widgets[$cell['size']] : 'label';
|
||||
$options = '';
|
||||
if (!is_array($type) && strpos($type,':') !== false)
|
||||
{
|
||||
list($type,$options) = explode(':',$type,2);
|
||||
}
|
||||
// For all select-cats, show missing entries as IDs
|
||||
if($type == 'select-cat')
|
||||
{
|
||||
list($rows,$type1,$type2,$type3,$type4,$type5,$type6) = explode(',',$options);
|
||||
$type6 = 2;
|
||||
$options = implode(',',array($rows,$type1,$type2,$type3,$type4,$type5,$type6));
|
||||
}
|
||||
$cell = etemplate::empty_cell($type,$cell['name'],array('readonly' => true,'size' => $options));
|
||||
if (is_array($type))
|
||||
{
|
||||
list($t) = explode(':',$type[0]);
|
||||
if (isset($type[0]) && // numeric indexed array --> multiple values of 1:N releation
|
||||
$tmpl->widgetExists($t))
|
||||
{
|
||||
$cell['type'] = 'vbox';
|
||||
$cell['size'] = '0,,0,0';
|
||||
$value = explode(bo_tracking::ONE2N_SEPERATOR,$value);
|
||||
foreach($type as $n => $t)
|
||||
{
|
||||
$opt = '';
|
||||
if(is_array($t))
|
||||
{
|
||||
$sel_options = $t;
|
||||
$t = 'select';
|
||||
}
|
||||
else
|
||||
{
|
||||
list($t,$opt) = explode(':',$t);
|
||||
}
|
||||
$child = etemplate::empty_cell($t,$cell['name']."[$n]",array('readonly' => true,'no_lang' => true,'size' => $opt));
|
||||
$child['sel_options'] = $sel_options;
|
||||
etemplate::add_child($cell,$child);
|
||||
unset($sel_options);
|
||||
unset($child);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$cell['sel_options'] = $cell['type'];
|
||||
$cell['type'] = 'select';
|
||||
}
|
||||
}
|
||||
// For all times, show time in user time
|
||||
elseif ($type == 'date-time' && $value)
|
||||
{
|
||||
$value = egw_time::server2user($value);
|
||||
}
|
||||
if ($cell['type'] == 'label') $cell['no_lang'] = 'true';
|
||||
return true;
|
||||
case 'historylog-helper':
|
||||
return $this->pre_process_helper($value, $cell, $tmpl);
|
||||
}
|
||||
$app = is_array($value) ? $value['app'] : $GLOBALS['egw_info']['flags']['currentapp'];
|
||||
$status_widgets = is_array($value) && isset($value['status-widgets']) ? $value['status-widgets'] : null;
|
||||
self::$status_widgets = is_array($value) && isset($value['status-widgets']) ? $value['status-widgets'] : null;
|
||||
|
||||
$id = is_array($value) ? $value['id'] : $value;
|
||||
$filter = is_array($value) ? $value['filter'] : array();
|
||||
@ -168,24 +195,34 @@ class historylog_widget
|
||||
{
|
||||
$tmpl->sel_options[$status]['#'.$cf_name] = lang($cf_data['label']);
|
||||
}
|
||||
if (isset($status_widgets['#'.$cf_name])) continue; // app set a status widget --> use that
|
||||
if (isset(self::$status_widgets['#'.$cf_name])) continue; // app set a status widget --> use that
|
||||
|
||||
if(!is_array($cf_data['values']) || !$cf_data['values'])
|
||||
{
|
||||
$status_widgets['#'.$cf_name] = $cf_data['type'] != 'text' ? $cf_data['type'] : 'label';
|
||||
self::$status_widgets['#'.$cf_name] = $cf_data['type'] != 'text' ? $cf_data['type'] : 'label';
|
||||
}
|
||||
elseif($cf_data['values']['@'])
|
||||
{
|
||||
$status_widgets['#'.$cf_name] = customfields_widget::_get_options_from_file($cf_data['values']['@']);
|
||||
self::$status_widgets['#'.$cf_name] = customfields_widget::_get_options_from_file($cf_data['values']['@']);
|
||||
}
|
||||
elseif(count($cf_data['values']))
|
||||
{
|
||||
$status_widgets['#'.$cf_name] = $cf_data['values'];
|
||||
self::$status_widgets['#'.$cf_name] = $cf_data['values'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($value) // autorepeated data-row only if there is data
|
||||
{
|
||||
// add "labels" for unsupported iCal properties, we just remove the '##' prefix
|
||||
foreach($value as &$row)
|
||||
{
|
||||
if ($row['status'][0] == '#' && $row['status'][1] == '#' &&
|
||||
isset($tmpl->sel_options[$status]) && !isset($tmpl->sel_options[$status][$row['status']]))
|
||||
{
|
||||
$tmpl->sel_options[$status][$row['status']] = substr($row['status'], 2);
|
||||
}
|
||||
}
|
||||
|
||||
$tpl->new_cell(2,'date-time','','${row}[user_ts]',array('readonly' => true));
|
||||
$tpl->new_cell(2,'select-account','','${row}[owner]',array('readonly' => true));
|
||||
|
||||
@ -201,7 +238,7 @@ class historylog_widget
|
||||
}
|
||||
// if $value[status-widgets] is set, use them together with the historylog-helper
|
||||
// to display new_ & old_value in the specified widget, otherwise use a label
|
||||
if ($status_widgets)
|
||||
if (self::$status_widgets)
|
||||
{
|
||||
$tpl->new_cell(2,'historylog-helper','','${row}[new_value]',array('size' => '$row_cont[status]','no_lang' => true,'readonly' => true));
|
||||
$tpl->new_cell(2,'historylog-helper','','${row}[old_value]',array('size' => '$row_cont[status]','no_lang' => true,'readonly' => true));
|
||||
|
@ -694,10 +694,12 @@ class infolog_bo
|
||||
* @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
|
||||
*
|
||||
* @return int/boolean info_id on a successfull write or false
|
||||
* @return int|boolean info_id on a successfull write or false
|
||||
*/
|
||||
function write(&$values_in, $check_defaults=true, $touch_modified=true, $user2server=true, $skip_notification=false, $throw_exception=false)
|
||||
function write(&$values_in, $check_defaults=true, $touch_modified=true, $user2server=true,
|
||||
$skip_notification=false, $throw_exception=false, $purge_cfs=null)
|
||||
{
|
||||
$values = $values_in;
|
||||
//echo "boinfolog::write()values="; _debug_array($values);
|
||||
@ -904,7 +906,7 @@ class infolog_bo
|
||||
//_debug_array($values);
|
||||
// error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n".array2string($values)."\n",3,'/tmp/infolog');
|
||||
|
||||
if (($info_id = $this->so->write($to_write,$check_modified)))
|
||||
if (($info_id = $this->so->write($to_write, $check_modified, $purge_cfs)))
|
||||
{
|
||||
if (!isset($values['info_type']) || $status_only || empty($values['caldav_url']))
|
||||
{
|
||||
|
@ -126,7 +126,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
'filter' => $task_filter,
|
||||
'info_type' => explode(',', $infolog_types),
|
||||
);
|
||||
error_log(__METHOD__."('$path', $user) returning ".array2string($ret));
|
||||
//error_log(__METHOD__."('$path', $user) returning ".array2string($ret));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
@ -208,6 +208,7 @@ class infolog_groupdav extends groupdav_handler
|
||||
'filter' => $task_filter,
|
||||
'date_format' => 'server',
|
||||
'col_filter' => $filter,
|
||||
'custom_fields' => true, // otherwise custom fields get NOT loaded!
|
||||
);
|
||||
|
||||
if (!$calendar_data)
|
||||
|
@ -327,6 +327,34 @@ class infolog_ical extends infolog_bo
|
||||
}
|
||||
$vevent->setAttribute('PRIORITY', $priority);
|
||||
|
||||
// for CalDAV add all X-Properties previously parsed
|
||||
if ($this->productManufacturer == 'groupdav')
|
||||
{
|
||||
foreach($taskData as $name => $value)
|
||||
{
|
||||
if (substr($name, 0, 2) == '##')
|
||||
{
|
||||
if ($name[2] == ':')
|
||||
{
|
||||
if ($value[1] == ':' && ($v = unserialize($value)) !== false) $value = $v;
|
||||
foreach((array)$value as $compvData)
|
||||
{
|
||||
$comp = Horde_iCalendar::newComponent(substr($name,3), $vevent);
|
||||
$comp->parsevCalendar($compvData,substr($name,3),'utf-8');
|
||||
$vevent->addComponent($comp);
|
||||
}
|
||||
}
|
||||
elseif ($value[1] == ':' && ($attr = unserialize($value)) !== false)
|
||||
{
|
||||
$vevent->setAttribute(substr($name, 2), $attr['value'], $attr['params'], true, $attr['values']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$vevent->setAttribute(substr($name, 2), $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$vcal->addComponent($vevent);
|
||||
|
||||
$retval = $vcal->exportvCalendar();
|
||||
@ -461,7 +489,7 @@ class infolog_ical extends infolog_bo
|
||||
{
|
||||
$taskData['caldav_name'] = $caldav_name;
|
||||
}
|
||||
return $this->write($taskData, true, true, false);
|
||||
return $this->write($taskData, true, true, false, false, false, 'ical');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -612,6 +640,7 @@ class infolog_ical extends infolog_bo
|
||||
$taskData['info_startdate'] = $component->getAttribute('DTSTART');
|
||||
}
|
||||
$attribute['value'] += $taskData['info_startdate'];
|
||||
$taskData['##DURATION'] = $attribute['value'];
|
||||
// fall throught
|
||||
case 'DUE':
|
||||
// even as EGroupware only displays the date, we can still store the full value
|
||||
@ -647,6 +676,8 @@ class infolog_ical extends infolog_bo
|
||||
}
|
||||
break;
|
||||
|
||||
case 'X-INFOLOG-STATUS':
|
||||
break;
|
||||
case 'STATUS':
|
||||
// check if we (still) have X-INFOLOG-STATUS set AND it would give an unchanged status (no change by the user)
|
||||
$taskData['info_status'] = $this->vtodo2status($attribute['value'],
|
||||
@ -679,10 +710,47 @@ class infolog_ical extends infolog_bo
|
||||
case 'PERCENT-COMPLETE':
|
||||
$taskData['info_percent'] = (int) $attribute['value'];
|
||||
break;
|
||||
|
||||
// ignore all PROPS, we dont want to store like X-properties or unsupported props
|
||||
case 'DTSTAMP':
|
||||
case 'SEQUENCE':
|
||||
case 'CREATED':
|
||||
case 'LAST-MODIFIED':
|
||||
//case 'ATTENDEE': // todo: add real support for it
|
||||
break;
|
||||
|
||||
default: // X- attribute or other by EGroupware unsupported property
|
||||
error_log(__METHOD__."() $attribute[name] = ".array2string($attribute));
|
||||
// for attributes with multiple values in multiple lines, merge the values
|
||||
if (isset($taskData['##'.$attribute['name']]))
|
||||
{
|
||||
error_log(__METHOD__."() taskData['##$attribute[name]'] = ".array2string($taskData['##'.$attribute['name']]));
|
||||
$attribute['values'] = array_merge(
|
||||
is_array($taskData['##'.$attribute['name']]) ? $taskData['##'.$attribute['name']]['values'] : (array)$taskData['##'.$attribute['name']],
|
||||
$attribute['values']);
|
||||
}
|
||||
$taskData['##'.$attribute['name']] = $attribute['params'] || count($attribute['values']) > 1 ?
|
||||
serialize($attribute) : $attribute['value'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// store included, but unsupported components like valarm as x-properties
|
||||
foreach($component->getComponents() as $comp)
|
||||
{
|
||||
$name = '##:'.strtoupper($comp->getType());
|
||||
$compvData = $comp->exportvCalendar($comp,'utf-8');
|
||||
if (isset($taskData[$name]))
|
||||
{
|
||||
$taskData[$name] = array($taskData[$name]);
|
||||
$taskData[$name][] = $compvData;
|
||||
}
|
||||
else
|
||||
{
|
||||
$taskData[$name] = $compvData;
|
||||
}
|
||||
}
|
||||
if ($this->log)
|
||||
{
|
||||
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($_taskID)\n" .
|
||||
|
@ -529,9 +529,10 @@ class infolog_so
|
||||
*
|
||||
* @param array $values with the data of the log-entry
|
||||
* @param int $check_modified=0 old modification date to check before update (include in WHERE)
|
||||
* @param string $purge_cfs=null null=dont, 'ical'=only iCal X-properties (cfs name starting with "#"), 'all'=all cfs
|
||||
* @return int|boolean info_id, false on error or 0 if the entry has been updated in the meantime
|
||||
*/
|
||||
function write($values,$check_modified=0) // did _not_ ensure ACL
|
||||
function write($values, $check_modified=0, $purge_cfs=null) // did _not_ ensure ACL
|
||||
{
|
||||
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']))
|
||||
{
|
||||
@ -604,6 +605,12 @@ class infolog_so
|
||||
//echo "<p>soinfolog.write values= "; _debug_array($values);
|
||||
|
||||
// write customfields now
|
||||
if ($purge_cfs)
|
||||
{
|
||||
$where = array('info_id' => $info_id);
|
||||
if ($purge_cfs == 'ical') $where[] = "info_extra_name LIKE '#%'";
|
||||
$this->db->delete($this->extra_table,$where,__LINE__,__FILE__);
|
||||
}
|
||||
$to_delete = array();
|
||||
foreach($values as $key => $val)
|
||||
{
|
||||
@ -627,7 +634,7 @@ class infolog_so
|
||||
$to_delete[] = substr($key,1);
|
||||
}
|
||||
}
|
||||
if ($to_delete)
|
||||
if ($to_delete && !$purge_cfs)
|
||||
{
|
||||
$this->db->delete($this->extra_table,array(
|
||||
'info_id' => $info_id,
|
||||
|
Loading…
Reference in New Issue
Block a user