History for InfoLog (incl. the ability to disable real deletes) and delete notifications

This commit is contained in:
Ralf Becker 2007-06-13 21:37:05 +00:00
parent 4b8657013e
commit 9e49e8c50d
10 changed files with 417 additions and 125 deletions

View File

@ -195,14 +195,16 @@ class bo_tracking
$changes = 0;
foreach($this->field2history as $name => $status)
{
if ($old[$name] != $data[$name])
if ($old[$name] != $data[$name] && !(!$old[$name] && !$data[$name]))
{
if (!is_object($this->historylog))
{
require_once(EGW_API_INC.'/class.historylog.inc.php');
$this->historylog =& new historylog($this->app);
}
$this->historylog->add($status,$data[$this->id_field],$data[$name],$old[$name]);
$this->historylog->add($status,$data[$this->id_field],
is_array($data[$name]) ? implode(',',$data[$name]) : $data[$name],
is_array($old[$name]) ? implode(',',$old[$name]) : $old[$name]);
++$changes;
}
}
@ -536,10 +538,18 @@ class bo_tracking
$link .= '&'.$this->id_field.'='.$data[$this->id_field];
}
}
elseif (($view = $GLOBALS['egw']->link->view($this->app,$data[$this->id_field])))
else
{
$link = $GLOBALS['egw']->link('/index.php',$view);
$popup = $GLOBALS['egw']->link->is_popup($this->app,'view');
if (!is_object($GLOBALS['egw']->link))
{
require_once(EGW_API_INC.'/class.bolink.inc.php');
$GLOBALS['egw']->link =& new bolink();
}
if (($view = $GLOBALS['egw']->link->view($this->app,$data[$this->id_field])))
{
$link = $GLOBALS['egw']->link('/index.php',$view);
$popup = $GLOBALS['egw']->link->is_popup($this->app,'view');
}
}
if ($link{0} == '/')
{
@ -585,7 +595,7 @@ class bo_tracking
// if there's no old entry, the entry is not modified by definition
// if both values are '', 0 or null, we count them as equal too
$modified = $old && $data[$name] != $old[$name] && !(!$data[$name] && !$old[$name]);
//if ($modified) error_log("data[$name]='{$data[$name]}', old[$name]='{$old[$name]}' --> modified=".(int)$modified);
//if ($modified) error_log("data[$name]=".print_r($data[$name],true).", old[$name]=".print_r($old[$name],true)." --> modified=".(int)$modified);
if (empty($detail['value']) && !$modified) continue; // skip unchanged, empty values
$body .= $this->format_line($html_email,$detail['type'],$modified,

View File

@ -12,6 +12,8 @@
include_once(EGW_INCLUDE_ROOT.'/infolog/inc/class.soinfolog.inc.php');
define('EGW_ACL_UNDELETE',EGW_ACL_CUSTOM_1); // undelete right
/**
* This class is the BO-layer of InfoLog, it also handles xmlrpc requests
*/
@ -32,7 +34,7 @@ class boinfolog
var $link;
var $vfs;
var $vfs_basedir='/infolog';
var $valid_pathes = array();
var $link_pathes = array();
var $send_file_ips = array();
var $xmlrpc_methods = array();
@ -111,6 +113,18 @@ class boinfolog
* @var int
*/
var $user;
/**
* History loggin: ''=no, 'history'=history & delete allowed, 'history_admin_delete', 'history_no_delete'
*
* @var string
*/
var $history;
/**
* Instance of infolog_tracking, only instaciated if needed!
*
* @var infolog_tracking
*/
var $tracking;
/**
* Constructor Infolog BO
@ -151,11 +165,11 @@ class boinfolog
'billed' => 'billed' ), // --> DONE
'note' => array(
'ongoing' => 'ongoing', // iCal has no status on notes
'done' => 'done'),
'done' => 'done' ),
'email' => array(
'ongoing' => 'ongoing', // iCal has no status on notes
'done' => 'done'
));
'done' => 'done' ),
);
if (!is_object($GLOBALS['egw']->link) && $instanciate_link)
{
@ -211,14 +225,15 @@ class boinfolog
}
if ($save_config) $this->config->save_repository();
}
if (count(explode(',',$this->config->config_data['responsible_edit'])))
if (is_array($this->config->config_data['responsible_edit']))
{
$this->responsible_edit = array_merge($this->responsible_edit,explode(',',$this->config->config_data['responsible_edit']));
$this->responsible_edit = array_merge($this->responsible_edit,$this->config->config_data['responsible_edit']);
}
if ($this->config->config_data['implicit_rights'] == 'edit')
{
$this->implicit_rights = 'edit';
}
$this->history = $this->config->config_data['history'];
}
// sort types by there translation
foreach($this->enums['type'] as $key => $val)
@ -305,6 +320,33 @@ class boinfolog
{
return $cache[$info_id][$required_rights];
}
// handle delete for the various history modes
if ($this->history)
{
if (!is_array($info) && !($info = $this->so->read($info_id))) return false;
if ($info['info_status'] == 'deleted' &&
($required_rights == EGW_ACL_EDIT || // no edit rights for deleted entries
$required_rights == EGW_ACL_ADD || // no add rights for deleted entries
$required_rights == EGW_ACL_DELETE && ($this->history == 'history_no_delete' || // no delete at all!
$this->history == 'history_admin_delete' && !isset($GLOBALS['egw_info']['user']['apps']['admin'])))) // delete only for admins
{
return $cache[$info_id][$required_rights] = false;
}
if ($required_rights == EGW_ACL_UNDELETE)
{
if ($info['info_status'] != 'deleted')
{
return $cache[$info_id][$required_rights] = false; // can only undelete deleted items
}
// undelete requires edit rights
return $cache[$info_id][$required_rights] = $this->so->check_access( $info,EGW_ACL_EDIT,$this->implicit_rights == 'edit' );
}
}
elseif ($required_rights == EGW_ACL_UNDELETE)
{
return $cache[$info_id][$required_rights] = false;
}
return $cache[$info_id][$required_rights] = $this->so->check_access( $info,$required_rights,$this->implicit_rights == 'edit' );
}
@ -467,18 +509,59 @@ class boinfolog
}
return False;
}
$this->link->unlink(0,'infolog',$info_id);
$info = $this->read($info_id);
$this->so->delete($info_id,$delete_children,$new_parent);
$GLOBALS['egw']->contenthistory->updateTimeStamp('infolog_'.$info['info_type'], $info_id, 'delete', time());
// check if we have children and delete or re-parent them
if (($children = $this->so->get_children($info_id)))
{
foreach($children as $id => $owner)
{
if ($delete_children && $this->so->grants[$owner] & EGW_ACL_DELETE)
{
$this->delete($id,$delete_children,$new_parent); // call ourself recursive to delete the child
}
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,
));
}
}
}
if (!($info = $this->read($info_id))) return false; // should not happen
$deleted = $info;
$deleted['info_status'] = 'deleted';
$deleted['info_datemodified'] = time();
$deleted['info_modifier'] = $this->user;
// if we have history switched on and not an already deleted item --> set only status deleted
if ($this->history && $info['info_status'] != 'deleted')
{
if ($info['info_status'] == 'deleted') return false; // entry already deleted
$this->so->write($deleted);
}
else
{
$this->so->delete($info_id,false); // we delete the children via bo to get all notifications!
}
if ($info['info_status'] != 'deleted') // dont notify of final purge of already deleted items
{
$this->link->unlink(0,'infolog',$info_id);
$GLOBALS['egw']->contenthistory->updateTimeStamp('infolog_'.$info['info_type'], $info_id, 'delete', time());
// send email notifications and do the history logging
require_once(EGW_INCLUDE_ROOT.'/infolog/inc/class.infolog_tracking.inc.php');
if (!is_object($this->tracking))
{
$this->tracking =& new infolog_tracking($this);
}
$this->tracking->track($deleted,$info,$this->user);
}
return True;
}
/**
* writes the given $values to InfoLog, a new entry gets created if info_id is not set or 0
*
@ -517,6 +600,10 @@ class boinfolog
{
$status_only = !!array_intersect($responsible,array_keys($GLOBALS['egw']->accounts->memberships($this->user)));
}
if (!$status_only && $values['info_status'] != 'deleted')
{
$status_only = $undelete = $this->check_access($values['info_id'],EGW_ACL_UNDELETE);
}
}
if ($values['info_id'] && !$this->check_access($values['info_id'],EGW_ACL_EDIT) && !$status_only ||
!$values['info_id'] && $values['info_id_parent'] && !$this->check_access($values['info_id_parent'],EGW_ACL_ADD))
@ -531,7 +618,7 @@ class boinfolog
{
$values = $this->xmlrpc2data($values);
}
if ($status_only) // make sure only status gets writen
if ($status_only && !$undelete) // make sure only status gets writen
{
$set_completed = !$values['info_datecompleted'] && // set date completed of finished job, only if its not already set
(in_array($values['info_status'],array('done','billed','cancelled')) || (int)$values['info_percent'] == 100);
@ -606,7 +693,7 @@ class boinfolog
$values['info_modifier'] = $this->so->user;
}
$to_write = $values;
if ($status_only) $values = array_merge($backup_values,$values);
if ($status_only && !$undelete) $values = array_merge($backup_values,$values);
// convert user- to system-time
foreach($this->timestamps as $time)
{
@ -623,7 +710,7 @@ class boinfolog
{
$values = $this->read($info_id);
}
if($values['info_id'])
if($values['info_id'] && $old['info_status'] != 'deleted')
{
// update
$GLOBALS['egw']->contenthistory->updateTimeStamp(
@ -640,7 +727,11 @@ class boinfolog
);
}
$values['info_id'] = $info_id;
if (!is_array($values['info_responsible'])) // this should not happen, bug it does ;-)
{
$values['info_responsible'] = $values['info_responsible'] ? explode(',',$values['info_responsible']) : array();
}
// create (and remove) links in custom fields
$this->update_customfield_links($values,$old);

View File

@ -46,7 +46,33 @@ class infolog_tracking extends bo_tracking
*
* @var array
*/
var $field2history = array();
var $field2history = array(
'info_type' => 'Ty',
'info_from' => 'Fr',
'info_addr' => 'Ad',
'info_link_id' => 'Li',
'info_cat' => 'Ca',
'info_priority' => 'Pr',
'info_owner' => 'Ow',
'info_access' => 'Ac',
'info_status' => 'St',
'info_percent' => 'Pe',
'info_datecompleted' => 'Co',
'info_location' => 'Lo',
'info_startdate' => 'st',
'info_enddate' => 'En',
'info_responsible' => 'Re',
'info_subject' => 'Su',
'info_des' => 'De',
'info_location' => 'Lo',
// PM fields
'info_planned_time' => 'pT',
'info_used_time' => 'uT',
'pl_id' => 'pL',
'info_price' => 'pr',
// all custom fields together
'custom' => '#c',
);
/**
* Translate field-names to labels
*
@ -56,9 +82,11 @@ class infolog_tracking extends bo_tracking
'info_type' => 'Type',
'info_from' => 'Contact',
'info_addr' => 'Phone/Email',
'info_link_id' => 'primary link',
'info_cat' => 'Category',
'info_priority' => 'Priority',
'info_owner' => 'Owner',
'info_access' => 'Access',
'info_status' => 'Status',
'info_percent' => 'Completed',
'info_datecompleted' => 'Date completed',
@ -67,6 +95,14 @@ class infolog_tracking extends bo_tracking
'info_enddate' => 'Enddate',
'info_responsible' => 'Responsible',
'info_subject' => 'Subject',
'info_des' => 'Description',
// PM fields
'info_planned_time' => 'planned time',
'info_used_time' => 'used time',
'pl_id' => 'pricelist',
'info_price' => 'price',
// custom fields
'custom' => 'custom fields'
);
/**
@ -90,29 +126,6 @@ class infolog_tracking extends bo_tracking
$this->infolog =& $boinfolog;
}
/**
* Tracks the changes in one entry $data, by comparing it with the last version in $old
*
* Reimplemented to fix some fields, who otherwise allways show up as modified
*
* @param array $data current entry
* @param array $old=null old/last state of the entry or null for a new entry
* @param int $user=null user who made the changes, default to current user
* @return int/boolean false on error, integer number of changes logged or true for new entries ($old == null)
*/
function track($data,$old=null,$user=null)
{
if ($old)
{
foreach($this->infolog->timestamps as $name)
{
if (!$old[$name]) $old[$name] = '';
}
}
return parent::track($data,$old,$user);
}
/**
* Get a notification-config value
*
@ -129,22 +142,54 @@ class infolog_tracking extends bo_tracking
return null;
}
/**
* Get the subject for a given entry
*
* Reimpleneted to use a New|deleted|modified prefix.
*
* @param array $data
* @param array $old
* @return string
*/
function get_subject($data,$old)
{
if (!$old || $old['info_status'] == 'deleted')
{
$prefix = lang('New %1',lang($this->infolog->enums['type'][$data['info_type']]));
}
elseif($data['info_status'] == 'deleted')
{
$prefix = lang('%1 deleted',lang($this->infolog->enums['type'][$data['info_type']]));
}
else
{
$prefix = lang('%1 modified',lang($this->infolog->enums['type'][$data['info_type']]));
}
return $prefix.': '.$data['info_subject'];
}
/**
* Get the modified / new message (1. line of mail body) for a given entry, can be reimplemented
*
* @param array $data
* @param array $old
* @return array/string array(message,user-id,timestamp-in-servertime) or string
* @return string
*/
function get_message($data,$old)
{
if ($data['message']) return $data['message']; // async notification
if (!$data['info_datemodified'] || !$old)
if (!$old || $old['info_status'] == 'deleted')
{
return lang('New %1 created by %2 at %3',lang($this->infolog->enums['type'][$data['info_type']]),
$GLOBALS['egw']->common->grab_owner_name($this->infolog->user),$this->datetime(time()));
}
elseif($data['info_status'] == 'deleted')
{
return lang('%1 deleted by %2 at %3',lang($this->infolog->enums['type'][$data['info_type']]),
$GLOBALS['egw']->common->grab_owner_name($data['info_modifier']),
$this->datetime($data['info_datemodified']-$this->infolog->tz_offset_s));
}
return lang('%1 modified by %2 at %3',lang($this->infolog->enums['type'][$data['info_type']]),
$GLOBALS['egw']->common->grab_owner_name($data['info_modifier']),
$this->datetime($data['info_datemodified']-$this->infolog->tz_offset_s));
@ -184,7 +229,7 @@ class infolog_tracking extends bo_tracking
'info_cat' => $data['info_cat'] ? $GLOBALS['egw']->categories->id2name($data['info_cat']) : '',
'info_priority' => lang($this->infolog->enums['priority'][$data['info_priority']]),
'info_owner' => $GLOBALS['egw']->common->grab_owner_name($data['info_owner']),
'info_status' => lang($this->infolog->status[$data['info_type']][$data['info_status']]),
'info_status' => lang($data['info_status']=='deleted'?'deleted':$this->infolog->status[$data['info_type']][$data['info_status']]),
'info_percent' => (int)$data['info_percent'].'%',
'info_datecompleted' => $data['info_datecomplete'] ? $this->datetime($data['info_datecompleted']-$this->infolog->tz_offset_s) : '',
'info_location' => $data['info_location'],
@ -209,7 +254,7 @@ class infolog_tracking extends bo_tracking
{
foreach($this->infolog->customfields as $name => $field)
{
if ($field['type2'] && $field['type2'] != $data['info_type']) continue; // different type
if ($field['type2'] && !in_array($data['info_type'],explode(',',$field['type2']))) continue; // different type
if (!$header_done)
{
@ -219,7 +264,7 @@ class infolog_tracking extends bo_tracking
);
$header_done = true;
}
$details[$name] = array(
$details['#'.$name] = array(
'label' => $field['label'],
'value' => $data['#'.$name],
);
@ -227,4 +272,27 @@ class infolog_tracking extends bo_tracking
}
return $details;
}
/**
* Save changes to the history log
*
* Reimplemented to store all customfields in a single field, as the history-log has only 2-char field-ids
*
* @param array $data current entry
* @param array $old=null old/last state of the entry or null for a new entry
* @param int number of log-entries made
*/
function save_history($data,$old)
{
$data_custom = $old_custom = array();
foreach($this->infolog->customfields as $name => $custom)
{
if (isset($data['#'.$name]) && (string)$data['#'.$name]!=='') $data_custom[] = $custom['label'].': '.$data['#'.$name];
if (isset($old['#'.$name]) && (string)$old['#'.$name]!=='') $old_custom[] = $custom['label'].': '.$old['#'.$name];
}
$data['custom'] = implode("\n",$data_custom);
$old['custom'] = implode("\n",$old_custom);
return parent::save_history($data,$old);
}
}

View File

@ -262,21 +262,24 @@ class soinfolog // DB-Layer
/**
* generate sql to filter based on the status of the log-entry
*
* @param $filter done = done or billed, open = not ()done or billed), offer = offer
* @param string $filter done = done or billed, open = not (done, billed, cancelled or deleted), offer = offer
* @param boolean $prefix_and=true if true prefix the fileter with ' AND '
* @return string the necesary sql
*/
function statusFilter($filter = '')
function statusFilter($filter = '',$prefix_and=true)
{
preg_match('/(done|open|offer)/',$filter,$vars);
preg_match('/(done|open|offer|deleted)/',$filter,$vars);
$filter = $vars[1];
switch ($filter)
{
case 'done': return " AND info_status IN ('done','billed','cancelled')";
case 'open': return " AND NOT (info_status IN ('done','billed','cancelled'))";
case 'offer': return " AND info_status = 'offer'";
case 'done': $filter = "info_status IN ('done','billed','cancelled')"; break;
case 'open': $filter = "NOT (info_status IN ('done','billed','cancelled','deleted'))"; break;
case 'offer': $filter = "info_status = 'offer'"; break;
case 'deleted': $filter = "info_status = 'deleted'"; break;
default: $filter = "info_status <> 'deleted'"; break;
}
return '';
return ($prefix_and ? ' AND ' : '').$filter;
}
/**
@ -444,6 +447,26 @@ class soinfolog // DB-Layer
// set parent_id to $new_parent or 0 for all not deleted children
$this->db->update($this->info_table,array('info_id_parent'=>$new_parent),array('info_id_parent'=>$info_id),__LINE__,__FILE__);
}
/**
* Return array with children of $info_id as info_id => info_owner pairs
*
* @param int $info_id
* @return array with info_id => info_owner pairs
*/
function get_children($info_id)
{
$this->db->select($this->info_table,'info_id,info_owner',array(
'info_id_parent' => $info_id,
),__LINE__,__FILE__);
$children = array();
while (($row = $this->db->row(true)))
{
$children[$row['info_id']] = $row['info_owner'];
}
return $children;
}
/**
* changes or deletes entries with a spezified owner (for hook_delete_account)
@ -466,6 +489,7 @@ class soinfolog // DB-Layer
{
$this->db->update($this->info_table,array('info_owner'=>$new_owner),array('info_owner'=>$owner),__LINE__,__FILE__);
}
// ToDo: does not work with multiple owners!!!
$this->db->update($this->info_table,array('info_responsible'=>$new_owner),array('info_responsible'=>$owner),__LINE__,__FILE__);
}
@ -560,7 +584,7 @@ class soinfolog // DB-Layer
//echo "<p>anzSubs($info_id) = ".$this->db->f(0)." ($sql)</p>\n";
return $this->db->f(0);
}
/**
* searches InfoLog for a certain pattern in $query
*
@ -743,7 +767,7 @@ class soinfolog // DB-Layer
{
$users[] = $this->db->f(0);
}
$this->db->select($this->info_table,'DISTINCT info_responsible',str_replace(' AND ','',$this->statusFilter('open')),__LINE__,__FILE__);
$this->db->select($this->info_table,'DISTINCT info_responsible',$this->statusFilter('open',false),__LINE__,__FILE__);
while ($this->db->next_record())
{
foreach(explode(',',$this->db->f(0)) as $responsible)

View File

@ -142,6 +142,10 @@ class uiinfolog
$this->duration_format = str_replace(',','',$pm_config->config_data['duration_units']).','.$pm_config->config_data['hours_per_workday'];
unset($pm_config);
}
if ($this->bo->history)
{
$this->filters['deleted'] = 'deleted';
}
/* these are just for testing of the notifications
for($i = -1; $i <= 3; ++$i)
{
@ -196,7 +200,8 @@ class uiinfolog
$readonlys["close[$id]"] = $done || ($readonlys["edit_status[$id]"] =
!($this->bo->check_access($info,EGW_ACL_EDIT) || $this->bo->is_responsible($info)));
$readonlys["edit_status[$id]"] = $readonlys["edit_percent[$id]"] =
!$this->bo->check_access($info,EGW_ACL_EDIT) && !$this->bo->is_responsible($info);
!$this->bo->check_access($info,EGW_ACL_EDIT) && !$this->bo->is_responsible($info) &&
!$this->bo->check_access($info,EGW_ACL_UNDELETE); // undelete is handled like status edit
$readonlys["delete[$id]"] = !$this->bo->check_access($info,EGW_ACL_DELETE);
$readonlys["sp[$id]"] = !$this->bo->check_access($info,EGW_ACL_ADD);
$readonlys["view[$id]"] = $info['info_anz_subs'] < 1;
@ -237,7 +242,8 @@ class uiinfolog
}
}
$info['info_type_label'] = $this->bo->enums['type'][$info['info_type']];
$info['info_status_label'] = $this->bo->status[$info['info_type']][$info['info_status']];
$info['info_status_label'] = isset($this->bo->status[$info['info_type']][$info['info_status']]) ?
$this->bo->status[$info['info_type']][$info['info_status']] : $info['info_status'];
if (!$this->prefs['show_percent'] || $this->prefs['show_percent'] == 2 && !$details)
{
@ -691,7 +697,7 @@ class uiinfolog
*/
function edit($content = null,$action = '',$action_id=0,$type='',$referer='')
{
$tabs = 'description|links|delegation|project|customfields';
$tabs = 'description|links|delegation|project|customfields|history';
if (is_array($content))
{
@ -722,9 +728,10 @@ class uiinfolog
{
$old = $this->bo->read($info_id);
$status_only = $this->bo->is_responsible($old);
$undelete = $this->bo->check_access($old,EGW_ACL_UNDELETE);
}
}
if (($button == 'save' || $button == 'apply') && (!$info_id || $edit_acl || $status_only))
if (($button == 'save' || $button == 'apply') && (!$info_id || $edit_acl || $status_only || $undelete))
{
if ($content['info_contact'])
{
@ -912,7 +919,9 @@ class uiinfolog
}
else
{
if ($info_id && !$this->bo->check_access($info_id,EGW_ACL_EDIT) && !$this->bo->is_responsible($content))
if ($info_id && !$this->bo->check_access($info_id,EGW_ACL_EDIT) &&
!($undelete = $this->bo->check_access($info_id,EGW_ACL_UNDELETE)) &&
!$this->bo->is_responsible($content))
{
if ($no_popup)
{
@ -1018,7 +1027,7 @@ class uiinfolog
}
$preserv = $content;
// for implizit edit of responsible user make all fields readonly, but status and percent
if ($info_id && !$this->bo->check_access($info_id,EGW_ACL_EDIT) && $this->bo->is_responsible($content))
if ($info_id && !$this->bo->check_access($info_id,EGW_ACL_EDIT) && $this->bo->is_responsible($content) && !$undelete)
{
$content['status_only'] = !in_array('link_to',$this->bo->responsible_edit);
foreach(array_diff(array_merge(array_keys($content),array('pm_id')),$this->bo->responsible_edit) as $name)
@ -1032,6 +1041,9 @@ class uiinfolog
$readonlys['#'.$name] = true;
}
}
// ToDo: use the old status before the delete
if ($undelete) $content['info_status'] = $this->bo->status['defaults'][$content['info_type']];
$content['hide_from_css'] = $content['info_custom_from'] ? '' : 'hideFrom';
if (!($readonlys['button[delete]'] = !$info_id || !$this->bo->check_access($info_id,EGW_ACL_DELETE)))
@ -1051,7 +1063,7 @@ class uiinfolog
}
else
{
$readonlys[$tabs] = array('customfields' => true);
$readonlys[$tabs]['customfields'] = true;
}
if (!isset($GLOBALS['egw_info']['user']['apps']['projectmanager']))
{
@ -1066,6 +1078,44 @@ class uiinfolog
$old_pm_id = is_array($pm_links) ? array_shift($pm_links) : $content['old_pm_id'];
if (!isset($content['pm_id']) && $old_pm_id) $content['pm_id'] = $old_pm_id;
if ($info_id && $this->bo->history)
{
$content['history'] = array(
'id' => $info_id,
'app' => 'infolog',
'status-widgets' => array(
'Ty' => $types,
//'Li', // info_link_id
'Ca' => 'select-cat',
'Pr' => $this->bo->enums['priority'],
'Ow' => 'select-account',
//'Ac', // info_access: private||public
'St' => $this->bo->status[$content['info_type']]+array('deleted' => 'deleted'),
'Pe' => 'select-percent',
'Co' => 'date-time',
'st' => 'date-time',
'En' => 'date',
'Re' => 'select-account',
// PM fields, ToDo: access control!!!
'pT' => 'date-duration',
'uT' => 'date-duration',
// 'pL' => 'projectmanager-pricelist',
'pr' => 'float',
),
);
$history_stati = array();
require_once(EGW_INCLUDE_ROOT.'/infolog/inc/class.infolog_tracking.inc.php');
$tracking = new infolog_tracking($this);
foreach($tracking->field2history as $field => $history)
{
$history_stati[$history] = $tracking->field2label[$field];
}
unset($tracking);
}
else
{
$readonlys[$tabs]['history'] = true;
}
$GLOBALS['egw_info']['flags']['app_header'] = lang('InfoLog').' - '.
($content['status_only'] ? lang('Edit Status') : lang('Edit'));
$GLOBALS['egw_info']['flags']['params']['manual'] = array('page' => ($info_id ? 'ManualInfologEdit' : 'ManualInfologAdd'));
@ -1074,7 +1124,8 @@ class uiinfolog
'info_type' => $types,
'info_priority' => $this->bo->enums['priority'],
'info_confirm' => $this->bo->enums['confirm'],
'info_status' => $this->bo->status[$content['info_type']]
'info_status' => $this->bo->status[$content['info_type']],
'status' => $history_stati,
),$readonlys,$preserv+array( // preserved values
'info_id' => $info_id,
'action' => $action,
@ -1110,6 +1161,33 @@ class uiinfolog
return $icon ? $this->html->image('infolog',$icon,lang($alt),'border=0') : lang($alt);
}
/**
* stripping slashes from an array
*
* @static
* @param array $arr
* @return array
*/
function array_stripslashes($arr)
{
foreach($arr as $key => $val)
{
if (is_array($val))
{
$arr[$key] = self::array_stripslashes($var);
}
else
{
$arr[$key] = stripslashes($val);
}
}
return $arr;
}
/**
* Infolog's site configuration
*
*/
function admin( )
{
$fields = array(
@ -1126,41 +1204,43 @@ class uiinfolog
);
if($_POST['save'] || $_POST['apply'])
{
$this->link_pathes = $this->bo->send_file_ips = array();
if (get_magic_quotes_gpc())
{
$_POST = self::array_stripslashes($_POST);
}
$this->bo->config->config_data['link_pathes'] = $this->bo->link_pathes = array();
$this->bo->config->config_data['send_file_ips'] = $this->bo->send_file_ips = array();
$valid = get_var('valid',Array('POST'));
$trans = get_var('trans',Array('POST'));
$ip = get_var('ip',Array('POST'));
while(list($key,$val) = each($valid))
foreach($valid as $key => $val)
{
if($val = stripslashes($val))
if($val)
{
$this->link_pathes[$val] = stripslashes($trans[$key]);
$this->bo->send_file_ips[$val] = stripslashes($ip[$key]);
$this->bo->config->config_data['link_pathes'][$val] = $this->bo->link_pathes[$val] = $trans[$key];
$this->bo->config->config_data['send_file_ips'][$val] = $this->bo->send_file_ips[$val] = $ip[$key];
}
}
$this->bo->responsible_edit = array('info_status','info_percent','info_datecompleted');
if ($_POST['responsible_edit'])
{
$extra = array_intersect($_POST['responsible_edit'],array_keys($fields));
$this->bo->responsible_edit = array_merge($this->bo->responsible_edit,$extra);
$this->bo->config->config_data['responsible_edit'] = $this->bo->responsible_edit = array_merge($this->bo->responsible_edit,$extra);
}
$this->bo->implicit_rights = $_POST['implicit_rights'] == 'edit' ? 'edit' : 'read';
$this->bo->config->config_data['implicit_rights'] = $this->bo->implicit_rights = $_POST['implicit_rights'] == 'edit' ? 'edit' : 'read';
$this->bo->config->config_data['history'] = $this->bo->history = $_POST['history'];
$this->bo->config->config_data += array( // only "adding" the changed items, to not delete other config like custom fields
'link_pathes' => $this->link_pathes,
'send_file_ips' => $this->bo->send_file_ips,
'implicit_rights' => $this->bo->implicit_rights,
'responsible_edit' => is_array($extra) ? implode(',',$extra) : $extra,
);
$this->bo->config->save_repository(True);
}
if($_POST['cancel'] || $_POST['save'])
{
$GLOBALS['egw']->redirect_link('/admin/index.php');
$GLOBALS['egw']->redirect_link('/infolog/index.php');
}
$GLOBALS['egw_info']['flags']['app_header'] = lang('InfoLog').' - '.lang('Configuration');
$GLOBALS['egw_info']['flags']['app_header'] = lang('InfoLog').' - '.lang('Site configuration');
$GLOBALS['egw']->common->egw_header();
$GLOBALS['egw']->template->set_file(array('info_admin_t' => 'admin.tpl'));
@ -1183,16 +1263,24 @@ class uiinfolog
'cancel_button' => $this->html->submit_button('cancel','Cancel'),
'lang_valid' => lang('valid path on clientside<br>eg. \\\\Server\\Share or e:\\'),
'lang_trans' => lang('path on (web-)serverside<br>eg. /var/samba/Share'),
'lang_ip' => lang('reg. expr. for local IP\'s<br>eg. ^192\\.168\\.1\\.')
'lang_ip' => lang('reg. expr. for local IP\'s<br>eg. ^192\\.168\\.1\\.'),
'lang_history'=> lang('History logging'),
'lang_history2'=> lang('History logging and deleting of items'),
'history' => $this->html->select('history',$this->bo->history,array(
'' => lang('No'),
'history' => lang('Yes, with purging of deleted items possible'),
'history_admin_delete' => lang('Yes, only admins can purge deleted items'),
'history_no_delete' => lang('Yes, noone can purge deleted items'),
))
));
if (!is_array($this->bo->send_file_ips))
{
$this->bo->send_file_ips = $this->link_pathes = array();
$this->bo->send_file_ips = $this->bo->link_pathes = array();
}
$i = 0; @reset($this->link_pathes);
$i = 0; @reset($this->bo->link_pathes);
do {
list($valid,$trans) = @each($this->link_pathes);
list($valid,$trans) = @each($this->bo->link_pathes);
$GLOBALS['egw']->template->set_var(array(
'tr_color' => $i & 1 ? 'row_off' : 'row_on',
'num' => $i+1,
@ -1322,23 +1410,6 @@ class uiinfolog
exit;
}
/**
* writes langfile with all templates and messages registered here
*
* called via [write Langfile] in the etemplate-editor or as http://domain/egroupware/index.php?menuaction=infolog.uiinfolog.writeLangFile
*/
function writeLangFile()
{
$extra = $this->messages + $this->filters;
$enums = $this->bo->enums + $this->bo->status;
unset($enums['defaults']);
foreach($enums as $key => $msg_arr)
{
$extra += $msg_arr;
}
return $this->tmpl->writeLangFile('infolog','en',$extra);
}
/**
* shows infolog in other applications
*

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,7 @@
%1 days in advance infolog de %1 Tage im Vorraus
%1 deleted infolog de %1 gelöscht
%1 deleted by %2 at %3 infolog de %1 wurde von %2 am %3 gelöscht
%1 modified infolog de %1 geändert
%1 modified by %2 at %3 infolog de %1 wurde von %2 am %3 geändert
%1 records imported infolog de %1 Datensätze importiert
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog de %1 Datensätze gelesen (noch nicht importiert, sie können %2zurück%3 gehen und Test Import ausschalten)
@ -97,6 +100,7 @@ delete one record by passing its id. infolog de Einen Datensatz spezifiziert dur
delete the entry infolog de Eintrag löschen
delete this entry infolog de diesen Eintrag löschen
delete this entry and all listed sub-entries infolog de Diesen Eintrag und all aufgelisteten Untereinträge löschen
deleted infolog de gelöscht
deletes the selected typ infolog de löscht den ausgewählten Typ
deletes this field infolog de löscht dieses Feld
deletes this status infolog de löscht diesen Status
@ -142,6 +146,8 @@ from infolog de Von
general infolog de Allgemein
group owner for infolog de Gruppeneigentümer für
high infolog de hoch
history logging infolog de Protokollierung der Historie
history logging and deleting of items infolog de Protokollierung der Historie und löschen von Einträgen
id infolog de Id
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog de Wenn ein Typ einen Gruppeneigentümer hat, gehören alle Einträge dieses Typs der angegebenen Gruppe und NICHT dem Benutzer der sie angelegt hat!
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog de Falls nicht gesetzt, wird die Suche und die Filter ausgeblendet für weniger Einträge als "maximale Treffer pro Seite" (in ihren allg. Einstellungen definiert).
@ -181,6 +187,7 @@ max length of the input [, length of the inputfield (optional)] infolog de max.
name must not be empty !!! infolog de Name darf nicht leer sein !!!
name of new type to create infolog de Name des neu anzulegenden Types
never hide search and filters infolog de Suche und Filter niemals ausblenden
new %1 infolog de Neue %1
new %1 created by %2 at %3 infolog de Neue %1 wurde von %2 am %3 angelegt
new name infolog de neuer name
new search infolog de Neue Suche
@ -322,7 +329,6 @@ urgent infolog de Dringend
used time infolog de benötigte Zeit
valid path on clientside<br>eg. \\server\share or e:\ infolog de gültiger Pfad clientseitig<br>zB. \\Server\Share oder e:\
valid path on clientside<br>eg. \servershare or e: infolog de gültiger Pfad clientseitig<br>zB. \\Server\Share oder e:\
valid path on clientside<br>eg. servershare or e: infolog de gültiger Pfad clientseitig<br>zB. \\Server\Share oder e:\
values for selectbox infolog de Werte für die Auswahlbox
view all subs of this entry infolog de alle Untereinträge dieses Eintrag anzeigen
view other subs infolog de andere Untereinträge anzeigen
@ -337,6 +343,9 @@ will-call infolog de ruft zur
write (add or update) a record by passing its fields. infolog de Schreiben (zufügen oder aktualisieren) eines Datensatzes durch Angabe seiner Felder.
yes - delete infolog de Ja - Löschen
yes - delete including sub-entries infolog de Ja - Löschen einschließlich Untereinträge
yes, noone can purge deleted items infolog de Ja, niemand darf gelöschte Einträge bereinigen
yes, only admins can purge deleted items infolog de Ja, nur Admins dürfen gelöschte Einträge bereinigen
yes, with purging of deleted items possible infolog de Ja, jeder darf gelöschte Einträge bereinigen
you can't delete one of the stock types !!! infolog de Sie können keinen der Standardtypen löschen!!!
you have entered an invalid ending date infolog de Sie haben ein ungültiges Fälligkeitsdatum eingegeben
you have entered an invalid starting date infolog de Sie haben ein ungültiges Startdatum eingegeben

View File

@ -1,4 +1,7 @@
%1 days in advance infolog en %1 days in advance
%1 deleted infolog en %1 deleted
%1 deleted by %2 at %3 infolog en %1 deleted by %2 at %3
%1 modified infolog en %1 modified
%1 modified by %2 at %3 infolog en %1 modified by %2 at %3
%1 records imported infolog en %1 records imported
%1 records read (not yet imported, you may go %2back%3 and uncheck test import) infolog en %1 records read (not yet imported, you may go %2back%3 and uncheck Test Import)
@ -97,6 +100,7 @@ delete one record by passing its id. infolog en Delete one record by passing its
delete the entry infolog en Delete the entry
delete this entry infolog en delete this entry
delete this entry and all listed sub-entries infolog en Delete this entry and all listed sub-entries
deleted infolog en deleted
deletes the selected typ infolog en deletes the selected type
deletes this field infolog en deletes this field
deletes this status infolog en deletes this status
@ -142,6 +146,8 @@ from infolog en From
general infolog en General
group owner for infolog en Group owner for
high infolog en high
history logging infolog en History logging
history logging and deleting of items infolog en History logging and deleting of items
id infolog en Id
if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog en If a type has a group owner, all entries of that type will be owned by the given group and NOT the user who created it!
if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog en If not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences).
@ -181,6 +187,7 @@ max length of the input [, length of the inputfield (optional)] infolog en max l
name must not be empty !!! infolog en Name must not be empty !!!
name of new type to create infolog en name of new type to create
never hide search and filters infolog en Never hide search and filters
new %1 infolog en New %1
new %1 created by %2 at %3 infolog en New %1 created by %2 at %3
new name infolog en new name
new search infolog en New search
@ -334,6 +341,9 @@ will-call infolog en will call
write (add or update) a record by passing its fields. infolog en Write (add or update) a record by passing its fields.
yes - delete infolog en Yes - Delete
yes - delete including sub-entries infolog en Yes - Delete including sub-entries
yes, noone can purge deleted items infolog en Yes, noone can purge deleted items
yes, only admins can purge deleted items infolog en Yes, only admins can purge deleted items
yes, with purging of deleted items possible infolog en Yes, with purging of deleted items possible
you can't delete one of the stock types !!! infolog en You can't delete one of the stock types !!!
you have entered an invalid ending date infolog en You have entered an invalid due date
you have entered an invalid starting date infolog en You have entered an invalid starting date

View File

@ -22,8 +22,12 @@
<td colspan="3">{lang_responsible_edit}</td>
<td>{responsible_edit}</td>
</tr>
<tr class="th">
<td colspan="4"><b>{lang_history}</b></td>
</tr>
<tr class="row_off">
<td colspan="4">&nbsp;</td>
<td colspan="3">{lang_history2}</td>
<td>{history}</td>
</tr>
<tr class="th">
<td colspan="4">{text}</td>

View File

@ -126,7 +126,19 @@
</rows>
</grid>
</template>
<template id="infolog.edit" template="" lang="" group="0" version="1.3.001">
<template id="infolog.edit.history" template="" lang="" group="0" version="1.3.002">
<grid width="100%" height="250" overflow="auto">
<columns>
<column/>
</columns>
<rows>
<row valign="top">
<historylog id="history"/>
</row>
</rows>
</grid>
</template>
<template id="infolog.edit" template="" lang="" group="0" version="1.3.002">
<grid width="100%">
<columns>
<column width="103"/>
@ -180,6 +192,7 @@
<tab label="Delegation" statustext="responsible user, priority"/>
<tab label="Projectmanager" statustext="Project settings: price, times"/>
<tab label="Customfields" statustext="Custom fields"/>
<tab label="History" statustext="Change history"/>
</tabs>
<tabpanels>
<template id="infolog.edit.description"/>
@ -187,6 +200,7 @@
<template id="infolog.edit.delegation"/>
<template id="infolog.edit.project"/>
<template id="infolog.edit.customfields"/>
<template id="infolog.edit.history"/>
</tabpanels>
</tabbox>
</row>