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
* EGroupare - InfoLog - Storage object
2006-10-04 19:40:33 +02:00
*
* @ link http :// www . egroupware . org
* @ author Ralf Becker < RalfBecker - AT - outdoor - training . de >
* @ 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
*/
2016-04-30 19:05:23 +02:00
use EGroupware\Api ;
use EGroupware\Api\Link ;
use EGroupware\Api\Acl ;
2006-10-04 19:40:33 +02:00
/**
* storage object / db - layer for InfoLog
*
* all values passed to this class are run either through intval or addslashes to prevent query - insertion
* and for pgSql 7.3 compatibility
*/
2008-10-19 13:34:12 +02:00
class infolog_so
2006-10-04 19:40:33 +02:00
{
2006-10-23 13:50:30 +02:00
/**
* Instance of the db class
*
2016-04-30 19:05:23 +02:00
* @ var Api\Db
2006-10-23 13:50:30 +02:00
*/
2006-10-04 19:40:33 +02:00
var $db ;
2006-10-23 13:50:30 +02:00
/**
* Grants from other users
*
* @ var array
*/
2006-10-04 19:40:33 +02:00
var $grants ;
2006-10-23 13:50:30 +02:00
/**
* Internal data array
*
* @ var array
*/
2006-10-04 19:40:33 +02:00
var $data = array ( );
2006-10-23 13:50:30 +02:00
/**
* Current user ( account_id )
*
* @ var int
*/
2006-10-04 19:40:33 +02:00
var $user ;
2006-10-23 13:50:30 +02:00
/**
* Infolog table - name
*
* @ var string
*/
2006-10-04 19:40:33 +02:00
var $info_table = 'egw_infolog' ;
2006-10-23 13:50:30 +02:00
/**
* Infolog custom fileds table - name
*
* @ var string
*/
2006-10-04 19:40:33 +02:00
var $extra_table = 'egw_infolog_extra' ;
2016-09-11 13:03:54 +02:00
/**
* Infolog delegation / iCal attendees
*
* @ var string
*/
var $users_table = 'egw_infolog_users' ;
2006-10-23 13:50:30 +02:00
/**
* Offset between server - and user - time in h
*
* @ var int
*/
2007-12-14 14:11:29 +01:00
var $tz_offset ;
2005-04-06 13:05:57 +02:00
/**
2007-03-12 12:27:33 +01:00
* Constructor
*
2016-04-30 19:05:23 +02:00
* @ param array $grants = array ()
2007-03-12 12:27:33 +01:00
* @ return soinfolog
2005-04-06 13:05:57 +02:00
*/
2008-10-22 08:15:37 +02:00
function __construct ( $grants = array () )
2001-07-12 01:17:32 +02:00
{
2006-10-04 19:40:33 +02:00
$this -> db = clone ( $GLOBALS [ 'egw' ] -> db );
$this -> db -> set_app ( 'infolog' );
2008-10-22 08:15:37 +02:00
$this -> grants = $grants ;
2006-10-04 19:40:33 +02:00
$this -> user = $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ];
2003-06-14 15:51:53 +02:00
2006-10-04 19:40:33 +02:00
$this -> tz_offset = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'tz_offset' ];
}
2003-09-08 02:40:42 +02:00
2006-10-24 12:08:21 +02:00
/**
2009-11-18 18:41:54 +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
2016-09-12 10:55:39 +02:00
* @ param int $user = null user to check for , default $this -> user
2006-10-24 12:08:21 +02:00
* @ return boolean
*/
2011-06-26 14:32:06 +02:00
function is_responsible ( $info , $user = null )
2006-10-24 12:08:21 +02:00
{
2011-06-26 14:32:06 +02:00
if ( ! $user ) $user = $this -> user ;
2016-09-12 10:55:39 +02:00
return self :: is_responsible_user ( $info , $user );
}
/**
* Check if user is responsible for an entry : he or one of his memberships is in responsible
*
* @ param array $info infolog entry as array
* @ param int $user = null user to check for
* @ return boolean
*/
static function is_responsible_user ( $info , $user )
{
2011-06-26 14:32:06 +02:00
static $um_cache = array ();
2016-09-12 10:55:39 +02:00
$user_and_memberships =& $um_cache [ $user ];
2011-06-26 14:32:06 +02:00
if ( ! isset ( $user_and_memberships ))
2006-10-24 12:08:21 +02:00
{
2011-06-26 14:32:06 +02:00
$user_and_memberships = $GLOBALS [ 'egw' ] -> accounts -> memberships ( $user , true );
$user_and_memberships [] = $user ;
2006-10-24 12:08:21 +02:00
}
2009-03-27 15:10:18 +01:00
return $info [ 'info_responsible' ] && array_intersect (( array ) $info [ 'info_responsible' ], $user_and_memberships );
2006-10-24 12:08:21 +02:00
}
2006-10-04 19:40:33 +02:00
/**
* checks if user has the $required_rights to access $info_id ( private access is handled too )
*
2009-05-05 14:49:15 +02:00
* @ param array | int $info data or info_id of InfoLog entry
2006-10-04 19:40:33 +02:00
* @ param int $required_rights EGW_ACL_xyz anded together
2016-04-30 19:05:23 +02:00
* @ param boolean $implicit_edit = false responsible has only implicit read and add rigths , unless this is set to true
* @ param array $grants = null grants to use , default ( null ) $this -> grants
* @ param int $user = null user to check , default ( null ) $this -> user
2006-10-04 19:40:33 +02:00
* @ return boolean True if access is granted else False
*/
2011-06-26 14:32:06 +02:00
function check_access ( $info , $required_rights , $implicit_edit = false , array $grants = null , $user = null )
2006-10-04 19:40:33 +02:00
{
2011-06-26 14:32:06 +02:00
if ( is_null ( $grants )) $grants = $this -> grants ;
if ( ! $user ) $user = $this -> user ;
2012-04-03 18:06:42 +02:00
// if info-array, but no owner given, force reading of info from db
if ( is_array ( $info ) && ! $info [ 'info_owner' ]) $info = $info [ 'info_id' ];
2006-10-04 19:40:33 +02:00
if ( is_array ( $info ))
{
2008-07-18 09:16:44 +02:00
2006-10-04 19:40:33 +02:00
}
elseif (( int ) $info != $this -> data [ 'info_id' ]) // already loaded?
{
// dont change our own internal data,
2011-04-11 11:29:39 +02:00
$backup_data = $this -> data ;
2011-07-07 10:19:31 +02:00
$info = $this -> read ( array ( 'info_id' => $info ));
2011-04-11 11:29:39 +02:00
$this -> data = $backup_data ;
2006-10-04 19:40:33 +02:00
}
else
{
$info = $this -> data ;
}
if ( ! $info )
{
return False ;
2001-07-12 01:17:32 +02:00
}
2006-10-04 19:40:33 +02:00
$owner = $info [ 'info_owner' ];
2011-06-26 14:32:06 +02:00
$access_ok = $owner == $user || // user has all rights
2006-10-04 19:40:33 +02:00
// ACL only on public entrys || $owner granted _PRIVATE
2011-06-26 14:32:06 +02:00
( !! ( $grants [ $owner ] & $required_rights ) ||
2011-06-26 15:18:30 +02:00
$this -> is_responsible ( $info , $user ) && // implicite rights for responsible user(s) and his memberships
2016-04-30 19:05:23 +02:00
( $required_rights == Acl :: READ || $required_rights == Acl :: ADD || $implicit_edit && $required_rights == Acl :: EDIT )) &&
( $info [ 'info_access' ] == 'public' || !! ( $this -> grants [ $user ] & Acl :: PRIVAT ));
2006-10-04 19:40:33 +02:00
2011-06-26 14:32:06 +02:00
// error_log(__METHOD__."($info[info_id],$required_rights,$implicit_edit,".array2string($grants).",$user) returning ".array2string($access_ok));
2006-10-04 19:40:33 +02:00
return $access_ok ;
}
2008-07-18 09:16:44 +02:00
2006-10-24 12:08:21 +02:00
/**
* Filter for a given responsible user : info_responsible either contains a the user or one of his memberships
*
2010-01-21 04:00:06 +01:00
* @ param int | array $users one or more account_ids
2016-09-11 13:03:54 +02:00
* @ param boolean $deleted_too = false true : also use deleted entries
2006-10-24 12:08:21 +02:00
* @ return string
*/
2016-09-11 13:03:54 +02:00
function responsible_filter ( $users , $deleted_too = false )
2006-10-24 12:08:21 +02:00
{
2010-01-21 04:00:06 +01:00
if ( ! $users ) return '0' ;
2006-10-24 12:08:21 +02:00
2010-01-21 04:00:06 +01:00
$responsible = array ();
foreach (( array ) $users as $user )
{
2010-03-15 10:55:16 +01:00
$responsible = array_merge ( $responsible ,( array )
( $user > 0 ? $GLOBALS [ 'egw' ] -> accounts -> memberships ( $user , true ) :
$GLOBALS [ 'egw' ] -> accounts -> members ( $user , true )));
2010-01-21 04:00:06 +01:00
$responsible [] = $user ;
}
if ( is_array ( $users ))
{
$responsible = array_unique ( $responsible );
}
2017-12-02 03:23:31 +01:00
$sql = " $this->users_table .account_id IN ( " . implode ( ',' , array_map ( array ( $this -> db , 'quote' ), $responsible )) . ')' ;
2016-09-11 13:03:54 +02:00
if ( ! $deleted_too )
2006-10-24 12:08:21 +02:00
{
2016-09-11 13:03:54 +02:00
// we use NULL or true, not false!
$sql .= " AND $this->users_table .info_res_deleted IS NULL " ;
2006-10-24 12:08:21 +02:00
}
2016-09-11 13:03:54 +02:00
return $sql ;
2006-10-24 12:08:21 +02:00
}
2006-10-04 19:40:33 +02:00
/**
* generate sql to be AND ' ed into a query to ensure ACL is respected ( incl . _PRIVATE )
*
2016-04-30 19:05:23 +02:00
* @ param string $_filter '' | all - list all entrys user have rights to see < br >
2008-07-18 09:16:44 +02:00
* private | own - list only his personal entrys ( incl . those he is responsible for !!! ),
* responsible | my = entries the user is responsible for
2007-06-10 11:21:04 +02:00
* delegated = entries the user delegated to someone else
2006-10-04 19:40:33 +02:00
* @ return string the necesary sql
*/
2016-04-30 19:05:23 +02:00
function aclFilter ( $_filter = False )
2006-10-04 19:40:33 +02:00
{
2014-01-28 10:22:12 +01:00
$vars = null ;
2016-09-12 16:25:27 +02:00
preg_match ( '/(my|responsible|delegated|own|privat|private|all|user)([0-9,-]*)(\+deleted)?/' , $_filter , $vars );
2006-10-04 19:40:33 +02:00
$filter = $vars [ 1 ];
2010-01-21 04:00:06 +01:00
$f_user = $vars [ 2 ];
2016-09-12 10:55:39 +02:00
$deleted_too = ! empty ( $vars [ 3 ]);
2001-07-12 01:17:32 +02:00
2006-10-04 19:40:33 +02:00
if ( isset ( $this -> acl_filter [ $filter . $f_user ]))
2001-07-14 23:44:01 +02:00
{
2006-10-04 19:40:33 +02:00
return $this -> acl_filter [ $filter . $f_user ]; // used cached filter if found
}
2010-01-21 04:00:06 +01:00
if ( $f_user && strpos ( $f_user , ',' ) !== false )
{
$f_user = explode ( ',' , $f_user );
}
2006-10-24 12:08:21 +02:00
2007-06-10 11:21:04 +02:00
$filtermethod = " (info_owner= $this->user " ; // user has all rights
2008-07-18 09:16:44 +02:00
2007-06-10 11:21:04 +02:00
if ( $filter == 'my' || $filter == 'responsible' )
{
2016-09-11 13:03:54 +02:00
$filtermethod .= " AND $this->users_table .account_id IS NULL " ;
2007-06-10 11:21:04 +02:00
}
if ( $filter == 'delegated' )
{
2016-09-11 13:03:54 +02:00
$filtermethod .= " AND $this->users_table .account_id IS NOT NULL) " ;
2007-06-10 11:21:04 +02:00
}
else
2006-10-04 19:40:33 +02:00
{
2007-06-10 11:21:04 +02:00
if ( is_array ( $this -> grants ))
2001-07-14 23:44:01 +02:00
{
2007-06-10 11:21:04 +02:00
foreach ( $this -> grants as $user => $grant )
2001-07-14 23:44:01 +02:00
{
2007-06-10 11:21:04 +02:00
// echo "<p>grants: user=$user, grant=$grant</p>";
if ( $grant & ( EGW_ACL_READ | EGW_ACL_EDIT ))
{
$public_user_list [] = $user ;
}
2016-04-30 19:05:23 +02:00
if ( $grant & Acl :: PRIVAT )
2007-06-10 11:21:04 +02:00
{
$private_user_list [] = $user ;
}
2001-07-12 01:17:32 +02:00
}
2007-06-10 11:21:04 +02:00
if ( count ( $private_user_list ))
2003-09-07 18:55:36 +02:00
{
2008-10-19 13:34:12 +02:00
$has_private_access = $this -> db -> expression ( $this -> info_table , array ( 'info_owner' => $private_user_list ));
2003-09-07 18:55:36 +02:00
}
2001-07-12 01:17:32 +02:00
}
2008-10-19 13:34:12 +02:00
$public_access = $this -> db -> expression ( $this -> info_table , array ( 'info_owner' => $public_user_list ));
2007-06-10 11:21:04 +02:00
// implicit read-rights for responsible user
2016-09-12 10:55:39 +02:00
$filtermethod .= " OR ( " . $this -> responsible_filter ( $this -> user , $deleted_too ) . ')' ;
2007-06-10 11:21:04 +02:00
// private: own entries plus the one user is responsible for
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 ( $filter == 'private' || $filter == 'privat' || $filter == 'own' )
2005-07-14 09:35:11 +02:00
{
2016-09-12 10:55:39 +02:00
$filtermethod .= " OR ( " . $this -> responsible_filter ( $this -> user , $deleted_too ) .
2007-06-10 11:21:04 +02:00
( $filter == 'own' && count ( $public_user_list ) ? // offer's should show up in own, eg. startpage, but need read-access
2008-10-19 13:34:12 +02:00
" OR info_status = 'offer' AND $public_access " : '' ) . " ) " .
2007-06-10 11:21:04 +02:00
" AND (info_access='public' " . ( $has_private_access ? " OR $has_private_access " : '' ) . ')' ;
2005-07-14 09:35:11 +02:00
}
2007-06-10 11:21:04 +02:00
elseif ( $filter != 'my' && $filter != 'responsible' ) // none --> all entrys user has rights to see
2001-07-14 23:44:01 +02:00
{
2007-06-10 11:21:04 +02:00
if ( $has_private_access )
{
$filtermethod .= " OR $has_private_access " ;
}
if ( count ( $public_user_list ))
{
2008-10-19 13:34:12 +02:00
$filtermethod .= " OR (info_access='public' AND $public_access ) " ;
2007-06-10 11:21:04 +02:00
}
2001-07-14 23:44:01 +02:00
}
2007-06-10 11:21:04 +02:00
$filtermethod .= ') ' ;
2008-07-18 09:16:44 +02:00
2010-01-21 04:00:06 +01:00
if ( $filter == 'user' && $f_user )
2001-07-14 23:44:01 +02:00
{
2010-01-21 04:00:06 +01:00
$filtermethod .= $this -> db -> expression ( $this -> info_table , ' AND (' , array (
'info_owner' => $f_user ,
2016-09-12 10:55:39 +02:00
), " AND $this->users_table .account_id IS NULL OR " , $this -> responsible_filter ( $f_user , $deleted_too ), ')' );
2006-10-04 19:40:33 +02:00
}
}
2016-04-30 19:05:23 +02:00
//echo "<p>aclFilter(filter='$_filter',user='$f_user') = '$filtermethod', privat_user_list=".print_r($privat_user_list,True).", public_user_list=".print_r($public_user_list,True)."</p>\n";
2006-10-04 19:40:33 +02:00
return $this -> acl_filter [ $filter . $f_user ] = $filtermethod ; // cache the filter
}
/**
* generate sql to filter based on the status of the log - entry
*
2016-04-30 19:05:23 +02:00
* @ 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 '
2006-10-04 19:40:33 +02:00
* @ return string the necesary sql
*/
2016-04-30 19:05:23 +02:00
function statusFilter ( $_filter = '' , $prefix_and = true )
2006-10-04 19:40:33 +02:00
{
2014-01-28 10:22:12 +01:00
$vars = null ;
2016-04-30 19:05:23 +02:00
preg_match ( '/(done|open|offer|deleted|\+deleted)/' , $_filter , $vars );
2006-10-04 19:40:33 +02:00
$filter = $vars [ 1 ];
switch ( $filter )
{
2007-06-13 23:37:05 +02:00
case 'done' : $filter = " info_status IN ('done','billed','cancelled') " ; break ;
2007-10-05 17:06:27 +02:00
case 'open' : $filter = " NOT (info_status IN ('done','billed','cancelled','deleted','template','nonactive','archive')) " ; break ;
2007-06-13 23:37:05 +02:00
case 'offer' : $filter = " info_status = 'offer' " ; break ;
case 'deleted' : $filter = " info_status = 'deleted' " ; break ;
2012-09-24 10:53:41 +02:00
case '+deleted' : $filter = " NOT (info_status IN ('template','nonactive','archive')) " ; break ;
2007-10-05 17:06:27 +02:00
default : $filter = " NOT (info_status IN ('deleted','template','nonactive','archive')) " ; break ;
2006-10-04 19:40:33 +02:00
}
2007-06-13 23:37:05 +02:00
return ( $prefix_and ? ' AND ' : '' ) . $filter ;
2006-10-04 19:40:33 +02:00
}
/**
* generate sql to filter based on the start - and enddate of the log - entry
*
2016-04-30 19:05:23 +02:00
* @ param string $_filter upcoming = startdate is in the future
2007-06-10 11:21:04 +02:00
* today : startdate < tomorrow
* overdue : enddate < tomorrow
* date : today <= startdate && startdate < tomorrow
* enddate : today <= enddate && enddate < tomorrow
2008-07-18 09:16:44 +02:00
* limitYYYY / MM / DD not older or open
2006-10-04 19:40:33 +02:00
* @ return string the necesary sql
*/
2016-04-30 19:05:23 +02:00
function dateFilter ( $_filter = '' )
2006-10-04 19:40:33 +02:00
{
2014-01-28 10:22:12 +01:00
$vars = null ;
2016-04-30 19:05:23 +02:00
preg_match ( '/(open-upcoming|upcoming|today|overdue|date|enddate)([-\\/.0-9]*)/' , $_filter , $vars );
2006-10-04 19:40:33 +02:00
$filter = $vars [ 1 ];
2009-06-08 18:21:14 +02:00
if ( isset ( $vars [ 2 ]) && ! empty ( $vars [ 2 ]) && ( $date = preg_split ( '/[-\\/.]/' , $vars [ 2 ])))
2006-10-04 19:40:33 +02:00
{
$today = mktime ( - $this -> tz_offset , 0 , 0 , intval ( $date [ 1 ]), intval ( $date [ 2 ]), intval ( $date [ 0 ]));
$tomorrow = mktime ( - $this -> tz_offset , 0 , 0 , intval ( $date [ 1 ]), intval ( $date [ 2 ]) + 1 , intval ( $date [ 0 ]));
}
else
{
$now = getdate ( time () - 60 * 60 * $this -> tz_offset );
$tomorrow = mktime ( - $this -> tz_offset , 0 , 0 , $now [ 'mon' ], $now [ 'mday' ] + 1 , $now [ 'year' ]);
}
switch ( $filter )
{
2010-07-15 12:09:35 +02:00
case 'open-upcoming' :
return " AND (info_startdate >= $tomorrow OR NOT (info_status IN ('done','billed','cancelled','deleted','template','nonactive','archive'))) " ;
2006-10-04 19:40:33 +02:00
case 'upcoming' :
2008-10-22 12:42:30 +02:00
return " AND info_startdate >= $tomorrow " ;
2006-10-04 19:40:33 +02:00
case 'today' :
2008-10-22 12:42:30 +02:00
return " AND info_startdate < $tomorrow " ;
2006-10-04 19:40:33 +02:00
case 'overdue' :
2008-10-22 12:42:30 +02:00
return " AND (info_enddate != 0 AND info_enddate < $tomorrow ) " ;
2006-10-04 19:40:33 +02:00
case 'date' :
if ( ! $today || ! $tomorrow )
2003-09-07 18:55:36 +02:00
{
2006-10-04 19:40:33 +02:00
return '' ;
2001-07-12 01:17:32 +02:00
}
2006-10-04 19:40:33 +02:00
return " AND ( $today <= info_startdate AND info_startdate < $tomorrow ) " ;
2007-06-10 11:21:04 +02:00
case 'enddate' :
if ( ! $today || ! $tomorrow )
{
return '' ;
}
return " AND ( $today <= info_enddate AND info_enddate < $tomorrow ) " ;
2006-10-04 19:40:33 +02:00
case 'limit' :
2008-10-22 12:42:30 +02:00
return " AND (info_modified >= $today OR NOT (info_status IN ('done','billed','cancelled'))) " ;
2006-10-04 19:40:33 +02:00
}
return '' ;
}
2003-09-07 18:55:36 +02:00
2006-10-04 19:40:33 +02:00
/**
* initialise the internal $this -> data to be empty
*
* only non - empty values got initialised
*/
function init ()
{
$this -> data = array (
'info_owner' => $this -> user ,
'info_priority' => 1 ,
'info_responsible' => array (),
);
}
2005-10-05 09:50:47 +02:00
2006-10-04 19:40:33 +02:00
/**
* read InfoLog entry $info_id
*
* some cacheing is done to prevent multiple reads of the same entry
*
2011-04-11 11:29:39 +02:00
* @ param array $where where clause for entry to read
2009-05-05 14:49:15 +02:00
* @ return array | boolean the entry as array or False on error ( eg . entry not found )
2006-10-04 19:40:33 +02:00
*/
2011-04-11 11:29:39 +02:00
function read ( array $where ) // did _not_ ensure ACL
2006-10-04 19:40:33 +02:00
{
2011-04-11 11:29:39 +02:00
//error_log(__METHOD__.'('.array2string($where).')');
2009-11-28 14:50:03 +01:00
if ( isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'syncml' ][ 'minimum_uid_length' ]))
{
2009-07-15 22:04:17 +02:00
$minimum_uid_length = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'syncml' ][ 'minimum_uid_length' ];
2009-11-28 14:50:03 +01:00
}
else
{
2009-07-15 22:04:17 +02:00
$minimum_uid_length = 8 ;
}
2016-09-11 13:03:54 +02:00
if ( isset ( $where [ 'info_id' ]))
{
$where [] = $this -> db -> expression ( $this -> info_table , $this -> info_table . '.' , array ( 'info_id' => $where [ 'info_id' ]));
unset ( $where [ 'info_id' ]);
}
2009-07-15 22:04:17 +02:00
2016-09-11 13:03:54 +02:00
if ( ! $where ||
2016-09-12 16:25:27 +02:00
! ( $this -> data = $this -> db -> select ( $this -> info_table ,
2017-12-06 14:24:38 +01:00
$this -> info_table . '.*,' . $this -> db -> group_concat ( 'account_id' ) . ' AS info_responsible,' .
2017-10-20 16:31:41 +02:00
$this -> db -> group_concat ( 'info_res_attendee' ) . ' AS info_cc,' .
$this -> info_table . '.info_id AS info_id' ,
2016-09-12 16:25:27 +02:00
$where , __LINE__ , __FILE__ , false , " GROUP BY $this->info_table .info_id " , 'infolog' , 1 ,
2016-09-13 18:02:04 +02:00
" LEFT JOIN $this->users_table ON $this->info_table .info_id= $this->users_table .info_id AND $this->users_table .info_res_deleted IS NULL " ) -> fetch ()))
2006-10-04 19:40:33 +02:00
{
$this -> init ( );
2011-04-11 11:29:39 +02:00
//error_log(__METHOD__.'('.array2string($where).') returning FALSE');
2006-10-04 19:40:33 +02:00
return False ;
}
2009-07-15 22:04:17 +02:00
// entry without uid --> create one based on our info_id and save it
2011-04-11 11:29:39 +02:00
if ( ! $this -> data [ 'info_uid' ] || strlen ( $this -> data [ 'info_uid' ]) < $minimum_uid_length )
{
2016-04-30 19:05:23 +02:00
$this -> data [ 'info_uid' ] = Api\CalDAV :: generate_uid ( 'infolog' , $this -> data [ 'info_id' ]);
2009-07-15 22:04:17 +02:00
$this -> db -> update ( $this -> info_table ,
array ( 'info_uid' => $this -> data [ 'info_uid' ]),
array ( 'info_id' => $this -> data [ 'info_id' ]), __LINE__ , __FILE__ );
}
2006-10-04 19:40:33 +02:00
if ( ! is_array ( $this -> data [ 'info_responsible' ]))
{
$this -> data [ 'info_responsible' ] = $this -> data [ 'info_responsible' ] ? explode ( ',' , $this -> data [ 'info_responsible' ]) : array ();
2017-10-20 16:31:41 +02:00
foreach ( $this -> data [ 'info_responsible' ] as $k => $v )
{
if ( ! is_numeric ( $v )) unset ( $this -> data [ 'info_responsible' ][ $k ]);
}
$this -> data [ 'info_responsible' ] = array_values ( $this -> data [ 'info_responsible' ]);
2003-09-07 18:55:36 +02:00
}
2013-12-10 20:18:05 +01:00
// Cast back to integer
$this -> data [ 'info_id_parent' ] = ( int ) $this -> data [ 'info_id_parent' ];
2011-04-11 11:29:39 +02:00
foreach ( $this -> db -> select ( $this -> extra_table , 'info_extra_name,info_extra_value' , array ( 'info_id' => $this -> data [ 'info_id' ]), __LINE__ , __FILE__ ) as $row )
2006-10-04 19:40:33 +02:00
{
2011-04-11 11:29:39 +02:00
$this -> data [ '#' . $row [ 'info_extra_name' ]] = $row [ 'info_extra_value' ];
2006-10-04 19:40:33 +02:00
}
2011-04-11 11:29:39 +02:00
//error_log(__METHOD__.'('.array2string($where).') returning '.array2string($this->data));
2006-10-04 19:40:33 +02:00
return $this -> data ;
}
2008-07-18 09:16:44 +02:00
2006-10-04 19:40:33 +02:00
/**
* delete InfoLog entry $info_id AND the links to it
*
* @ param int $info_id id of log - entry
2009-05-05 14:49:15 +02:00
* @ param boolean $delete_children delete the children , if not set there parent - id to $new_parent
2006-10-04 19:40:33 +02:00
* @ param int $new_parent new parent - id to set for subs
*/
function delete ( $info_id , $delete_children = True , $new_parent = 0 ) // did _not_ ensure ACL
{
//echo "<p>soinfolog::delete($info_id,'$delete_children',$new_parent)</p>\n";
if (( int ) $info_id <= 0 )
2001-07-15 23:42:17 +02:00
{
2006-10-04 19:40:33 +02:00
return ;
}
$this -> db -> delete ( $this -> info_table , array ( 'info_id' => $info_id ), __LINE__ , __FILE__ );
$this -> db -> delete ( $this -> extra_table , array ( 'info_id' => $info_id ), __LINE__ , __FILE__ );
2016-09-11 13:03:54 +02:00
$this -> db -> delete ( $this -> users_table , array ( 'info_id' => $info_id ), __LINE__ , __FILE__ );
2016-04-30 19:05:23 +02:00
Link :: unlink ( 0 , 'infolog' , $info_id );
2001-07-15 23:42:17 +02:00
2006-10-04 19:40:33 +02:00
if ( $this -> data [ 'info_id' ] == $info_id )
{
2008-07-18 09:16:44 +02:00
$this -> init ( );
2001-07-12 01:17:32 +02:00
}
2006-10-04 19:40:33 +02:00
// delete children, if they are owned by the user
if ( $delete_children )
{
$db2 = clone ( $this -> db ); // we need an extra result-set
2016-04-02 21:55:08 +02:00
foreach ( $db2 -> select ( $this -> info_table , 'info_id' , array (
2006-10-04 19:40:33 +02:00
'info_id_parent' => $info_id ,
'info_owner' => $this -> user ,
2016-04-02 21:55:08 +02:00
), __LINE__ , __FILE__ ) as $row )
2003-06-14 15:51:53 +02:00
{
2016-04-02 21:55:08 +02:00
$this -> delete ( $row [ 'info_id' ], $delete_children );
2003-06-14 15:51:53 +02:00
}
2006-10-04 19:40:33 +02:00
}
// 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__ );
}
2008-07-18 09:16:44 +02:00
2007-06-13 23:37:05 +02:00
/**
* 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 )
{
$children = array ();
2012-06-19 16:44:13 +02:00
foreach ( $this -> db -> select ( $this -> info_table , 'info_id,info_owner' , array (
'info_id_parent' => $info_id ,
), __LINE__ , __FILE__ ) as $row )
2007-06-13 23:37:05 +02:00
{
$children [ $row [ 'info_id' ]] = $row [ 'info_owner' ];
}
return $children ;
}
2002-09-01 22:41:36 +02:00
2006-10-04 19:40:33 +02:00
/**
* changes or deletes entries with a spezified owner ( for hook_delete_account )
*
2008-10-22 08:15:37 +02:00
* @ param array $args hook arguments
* @ param int $args [ 'account_id' ] account to delete
* @ param int $args [ 'new_owner' ] = 0 new owner
2016-09-11 13:03:54 +02:00
* @ todo test deleting an owner with replace and without
2006-10-04 19:40:33 +02:00
*/
2008-10-22 08:15:37 +02:00
function change_delete_owner ( array $args ) // new_owner=0 means delete
2006-10-04 19:40:33 +02:00
{
2008-10-22 08:15:37 +02:00
if ( ! ( int ) $args [ 'new_owner' ])
2006-10-04 19:40:33 +02:00
{
2008-10-22 08:15:37 +02:00
foreach ( $this -> db -> select ( $this -> info_table , 'info_id' , array ( 'info_owner' => $args [ 'account_id' ]), __LINE__ , __FILE__ , false , '' , 'infolog' ) as $row )
2003-08-28 16:31:11 +02:00
{
2008-10-22 08:15:37 +02:00
$this -> delete ( $row [ 'info_id' ], False );
2003-08-28 16:31:11 +02:00
}
2001-07-12 01:17:32 +02:00
}
2006-10-04 19:40:33 +02:00
else
{
2008-10-22 08:15:37 +02:00
$this -> db -> update ( $this -> info_table , array ( 'info_owner' => $args [ 'new_owner' ]), array ( 'info_owner' => $args [ 'account_id' ]), __LINE__ , __FILE__ , 'infolog' );
}
2016-09-11 13:03:54 +02:00
if ( $args [ 'new_owner' ])
2008-10-22 08:15:37 +02:00
{
2016-09-11 13:03:54 +02:00
// we cant just set the new owner, as he might be already set and we have a unique index
2017-11-27 13:41:28 +01:00
$this -> db -> query ( 'UPDATE ' . $this -> users_table .
2016-09-11 13:03:54 +02:00
" LEFT JOIN $this->users_table new_owner ON new_owner.info_id= $this->users_table .info_id " .
2017-12-02 03:23:31 +01:00
" AND new_owner.account_id= " . $this -> db -> quote ( $args [ 'new_owner' ]) .
' SET ' . $this -> users_table . '.account_id=' . $this -> db -> quote ( $args [ 'new_owner' ]) .
' WHERE ' . $this -> users_table . '.account_id=' . $this -> db -> quote ( $args [ 'account_id' ]) .
2017-11-27 13:41:28 +01:00
' AND new_owner.account_id IS NULL' ,
__LINE__ , __FILE__ );
2006-10-04 19:40:33 +02:00
}
2016-09-11 13:03:54 +02:00
$this -> db -> delete ( $this -> users_table , array ( 'account_id' => $args [ 'account_id' ]), __LINE__ , __FILE__ , 'infolog' );
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
*
* @ param array $values with the data of the log - entry
2016-04-30 19:05:23 +02:00
* @ 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
2016-10-04 11:30:02 +02:00
* @ param boolean $force_insert = false force using insert , even if an id is given eg . for import
2009-05-05 14:49:15 +02:00
* @ return int | boolean info_id , false on error or 0 if the entry has been updated in the meantime
2006-10-04 19:40:33 +02:00
*/
2016-10-04 11:30:02 +02:00
function write ( $values , $check_modified = 0 , $purge_cfs = null , $force_insert = false ) // did _not_ ensure ACL
2006-10-04 19:40:33 +02:00
{
2010-03-15 10:55:16 +01:00
if ( isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'syncml' ][ 'minimum_uid_length' ]))
2009-11-28 14:50:03 +01:00
{
2009-07-15 22:04:17 +02:00
$minimum_uid_length = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'syncml' ][ 'minimum_uid_length' ];
2010-03-15 10:55:16 +01:00
}
else
2009-11-28 14:50:03 +01:00
{
2009-07-15 22:04:17 +02:00
$minimum_uid_length = 8 ;
}
2006-10-04 19:40:33 +02:00
//echo "soinfolog::write(,$check_modified) values="; _debug_array($values);
$info_id = ( int ) $values [ 'info_id' ];
2001-07-12 01:17:32 +02:00
2006-10-04 19:40:33 +02:00
$table_def = $this -> db -> get_table_definitions ( 'infolog' , $this -> info_table );
$to_write = array ();
foreach ( $values as $key => $val )
{
2016-11-10 16:44:15 +01:00
if (( $key != 'info_id' || $force_insert && $info_id > 0 ) && isset ( $table_def [ 'fd' ][ $key ]))
2002-11-20 20:58:15 +01:00
{
2006-10-04 19:40:33 +02:00
$to_write [ $key ] = $this -> data [ $key ] = $val ; // update internal data
2002-11-20 20:58:15 +01:00
}
2006-10-04 19:40:33 +02:00
}
2006-12-08 08:10:27 +01:00
// writing no price as SQL NULL (required by postgres)
if ( $to_write [ 'info_price' ] === '' ) $to_write [ 'info_price' ] = NULL ;
2016-10-04 11:30:02 +02:00
if (( $this -> data [ 'info_id' ] = $info_id ) && ! $force_insert )
2006-10-04 19:40:33 +02:00
{
$where = array ( 'info_id' => $info_id );
2021-11-22 17:53:37 +01:00
if ( $check_modified )
{
$where [ 'info_datemodified' ] = $check_modified ;
// also check etag, if we got it
if ( isset ( $values [ 'info_etag' ]))
{
$where [ 'info_etag' ] = $values [ 'info_etag' ];
}
unset ( $to_write [ 'info_etag' ]);
// and increment it
$to_write [] = 'info_etag=info_etag+1' ;
}
2016-10-04 11:30:02 +02:00
if ( ! $this -> db -> update ( $this -> info_table , $to_write , $where , __LINE__ , __FILE__ ))
2002-11-20 20:58:15 +01:00
{
2007-08-27 15:04:05 +02:00
//error_log("### soinfolog::write(".print_r($to_write,true).") where=".print_r($where,true)." returning false");
2006-10-04 19:40:33 +02:00
return false ; // Error
2002-11-20 20:58:15 +01:00
}
2007-08-27 15:04:05 +02:00
if ( $check_modified && $this -> db -> affected_rows () < 1 )
{
//error_log("### soinfolog::write(".print_r($to_write,true).") where=".print_r($where,true)." returning 0 (nothing updated, eg. condition not met)");
return 0 ; // someone else updated the modtime or deleted the entry
}
2002-11-20 20:58:15 +01:00
}
2006-10-04 19:40:33 +02:00
else
2001-07-14 23:44:01 +02:00
{
2006-10-04 19:40:33 +02:00
if ( ! isset ( $to_write [ 'info_id_parent' ])) $to_write [ 'info_id_parent' ] = 0 ; // must not be null
2003-08-28 16:31:11 +02:00
2006-10-04 19:40:33 +02:00
$this -> db -> insert ( $this -> info_table , $to_write , false , __LINE__ , __FILE__ );
$info_id = $this -> data [ 'info_id' ] = $this -> db -> get_last_insert_id ( $this -> info_table , 'info_id' );
}
2009-07-15 22:04:17 +02:00
2011-04-11 11:29:39 +02:00
$update = array ();
// entry without (reasonable) uid --> create one based on our info_id and save it
if ( ! $this -> data [ 'info_uid' ] || strlen ( $this -> data [ 'info_uid' ]) < $minimum_uid_length )
{
2016-04-30 19:05:23 +02:00
$update [ 'info_uid' ] = $this -> data [ 'info_uid' ] = Api\CalDAV :: generate_uid ( 'infolog' , $info_id );
2011-04-11 11:29:39 +02:00
}
// entry without caldav_name --> generate one based on info_id plus '.ics' extension
if ( empty ( $this -> data [ 'caldav_name' ]))
{
$update [ 'caldav_name' ] = $this -> data [ 'caldav_name' ] = $info_id . '.ics' ;
}
if ( $update )
{
$this -> db -> update ( $this -> info_table , $update ,
2009-07-15 22:04:17 +02:00
array ( 'info_id' => $info_id ), __LINE__ , __FILE__ );
}
2006-10-04 19:40:33 +02:00
//echo "<p>soinfolog.write values= "; _debug_array($values);
// write customfields now
2012-01-29 23:34:43 +01:00
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__ );
}
2008-03-31 16:48:49 +02:00
$to_delete = array ();
2017-04-10 18:39:04 +02:00
// Deal with files in new entries
2017-04-17 17:48:25 +02:00
Api\Storage\Customfields :: handle_files ( 'infolog' , $info_id , $values );
2017-04-10 18:39:04 +02:00
2006-10-04 19:40:33 +02:00
foreach ( $values as $key => $val )
{
if ( $key [ 0 ] != '#' )
2001-07-14 23:44:01 +02:00
{
2006-10-04 19:40:33 +02:00
continue ; // no customfield
2001-07-14 23:44:01 +02:00
}
2006-10-04 19:40:33 +02:00
$this -> data [ $key ] = $val ; // update internal data
2005-10-05 09:50:47 +02:00
2008-03-31 16:48:49 +02:00
if ( $val )
{
$this -> db -> insert ( $this -> extra_table , array (
2013-06-12 16:12:58 +02:00
// store multivalued CalDAV properties as serialized array, everything else get comma-separated
2020-09-16 17:01:51 +02:00
'info_extra_value' => is_array ( $val ) ? ( $key [ 1 ] == '#' ? json_encode ( $val ) : implode ( ',' , $val )) : $val ,
2008-03-31 16:48:49 +02:00
), array (
'info_id' => $info_id ,
'info_extra_name' => substr ( $key , 1 ),
), __LINE__ , __FILE__ );
}
else
{
$to_delete [] = substr ( $key , 1 );
}
}
2012-01-29 23:34:43 +01:00
if ( $to_delete && ! $purge_cfs )
2008-03-31 16:48:49 +02:00
{
$this -> db -> delete ( $this -> extra_table , array (
2006-10-04 19:40:33 +02:00
'info_id' => $info_id ,
2008-03-31 16:48:49 +02:00
'info_extra_name' => $to_delete ,
2006-10-04 19:40:33 +02:00
), __LINE__ , __FILE__ );
}
// echo "<p>soinfolog.write this->data= "; _debug_array($this->data);
2007-08-27 15:04:05 +02:00
//error_log("### soinfolog::write(".print_r($to_write,true).") where=".print_r($where,true)." returning id=".$this->data['info_id']);
2003-08-28 16:31:11 +02:00
2016-09-11 13:03:54 +02:00
// update attendees/delegates
2017-10-20 16:31:41 +02:00
if ( array_key_exists ( 'info_responsible' , $values ) || array_key_exists ( 'info_cc' , $values ))
2016-09-11 13:03:54 +02:00
{
2017-10-20 16:31:41 +02:00
$users = empty ( $values [ 'info_responsible' ]) ? array () :
array_combine ( $values [ 'info_responsible' ], array_fill ( 0 , count ( $values [ 'info_responsible' ]), null ));
foreach ( ! empty ( $values [ 'info_cc' ]) ? explode ( ',' , $values [ 'info_cc' ]) : array () as $email )
{
$email = trim ( $email );
$matches = null ;
if ( preg_match ( '/<[^>]+@[^>]+>$/' , $email , $matches ))
{
$hash = md5 ( strtolower ( $matches [ 1 ]));
}
else
{
$hash = md5 ( strtolower ( $email ));
}
$users [ $hash ] = $email ;
}
2016-09-11 13:03:54 +02:00
// mark removed attendees as deleted
$this -> db -> update ( $this -> users_table , array (
'info_res_deleted' => true ,
'info_res_modifier' => $this -> user ,
), array (
'info_id' => $this -> data [ 'info_id' ],
'info_res_deleted IS NULL' ,
) + ( ! $values [ 'info_responsible' ] ? array () :
2017-10-20 16:31:41 +02:00
array ( 1 => 'account_id NOT IN (' . implode ( ',' , array_map ( array ( $this -> db , 'quote' ), array_keys ( $users ))) . ')' )),
2016-09-11 13:03:54 +02:00
__LINE__ , __FILE__ , 'infolog' );
// add newly added attendees
2017-10-20 16:31:41 +02:00
if ( $users )
2016-09-11 13:03:54 +02:00
{
2017-10-20 16:31:41 +02:00
$old_users = array ();
foreach ( $this -> db -> select ( $this -> users_table , 'account_id,info_res_attendee' , array (
2016-09-11 13:03:54 +02:00
'info_id' => $this -> data [ 'info_id' ],
'info_res_deleted IS NULL' ,
), __LINE__ , __FILE__ , false , '' , 'infolog' ) as $row )
{
2017-10-20 16:31:41 +02:00
$old_users [] = $row [ 'account_id' ];
2016-09-11 13:03:54 +02:00
}
2017-10-20 16:31:41 +02:00
foreach ( array_diff ( array_keys ( $users ), $old_users ) as $account_id )
2016-09-11 13:03:54 +02:00
{
$this -> db -> insert ( $this -> users_table , array (
'info_res_modifier' => $this -> user ,
'info_res_status' => 'NEEDS-ACTION' ,
2017-10-20 16:31:41 +02:00
'info_res_attendee' => $users [ $account_id ],
2016-09-11 13:03:54 +02:00
'info_res_deleted' => null ,
), array (
'info_id' => $this -> data [ 'info_id' ],
'account_id' => $account_id ,
), __LINE__ , __FILE__ , 'infolog' );
}
}
}
2006-10-04 19:40:33 +02:00
return $this -> data [ 'info_id' ];
}
2003-06-14 15:51:53 +02:00
2006-10-04 19:40:33 +02:00
/**
* count the sub - entries of $info_id
*
* This is done now be search too ( in key info_anz_subs ), if DB can use sub - queries
*
2008-10-19 13:34:12 +02:00
* @ param int | array $info_id id ( s ) of log - entry
* @ return int | array the number of sub - entries or indexed by info_id , if array as param given
2006-10-04 19:40:33 +02:00
*/
function anzSubs ( $info_id )
{
2008-10-19 13:34:12 +02:00
if ( ! is_array ( $info_id ) || ! $info_id )
2006-10-04 19:40:33 +02:00
{
2008-10-19 13:34:12 +02:00
if (( int ) $info_id <= 0 ) return 0 ;
2001-07-12 01:17:32 +02:00
}
2008-10-19 13:34:12 +02:00
$counts = array ();
2011-05-05 09:56:58 +02:00
foreach ( $this -> db -> select ( $this -> info_table , 'info_id_parent,COUNT(*) AS info_anz_subs' , array (
'info_id_parent' => $info_id ,
" info_status != 'deleted' " , // dont count deleted subs as subs, as they are not shown by default
), __LINE__ , __FILE__ ,
2008-10-19 13:34:12 +02:00
false , 'GROUP BY info_id_parent' , 'infolog' ) as $row )
{
$counts [ $row [ 'info_id_parent' ]] = ( int ) $row [ 'info_anz_subs' ];
}
//echo '<p>'.__METHOD__."($info_id) = ".array2string($counts)."</p>\n";
return is_array ( $info_id ) ? $counts : ( int ) array_pop ( $counts );
2006-10-04 19:40:33 +02:00
}
2008-07-18 09:16:44 +02:00
2006-10-04 19:40:33 +02:00
/**
* searches InfoLog for a certain pattern in $query
*
2009-05-05 14:49:15 +02:00
* @ param string $query [ order ] column - name to sort after
* @ param string $query [ sort ] sort - order DESC or ASC
* @ param string $query [ filter ] string with combination of acl - , date - and status - filters , eg . 'own-open-today' or ''
* @ param int $query [ cat_id ] category to use or 0 or unset
* @ param string $query [ search ] pattern to search , search is done in info_from , info_subject and info_des
* @ param string $query [ action ] / $query [ action_id ] if only entries linked to a specified app / entry show be used
* @ param int & $query [ start ], & $query [ total ] nextmatch - parameters will be used and set if query returns less entries
* @ param array $query [ col_filter ] array with column - name - data pairs , data == '' means no filter ( ! )
* @ param boolean $query [ subs ] return subs or not , if unset the user preference is used
* @ param int $query [ num_rows ] number of rows to return if $query [ start ] is set , default is to use the value from the general prefs
* @ param string | array $query [ cols ] = null what to query , if set the recordset / iterator get ' s returned
* @ param string $query [ append ] = null get ' s appended to sql query , eg . for GROUP BY
2014-01-28 10:36:36 +01:00
* @ param boolean $query [ 'custom_fields' ] = false query custom - fields too , default not
2016-09-26 11:40:02 +02:00
* @ param boolean $no_acl = false true : ignore all acl
2009-05-05 14:49:15 +02:00
* @ return array | iterator with id ' s as key of the matching log - entries or recordset / iterator if cols is set
2006-10-04 19:40:33 +02:00
*/
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).')');
2006-10-04 19:40:33 +02:00
$action2app = array (
'addr' => 'addressbook' ,
'proj' => 'projects' ,
'event' => 'calendar'
);
2013-10-10 13:29:31 +02:00
// query children independent of action
2021-10-21 10:39:30 +02:00
if ( empty ( $query [ 'col_filter' ][ 'info_id_parent' ]))
2001-07-14 23:44:01 +02:00
{
2021-10-21 10:39:30 +02:00
$action = isset ( $action2app [ $query [ 'action' ]]) ? $action2app [ $query [ 'action' ]] : ( $query [ 'action' ] ? ? null );
2013-10-10 13:29:31 +02:00
if ( $action )
2002-10-16 02:23:39 +02:00
{
2016-04-30 19:05:23 +02:00
$links = Link\Storage :: get_links ( $action == 'sp' ? 'infolog' : $action ,
2014-04-28 22:25:40 +02:00
is_array ( $query [ 'action_id' ]) ? $query [ 'action_id' ] : explode ( ',' , $query [ 'action_id' ]), 'infolog' , '' , $query [ 'col_filter' ][ 'info_status' ] == 'deleted' );
2013-10-10 13:29:31 +02:00
if ( count ( $links ))
{
$links = call_user_func_array ( 'array_merge' , $links ); // flatten the array
$link_extra = ( $action == 'sp' ? 'OR' : 'AND' ) . " main.info_id IN ( " . implode ( ',' , $links ) . ')' ;
}
2002-09-01 22:41:36 +02:00
}
2006-10-04 19:40:33 +02:00
}
2007-12-14 14:11:29 +01:00
$sortbycf = '' ;
2008-07-18 09:16:44 +02:00
if ( ! empty ( $query [ 'order' ]) && ( preg_match ( '/^[a-z_0-9, ]+$/i' , $query [ 'order' ]) || stripos ( $query [ 'order' ], '#' ) !== FALSE ) &&
2021-11-13 17:45:25 +01:00
( empty ( $query [ 'sort' ]) || is_string ( $query [ 'sort' ]) && preg_match ( '/^(DESC|ASC)$/i' , $query [ 'sort' ])))
2006-10-04 19:40:33 +02:00
{
$order = array ();
foreach ( explode ( ',' , $query [ 'order' ]) as $val )
2001-07-14 23:44:01 +02:00
{
2006-10-04 19:40:33 +02:00
$val = trim ( $val );
2008-07-18 09:16:44 +02:00
if ( $val [ 0 ] == '#' )
2008-01-19 06:36:20 +01:00
{
$sortbycf = substr ( $val , 1 );
2015-03-23 09:38:30 +01:00
$val = " cfsortcrit IS NULL,cfsortcrit " ;
2008-01-19 06:36:20 +01:00
}
2008-07-18 09:16:44 +02:00
else
2008-01-19 06:36:20 +01:00
{
2014-01-28 10:22:12 +01:00
static $table_def = null ;
2009-05-05 14:49:15 +02:00
if ( is_null ( $table_def )) $table_def = $this -> db -> get_table_definitions ( 'infolog' , $this -> info_table );
if ( substr ( $val , 0 , 5 ) != 'info_' && isset ( $table_def [ 'fd' ][ 'info_' . $val ])) $val = 'info_' . $val ;
2007-12-14 14:11:29 +01:00
if ( $val == 'info_des' && $this -> db -> capabilities [ 'order_on_text' ] !== true )
{
if ( ! $this -> db -> capabilities [ 'order_on_text' ]) continue ;
2005-11-12 14:25:59 +01:00
2007-12-14 14:11:29 +01:00
$val = sprintf ( $this -> db -> capabilities [ 'order_on_text' ], $val );
}
2004-03-13 18:58:37 +01:00
}
2006-10-04 19:40:33 +02:00
$order [] = $val ;
2001-07-14 23:44:01 +02:00
}
2006-10-04 19:40:33 +02:00
$ordermethod = 'ORDER BY ' . implode ( ',' , $order ) . ' ' . $query [ 'sort' ];
}
else
{
$ordermethod = 'ORDER BY info_datemodified DESC' ; // newest first
}
2016-09-26 11:40:02 +02:00
$filtermethod = $no_acl ? '1=1' : $this -> aclFilter ( $query [ 'filter' ]);
2021-10-21 10:39:30 +02:00
if ( empty ( $query [ 'col_filter' ][ 'info_status' ])) $filtermethod .= $this -> statusFilter ( $query [ 'filter' ]);
2006-10-04 19:40:33 +02:00
$filtermethod .= $this -> dateFilter ( $query [ 'filter' ]);
2007-12-14 14:11:29 +01:00
$cfcolfilter = 0 ;
2021-10-21 10:39:30 +02:00
if ( isset ( $query [ 'col_filter' ]) && is_array ( $query [ 'col_filter' ]))
2006-10-04 19:40:33 +02:00
{
foreach ( $query [ 'col_filter' ] as $col => $data )
2003-12-09 01:08:31 +01:00
{
2009-05-05 14:49:15 +02:00
if ( is_int ( $col ))
{
$filtermethod .= ' AND ' . $data ;
continue ;
}
2011-04-11 11:29:39 +02:00
if ( $col [ 0 ] != '#' && substr ( $col , 0 , 5 ) != 'info_' && isset ( $table_def [ 'fd' ][ 'info_' . $col ])) $col = 'info_' . $col ;
2014-08-27 09:53:40 +02:00
if (( string ) $data !== '' && preg_match ( '/^[a-z_0-9]+$/i' , $col ))
2003-12-09 01:08:31 +01:00
{
2009-10-23 11:57:47 +02:00
switch ( $col )
2003-12-09 01:08:31 +01:00
{
2009-10-23 11:57:47 +02:00
case 'info_responsible' :
$data = ( int ) $data ;
2018-12-11 12:45:17 +01:00
if ( ! $data ) continue 2 ; // +1 for switch
2016-09-11 13:03:54 +02:00
$filtermethod .= ' AND (' . $this -> responsible_filter ( $data ) . " OR $this->users_table .account_id IS NULL AND " .
2009-10-23 11:57:47 +02:00
$this -> db -> expression ( $this -> info_table , array (
'info_owner' => $data > 0 ? $data : $GLOBALS [ 'egw' ] -> accounts -> members ( $data , true )
)) . ')' ;
break ;
case 'info_id' : // info_id itself is ambigous
$filtermethod .= ' AND ' . $this -> db -> expression ( $this -> info_table , 'main.' , array ( 'info_id' => $data ));
break ;
default :
$filtermethod .= ' AND ' . $this -> db -> expression ( $this -> info_table , array ( $col => $data ));
break ;
2008-07-18 09:16:44 +02:00
}
2003-12-09 01:08:31 +01:00
}
2008-07-18 09:16:44 +02:00
if ( $col [ 0 ] == '#' && $query [ 'custom_fields' ] && $data )
2008-01-19 06:36:20 +01:00
{
2010-04-07 17:52:59 +02:00
$filtermethod .= " AND main.info_id IN (SELECT DISTINCT info_id FROM $this->extra_table WHERE " ;
2016-04-30 19:05:23 +02:00
$custom_fields = Api\Storage\Customfields :: get ( 'infolog' );
2010-04-07 17:52:59 +02:00
if ( $custom_fields [ substr ( $col , 1 )][ 'type' ] == 'select' && $custom_fields [ substr ( $col , 1 )][ 'rows' ] > 1 )
{
// Multi-select - any entry with the filter value selected matches
$filtermethod .= $this -> db -> expression ( $this -> extra_table , array (
'info_extra_name' => substr ( $col , 1 ),
2016-04-30 19:05:23 +02:00
$this -> db -> concat ( " ',' " , 'info_extra_value' , " ',' " ) . ' ' . $this -> db -> capabilities [ Api\Db :: CAPABILITY_CASE_INSENSITIV_LIKE ] . ' ' . $this -> db -> quote ( '%,' . $data . ',%' ),
2010-04-07 17:52:59 +02:00
)) . ')' ;
}
else
{
$filtermethod .= $this -> db -> expression ( $this -> extra_table , array (
2008-01-19 06:36:20 +01:00
'info_extra_name' => substr ( $col , 1 ),
'info_extra_value' => $data ,
)) . ')' ;
2010-04-07 17:52:59 +02:00
}
2007-12-14 14:11:29 +01:00
$cfcolfilter ++ ;
}
2003-12-09 01:08:31 +01:00
}
2006-10-04 19:40:33 +02:00
}
//echo "<p>filtermethod='$filtermethod'</p>";
2001-07-14 23:44:01 +02:00
2021-10-21 10:39:30 +02:00
if ( ! empty ( $query [ 'cat_id' ]) && ( int ) $query [ 'cat_id' ])
2006-10-04 19:40:33 +02:00
{
2016-04-30 19:05:23 +02:00
$categories = new Api\Categories ( '' , 'infolog' );
2015-09-02 16:56:06 +02:00
$cats = $categories -> return_all_children (( int ) $query [ 'cat_id' ]);
2006-10-04 19:40:33 +02:00
$filtermethod .= ' AND info_cat' . ( count ( $cats ) > 1 ? ' IN (' . implode ( ',' , $cats ) . ') ' : '=' . ( int ) $query [ 'cat_id' ]);
}
2008-10-19 13:34:12 +02:00
$join = $distinct = '' ;
2021-10-21 10:39:30 +02:00
if ( ! empty ( $query [ 'query' ])) $query [ 'search' ] = $query [ 'query' ]; // allow both names
if ( ! empty ( $query [ 'search' ])) // we search in _from, _subject, _des and _extra_value for $query
2006-10-04 19:40:33 +02:00
{
2019-02-18 19:03:29 +01:00
$columns = array ( 'info_from' , 'info_location' , 'info_subject' );
2006-10-04 19:40:33 +02:00
// at the moment MaxDB 7.5 cant cast nor search text columns, it's suppost to change in 7.6
if ( $this -> db -> capabilities [ 'like_on_text' ]) $columns [] = 'info_des' ;
2005-11-12 14:25:59 +01:00
2019-02-18 19:03:29 +01:00
$wildcard = '%' ; $op = null ;
$so_sql = new Api\Storage ( 'infolog' , $this -> info_table , $this -> extra_table , '' , 'info_extra_name' , 'info_extra_value' , 'info_id' , $this -> db );
2017-03-07 20:24:42 +01:00
$so_sql -> table_name = 'main' ;
2015-05-19 16:57:35 +02:00
$search = $so_sql -> search2criteria ( $query [ 'search' ], $wildcard , $op , null , $columns );
2006-10-04 19:40:33 +02:00
$sql_query = 'AND (' . ( is_numeric ( $query [ 'search' ]) ? 'main.info_id=' . ( int ) $query [ 'search' ] . ' OR ' : '' ) .
2010-03-31 23:37:35 +02:00
implode ( $op , $search ) . ')' ;
2006-10-04 19:40:33 +02:00
}
2016-09-11 13:03:54 +02:00
$join .= " LEFT JOIN $this->users_table ON main.info_id= $this->users_table .info_id " ;
2016-09-13 18:02:04 +02:00
if ( strpos ( $query [ 'filter' ], '+deleted' ) === false )
{
$join .= " AND $this->users_table .info_res_deleted IS NULL " ;
}
2016-09-12 14:38:23 +02:00
// do not return deleted attendees
$join .= " LEFT JOIN $this->users_table attendees ON main.info_id=attendees.info_id AND attendees.info_res_deleted IS NULL " ;
$group_by = ' GROUP BY main.info_id ' ;
2016-10-07 14:32:26 +02:00
// check if $query['append'] already contains a GROUP BY clause
2021-10-21 10:39:30 +02:00
if ( ! empty ( $query [ 'append' ]) && stripos ( $query [ 'append' ], 'group by' ) !== false )
2016-10-07 14:32:26 +02:00
{
$query [ 'append' ] .= ',main.info_id ' ;
}
else
{
$query [ 'append' ] = $group_by ;
}
2011-05-03 02:14:44 +02:00
$pid = 'AND ' . $this -> db -> expression ( $this -> info_table , array ( 'info_id_parent' => ( $action == 'sp' ? $query [ 'action_id' ] : 0 )));
2001-07-14 23:44:01 +02:00
2014-08-27 16:38:03 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'infolog' ][ 'listNoSubs' ] != '1' && $action != 'sp' ||
( string ) $query [ 'col_filter' ][ 'info_id_parent' ] !== '' ||
isset ( $query [ 'subs' ]) && $query [ 'subs' ] || $action != 'sp' && ! empty ( $query [ 'search' ]))
2006-10-04 19:40:33 +02:00
{
$pid = '' ;
}
$ids = array ( );
if ( $action == '' || $action == 'sp' || count ( $links ))
{
2021-10-21 10:39:30 +02:00
$sql_query = " FROM $this->info_table main $join WHERE ( $filtermethod $pid " . ( $sql_query ? ? '' ) . ') ' . ( $link_extra ? ? '' );
2009-07-15 22:04:17 +02:00
#error_log("infolog.so.search:\n" . print_r($sql_query, true));
2008-07-18 09:16:44 +02:00
2021-03-31 13:31:42 +02:00
if ( $this -> db -> Type == 'mysql' && ( float ) $this -> db -> ServerInfo [ 'version' ] >= 4.0 )
2008-03-06 23:41:36 +01:00
{
$mysql_calc_rows = 'SQL_CALC_FOUND_ROWS ' ;
unset ( $query [ 'total' ]);
}
else
2001-07-14 23:44:01 +02:00
{
2016-09-11 13:03:54 +02:00
$query [ 'total' ] = $this -> db -> query ( $sql = " SELECT $distinct main.info_id " . $sql_query . $group_by , __LINE__ , __FILE__ ) -> NumRows ();
2001-07-14 23:44:01 +02:00
}
2008-01-19 06:36:20 +01:00
$info_customfield = '' ;
2008-07-18 09:16:44 +02:00
if ( $sortbycf != '' )
2008-01-19 06:36:20 +01:00
{
2015-03-23 09:38:30 +01:00
$sort_col = " (SELECT DISTINCT info_extra_value FROM $this->extra_table sub2 WHERE sub2.info_id=main.info_id AND info_extra_name= " . $this -> db -> quote ( $sortbycf ) . " ) " ;
2016-04-30 19:05:23 +02:00
if ( ! isset ( $custom_fields )) $custom_fields = Api\Storage\Customfields :: get ( 'infolog' );
2015-03-23 09:38:30 +01:00
switch ( $custom_fields [ $sortbycf ][ 'type' ])
{
case 'int' :
$sort_col = $this -> db -> to_int ( $sort_col );
break ;
case 'float' :
$sort_col = $this -> db -> to_double ( $sort_col );
break ;
}
$info_customfield = " , $sort_col AS cfsortcrit " ;
2007-12-14 14:11:29 +01:00
}
2008-10-19 13:34:12 +02:00
//echo "SELECT $distinct main.* $info_customfield $sql_query $ordermethod"."<br>";
2008-03-06 23:41:36 +01:00
do
{
if ( isset ( $query [ 'start' ]) && isset ( $query [ 'total' ]) && $query [ 'start' ] > $query [ 'total' ])
{
$query [ 'start' ] = 0 ;
}
2009-05-05 14:49:15 +02:00
$cols = isset ( $query [ 'cols' ]) ? $query [ 'cols' ] : 'main.*' ;
if ( is_array ( $cols )) $cols = implode ( ',' , $cols );
2016-09-11 13:03:54 +02:00
$cols .= ',' . $this -> db -> group_concat ( 'attendees.account_id' ) . ' AS info_responsible' ;
2017-10-20 16:31:41 +02:00
$cols .= ',' . $this -> db -> group_concat ( 'attendees.info_res_attendee' ) . ' AS info_cc' ;
2016-09-11 13:03:54 +02:00
$rs = $this -> db -> query ( $sql = 'SELECT ' . $mysql_calc_rows . ' ' . $distinct . ' ' . $cols . ' ' . $info_customfield . ' ' . $sql_query .
2016-10-07 14:32:26 +02:00
$query [ 'append' ] . $ordermethod , __LINE__ , __FILE__ ,
2021-10-21 10:39:30 +02:00
( int )( $query [ 'start' ] ? ? 0 ), isset ( $query [ 'start' ]) ? ( int ) $query [ 'num_rows' ] : - 1 , false , Api\Db :: FETCH_ASSOC );
2008-03-06 23:41:36 +01:00
//echo "<p>db::query('$sql',,,".(int)$query['start'].','.(isset($query['start']) ? (int) $query['num_rows'] : -1).")</p>\n";
if ( $mysql_calc_rows )
{
$query [ 'total' ] = $this -> db -> Link_ID -> GetOne ( 'SELECT FOUND_ROWS()' );
}
}
// check if start is behind total --> loop to set start=0
while ( isset ( $query [ 'start' ]) && $query [ 'start' ] > $query [ 'total' ]);
2008-07-18 09:16:44 +02:00
2009-05-05 14:49:15 +02:00
if ( isset ( $query [ 'cols' ]))
{
return $rs ;
}
2008-03-06 23:41:36 +01:00
foreach ( $rs as $info )
2008-07-18 09:16:44 +02:00
{
2016-09-11 13:03:54 +02:00
$info [ 'info_responsible' ] = $info [ 'info_responsible' ] ? array_unique ( explode ( ',' , $info [ 'info_responsible' ])) : array ();
2017-10-20 16:31:41 +02:00
foreach ( $info [ 'info_responsible' ] as $k => $v )
{
if ( ! is_numeric ( $v )) unset ( $info [ 'info_responsible' ][ $k ]);
}
$info [ 'info_responsible' ] = array_values ( $info [ 'info_responsible' ]);
2006-10-04 19:40:33 +02:00
$ids [ $info [ 'info_id' ]] = $info ;
2001-07-14 23:44:01 +02:00
}
2014-01-28 10:22:12 +01:00
static $index_load_cfs = null ;
2021-10-21 10:39:30 +02:00
if ( is_null ( $index_load_cfs ) && ! empty ( $query [ 'col_filter' ][ 'info_type' ]))
2011-11-17 10:30:30 +01:00
{
2016-04-30 19:05:23 +02:00
$config_data = Api\Config :: read ( 'infolog' );
2013-05-29 15:54:46 +02:00
$index_load_cfs = $config_data [ 'index_load_cfs' ];
if ( ! is_array ( $index_load_cfs )) $index_load_cfs = explode ( ',' , $index_load_cfs );
2011-11-17 10:30:30 +01:00
}
2009-06-30 19:48:04 +02:00
// if no specific custom field is selected, show/query all custom fields
2011-11-17 10:30:30 +01:00
if ( $ids && ( $query [ 'custom_fields' ] || $query [ 'csv_export' ] ||
$index_load_cfs && $query [ 'col_filter' ][ 'info_type' ] && in_array ( $query [ 'col_filter' ][ 'info_type' ], $index_load_cfs )))
2006-10-21 15:07:32 +02:00
{
2008-03-25 12:14:29 +01:00
$where = array ( 'info_id' => array_keys ( $ids ));
2014-05-07 20:36:13 +02:00
if ( ! ( $query [ 'csv_export' ] || strchr ( is_array ( $query [ 'selectcols' ]) ? implode ( ',' , $query [ 'selectcols' ]) : $query [ 'selectcols' ], '#' ) === false ||
2011-11-17 10:30:30 +01:00
$index_load_cfs && $query [ 'col_filter' ][ 'info_type' ] && in_array ( $query [ 'col_filter' ][ 'info_type' ], $index_load_cfs )))
2006-10-21 15:07:32 +02:00
{
2008-03-25 12:14:29 +01:00
$where [ 'info_extra_name' ] = array ();
2014-03-24 18:00:54 +01:00
foreach ( is_array ( $query [ 'selectcols' ]) ? $query [ 'selectcols' ] : explode ( ',' , $query [ 'selectcols' ]) as $col )
2008-03-25 12:14:29 +01:00
{
if ( $col [ 0 ] == '#' ) $where [ 'info_extra_name' ][] = substr ( $col , 1 );
}
2008-03-06 23:41:36 +01:00
}
2008-03-25 12:14:29 +01:00
foreach ( $this -> db -> select ( $this -> extra_table , '*' , $where , __LINE__ , __FILE__ ) as $row )
2008-03-06 23:41:36 +01:00
{
$ids [ $row [ 'info_id' ]][ '#' . $row [ 'info_extra_name' ]] = $row [ 'info_extra_value' ];
2006-10-21 15:07:32 +02:00
}
}
2001-07-14 23:44:01 +02:00
}
2006-10-04 19:40:33 +02:00
else
{
$query [ 'start' ] = $query [ 'total' ] = 0 ;
}
return $ids ;
2001-07-12 01:17:32 +02:00
}
2008-07-18 09:16:44 +02:00
2007-06-10 11:21:04 +02:00
/**
* Query infolog for users with open entries , either own or responsible , with start or end within 4 days
2008-07-18 09:16:44 +02:00
*
2007-06-10 11:21:04 +02:00
* This functions tries to minimize the users really checked with the complete filters , as creating a
* user enviroment and running the specific check costs ...
*
* @ return array with acount_id ' s groups get resolved to there memebers
*/
function users_with_open_entries ()
{
$users = array ();
2008-07-18 09:16:44 +02:00
2016-04-02 21:55:08 +02:00
foreach ( $this -> db -> select ( $this -> info_table , 'DISTINCT info_owner' , array (
2007-06-10 11:21:04 +02:00
str_replace ( ' AND ' , '' , $this -> statusFilter ( 'open' )),
'(ABS(info_startdate-' . time () . ')<' . ( 4 * 24 * 60 * 60 ) . ' OR ' . // start_day within 4 days
'ABS(info_enddate-' . time () . ')<' . ( 4 * 24 * 60 * 60 ) . ')' , // end_day within 4 days
2016-04-02 21:55:08 +02:00
), __LINE__ , __FILE__ ) as $row )
2007-06-10 11:21:04 +02:00
{
2016-11-23 19:27:43 +01:00
$users [] = $row [ 'info_owner' ];
2007-06-10 11:21:04 +02:00
}
2016-09-12 22:57:00 +02:00
foreach ( $this -> db -> select ( $this -> info_table , " DISTINCT $this->users_table .account_id AS account_id " ,
$this -> statusFilter ( 'open' , false ), __LINE__ , __FILE__ , false , '' , 'infolog' , 0 ,
" JOIN $this->users_table ON $this->info_table .info_id= $this->users_table .info_id AND info_res_deleted IS NULL " ) as $row )
2007-06-10 11:21:04 +02:00
{
2016-09-12 22:57:00 +02:00
$responsible = $row [ 'account_id' ];
if ( $GLOBALS [ 'egw' ] -> accounts -> get_type ( $responsible ) == 'g' )
2007-06-10 11:21:04 +02:00
{
2016-09-12 22:57:00 +02:00
$responsible = $GLOBALS [ 'egw' ] -> accounts -> members ( $responsible , true );
}
if ( $responsible )
{
foreach (( array ) $responsible as $user )
2007-06-10 11:21:04 +02:00
{
2016-09-12 22:57:00 +02:00
if ( $user && ! in_array ( $user , $users )) $users [] = $user ;
2007-06-10 11:21:04 +02:00
}
}
}
return $users ;
}
2006-10-04 19:40:33 +02:00
}