2004-08-01 17:36:04 +02:00
< ? php
2007-03-09 12:39:47 +01:00
/**
2011-04-06 21:26:10 +02:00
* EGroupware - Calendar ' s buisness - object - access only
2007-03-09 12:39:47 +01:00
*
* @ link http :// www . egroupware . org
* @ package calendar
* @ author Ralf Becker < RalfBecker - AT - outdoor - training . de >
2009-07-15 22:35:56 +02:00
* @ author Joerg Lehrke < jlehrke @ noc . de >
2016-05-01 19:47:59 +02:00
* @ copyright ( c ) 2004 - 16 by RalfBecker - At - outdoor - training . de
2007-03-09 12:39:47 +01:00
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
2008-05-08 17:02:35 +02:00
* @ version $Id $
2007-03-09 12:39:47 +01:00
*/
2004-08-01 17:36:04 +02:00
2016-05-01 19:47:59 +02:00
use EGroupware\Api ;
use EGroupware\Api\Acl ;
2020-03-11 16:25:24 +01:00
use EGroupware\Api\Link ;
2016-05-01 19:47:59 +02:00
2005-11-09 00:15:14 +01:00
if ( ! defined ( 'ACL_TYPE_IDENTIFER' )) // used to mark ACL-values for the debug_message methode
{
define ( 'ACL_TYPE_IDENTIFER' , '***ACL***' );
}
2010-02-19 18:10:15 +01:00
define ( 'HOUR_s' , 60 * 60 );
define ( 'DAY_s' , 24 * HOUR_s );
define ( 'WEEK_s' , 7 * DAY_s );
2008-06-12 09:03:06 +02:00
/**
* Required ( ! ) include , as we use the MCAL_ * constants , BEFORE instanciating ( and therefore autoloading ) the class
*/
require_once ( EGW_INCLUDE_ROOT . '/calendar/inc/class.calendar_so.inc.php' );
2004-08-01 17:36:04 +02:00
/**
2005-11-09 00:15:14 +01:00
* Class to access all calendar data
2004-08-01 17:36:04 +02:00
*
2005-11-09 00:15:14 +01:00
* For updating calendar data look at the bocalupdate class , which extends this class .
2004-08-01 17:36:04 +02:00
*
* The new UI , BO and SO classes have a strikt definition , in which time - zone they operate :
* UI only operates in user - time , so there have to be no conversation at all !!!
* BO ' s functions take and return user - time only ( ! ), they convert internaly everything to servertime , because
2005-11-09 00:15:14 +01:00
* SO operates only in server - time
2004-08-01 17:36:04 +02:00
*
* As this BO class deals with dates / times of several types and timezone , each variable should have a postfix
* appended , telling with type it is : _s = seconds , _su = secs in user - time , _ss = secs in server - time , _h = hours
*
* All new BO code ( should be true for eGW in general ) NEVER use any $_REQUEST ( $_POST or $_GET ) vars itself .
2005-11-09 00:15:14 +01:00
* Nor does it store the state of any UI - elements ( eg . cat - id selectbox ) . All this is the task of the UI class ( es ) !!!
2004-08-01 17:36:04 +02:00
*
2005-11-09 00:15:14 +01:00
* All permanent debug messages of the calendar - code should done via the debug - message method of this class ! ! !
2004-08-01 17:36:04 +02:00
*/
2008-06-07 19:45:33 +02:00
class calendar_bo
2004-08-01 17:36:04 +02:00
{
2016-05-01 19:47:59 +02:00
/**
* Gives read access to the calendar , but all events the user is not participating are private !
* Used by addressbook .
*/
const ACL_READ_FOR_PARTICIPANTS = Acl :: CUSTOM1 ;
/**
* Right to see free / busy data only
*/
const ACL_FREEBUSY = Acl :: CUSTOM2 ;
/**
* Allows to invite an other user ( if configured to be used ! )
*/
const ACL_INVITE = Acl :: CUSTOM3 ;
2004-08-01 17:36:04 +02:00
/**
* @ var int $debug name of method to debug or level of debug - messages :
* False = Off as higher as more messages you get ; - )
* 1 = function - calls incl . parameters to general functions like search , read , write , delete
* 2 = function - calls to exported helper - functions like check_perms
* 4 = function - calls to exported conversation - functions like date2ts , date2array , ...
* 5 = function - calls to private functions
*/
2004-11-07 15:38:00 +01:00
var $debug = false ;
2004-08-01 17:36:04 +02:00
2010-06-07 19:54:29 +02:00
/**
* @ var int $now timestamp in server - time
*/
var $now ;
2010-11-04 14:30:11 +01:00
2004-08-01 17:36:04 +02:00
/**
* @ var int $now_su timestamp of actual user - time
*/
var $now_su ;
/**
* @ var array $cal_prefs calendar - specific prefs
*/
var $cal_prefs ;
/**
* @ var array $common_prefs common preferences
*/
var $common_prefs ;
2013-05-10 12:54:36 +02:00
/**
* Custom fields read from the calendar config
*
* @ var array
*/
var $customfields = array ();
2004-08-01 17:36:04 +02:00
/**
2023-04-05 16:08:36 +02:00
* @ var int $user numerical id of the current user - id
2004-08-01 17:36:04 +02:00
*/
var $user = 0 ;
/**
* @ var array $grants grants of the current user , array with user - id / ored - ACL - rights pairs
*/
var $grants = array ();
/**
* @ var array $verbose_status translated 1 - char status values to a verbose name , run through lang () by the constructor
*/
var $verbose_status = array (
2009-07-08 12:22:11 +02:00
'A' => 'Accepted' ,
'R' => 'Rejected' ,
'T' => 'Tentative' ,
'U' => 'No Response' ,
2010-02-17 14:29:28 +01:00
'D' => 'Delegated' ,
2009-07-08 12:22:11 +02:00
'G' => 'Group invitation' ,
2004-08-01 17:36:04 +02:00
);
2005-11-09 00:15:14 +01:00
/**
* @ var array recur_types translates MCAL recur - types to verbose labels
*/
var $recur_types = Array (
2009-11-25 21:16:41 +01:00
MCAL_RECUR_NONE => 'No recurrence' ,
2009-07-08 12:22:11 +02:00
MCAL_RECUR_DAILY => 'Daily' ,
MCAL_RECUR_WEEKLY => 'Weekly' ,
MCAL_RECUR_MONTHLY_WDAY => 'Monthly (by day)' ,
MCAL_RECUR_MONTHLY_MDAY => 'Monthly (by date)' ,
MCAL_RECUR_YEARLY => 'Yearly'
2005-11-09 00:15:14 +01:00
);
/**
* @ var array recur_days translates MCAL recur - days to verbose labels
*/
var $recur_days = array (
2009-07-08 12:22:11 +02:00
MCAL_M_MONDAY => 'Monday' ,
MCAL_M_TUESDAY => 'Tuesday' ,
MCAL_M_WEDNESDAY => 'Wednesday' ,
MCAL_M_THURSDAY => 'Thursday' ,
MCAL_M_FRIDAY => 'Friday' ,
MCAL_M_SATURDAY => 'Saturday' ,
MCAL_M_SUNDAY => 'Sunday' ,
2005-11-09 00:15:14 +01:00
);
2009-10-12 21:16:42 +02:00
/**
* Standard iCal attendee roles
*
* @ var array
*/
var $roles = array (
'REQ-PARTICIPANT' => 'Requested' ,
'CHAIR' => 'Chair' ,
'OPT-PARTICIPANT' => 'Optional' ,
'NON-PARTICIPANT' => 'None' ,
);
2014-05-28 12:03:57 +02:00
/**
* Alarm times
*
* @ var array
*/
var $alarms = array (
300 => '5 Minutes' ,
600 => '10 Minutes' ,
900 => '15 Minutes' ,
1800 => '30 Minutes' ,
3600 => '1 Hour' ,
7200 => '2 Hours' ,
43200 => '12 Hours' ,
86400 => '1 Day' ,
172800 => '2 Days' ,
604800 => '1 Week' ,
);
2005-11-09 00:15:14 +01:00
/**
2010-12-17 04:40:55 +01:00
* @ var array $resources registered scheduling resources of the calendar ( gets cached in the session for performance reasons )
2005-11-09 00:15:14 +01:00
*/
var $resources ;
/**
* @ var array $cached_event here we do some caching to read single events only once
*/
2008-05-10 22:10:45 +02:00
protected static $cached_event = array ();
protected static $cached_event_date_format = false ;
2009-07-15 22:35:56 +02:00
protected static $cached_event_date = 0 ;
2017-08-31 14:03:18 +02:00
2006-12-22 20:51:56 +01:00
/**
* Instance of the socal class
*
2009-03-20 08:55:22 +01:00
* @ var calendar_so
2006-12-22 20:51:56 +01:00
*/
var $so ;
2009-11-25 13:55:59 +01:00
/**
* Instance of the categories class
*
2016-05-01 19:47:59 +02:00
* @ var Api\Categories
2009-11-25 13:55:59 +01:00
*/
var $categories ;
2016-07-06 12:45:22 +02:00
/**
* Config values for " calendar " , only used for horizont , regular calendar config is under phpgwapi
*
* @ var array
*/
var $config ;
2004-08-01 17:36:04 +02:00
2009-11-19 19:56:04 +01:00
/**
* Does a user require an extra invite grant , to be able to invite an other user , default no
*
2013-01-24 13:54:08 +01:00
* @ var string 'all' , 'groups' or null
2009-11-19 19:56:04 +01:00
*/
2013-01-24 13:54:08 +01:00
public $require_acl_invite = null ;
2009-11-19 19:56:04 +01:00
2011-06-14 20:33:26 +02:00
/**
* Warnings to show in regular UI
*
* @ var array
*/
var $warnings = array ();
2004-08-01 17:36:04 +02:00
/**
* Constructor
*/
2008-06-07 19:45:33 +02:00
function __construct ()
2004-08-01 17:36:04 +02:00
{
2015-07-16 14:10:48 +02:00
if ( $this -> debug > 0 ) $this -> debug_message ( 'calendar_bo::bocal() started' , True );
2008-05-08 17:02:35 +02:00
2008-06-07 19:45:33 +02:00
$this -> so = new calendar_so ();
2004-08-01 17:36:04 +02:00
2005-11-09 00:15:14 +01:00
$this -> common_prefs =& $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ];
$this -> cal_prefs =& $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'calendar' ];
2004-08-01 17:36:04 +02:00
2010-06-07 19:54:29 +02:00
$this -> now = time ();
2016-05-01 19:47:59 +02:00
$this -> now_su = Api\DateTime :: server2user ( $this -> now , 'ts' );
2004-08-01 17:36:04 +02:00
2005-11-09 00:15:14 +01:00
$this -> user = $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ];
2004-08-01 17:36:04 +02:00
2005-11-09 00:15:14 +01:00
$this -> grants = $GLOBALS [ 'egw' ] -> acl -> get_grants ( 'calendar' );
2004-08-01 17:36:04 +02:00
2016-05-01 19:47:59 +02:00
if ( ! is_array ( $this -> resources = Api\Cache :: getSession ( 'calendar' , 'resources' )))
2005-11-09 00:15:14 +01:00
{
$this -> resources = array ();
2016-05-01 19:47:59 +02:00
foreach ( Api\Hooks :: process ( 'calendar_resources' ) as $app => $data )
2005-11-09 00:15:14 +01:00
{
if ( $data && $data [ 'type' ])
{
$this -> resources [ $data [ 'type' ]] = $data + array ( 'app' => $app );
}
}
2008-05-08 17:02:35 +02:00
$this -> resources [ 'e' ] = array (
2009-07-08 12:22:11 +02:00
'type' => 'e' ,
'info' => __CLASS__ . '::email_info' ,
'app' => 'email' ,
2008-05-08 17:02:35 +02:00
);
2016-07-06 21:18:36 +02:00
$this -> resources [ 'l' ] = array (
'type' => 'l' , // one char type-identifier for this resources
'info' => __CLASS__ . '::mailing_lists' , // info method, returns array with id, type & name for a given id
2016-07-20 20:39:06 +02:00
'app' => 'Distribution list'
2016-07-06 21:18:36 +02:00
);
2011-09-07 16:47:51 +02:00
$this -> resources [ '' ] = array (
'type' => '' ,
2016-05-01 11:57:48 +02:00
'app' => 'api-accounts' ,
2011-09-07 16:47:51 +02:00
);
2016-05-01 19:47:59 +02:00
Api\Cache :: setSession ( 'calendar' , 'resources' , $this -> resources );
2008-05-08 17:02:35 +02:00
}
2016-05-02 21:22:52 +02:00
//error_log(__METHOD__ . " registered resources=". array2string($this->resources));
2005-11-09 00:15:14 +01:00
2016-07-06 12:45:22 +02:00
$this -> config = Api\Config :: read ( 'calendar' ); // only used for horizont, regular calendar config is under phpgwapi
2022-04-26 21:04:16 +02:00
$this -> require_acl_invite = $GLOBALS [ 'egw_info' ][ 'server' ][ 'require_acl_invite' ] ? ? null ;
2009-12-01 11:24:55 +01:00
2016-05-01 19:47:59 +02:00
$this -> categories = new Api\Categories ( $this -> user , 'calendar' );
2013-05-10 12:54:36 +02:00
2016-05-01 19:47:59 +02:00
$this -> customfields = Api\Storage\Customfields :: get ( 'calendar' );
2014-05-28 12:03:57 +02:00
foreach ( $this -> alarms as $secs => & $label )
{
$label = self :: secs2label ( $secs );
}
}
/**
* Generate translated label for a given number of seconds
*
* @ param int $secs
* @ return string
*/
static public function secs2label ( $secs )
{
if ( $secs <= 3600 )
{
$label = lang ( '%1 minutes' , $secs / 60 );
}
elseif ( $secs <= 86400 )
{
$label = lang ( '%1 hours' , $secs / 3600 );
}
else
{
$label = lang ( '%1 days' , $secs / 86400 );
}
return $label ;
2004-08-01 17:36:04 +02:00
}
2008-05-08 17:02:35 +02:00
/**
* returns info about email addresses as participants
*
2009-08-04 19:14:16 +02:00
* @ param int | array $ids single contact - id or array of id ' s
2008-05-08 17:02:35 +02:00
* @ return array
*/
static function email_info ( $ids )
{
if ( ! $ids ) return null ;
$data = array ();
2011-04-28 19:55:44 +02:00
foreach (( array ) $ids as $id )
2008-05-08 17:02:35 +02:00
{
$email = $id ;
$name = '' ;
2015-07-16 14:10:48 +02:00
$matches = null ;
2014-03-13 11:20:17 +01:00
if ( preg_match ( '/^(.*) *<([a-z0-9_.@-]{8,})>$/iU' , $email , $matches ))
2008-05-08 17:02:35 +02:00
{
$name = $matches [ 1 ];
$email = $matches [ 2 ];
}
$data [] = array (
2009-07-08 12:22:11 +02:00
'res_id' => $id ,
'email' => $email ,
2019-07-26 22:59:10 +02:00
'rights' => self :: ACL_READ_FOR_PARTICIPANTS | self :: ACL_INVITE ,
2009-07-08 12:22:11 +02:00
'name' => $name ,
2008-05-08 17:02:35 +02:00
);
}
2011-04-28 19:55:44 +02:00
//error_log(__METHOD__.'('.array2string($ids).')='.array2string($data).' '.function_backtrace());
2008-05-08 17:02:35 +02:00
return $data ;
}
2016-07-06 21:18:36 +02:00
/**
* returns info about mailing lists as participants
*
* @ param int | array $ids single mailing list ID or array of id ' s
* @ return array
*/
static function mailing_lists ( $ids )
{
if ( ! is_array ( $ids ))
{
$ids = array ( $ids );
}
$data = array ();
// Email list
$contacts_obj = new Api\Contacts ();
2016-07-19 22:09:58 +02:00
$bo = new calendar_bo ();
2016-07-06 21:18:36 +02:00
foreach ( $ids as $id )
{
$list = $contacts_obj -> read_list (( int ) $id );
2020-09-03 21:26:41 +02:00
if ( ! $list && $id < 0 )
{
$list = array (
'list_name' => Link :: title ( 'api-accounts' , $id ) ? : Api\Accounts :: username ( $id )
);
}
2016-07-06 21:18:36 +02:00
$data [] = array (
'res_id' => $id ,
'rights' => self :: ACL_READ_FOR_PARTICIPANTS ,
'name' => $list [ 'list_name' ],
2016-07-19 22:09:58 +02:00
'resources' => $bo -> enum_mailing_list ( 'l' . $id , false , false )
2016-07-06 21:18:36 +02:00
);
}
return $data ;
}
2016-07-12 19:22:25 +02:00
/**
* Enumerates the contacts in a contact list , and returns the list of contact IDs
*
* This is used to enable mailing lists as owner / participant
*
* @ param string $id Mailing list participant ID , which is the mailing list
* ID prefixed with 'l'
* @ param boolean $ignore_acl = false Flag to skip ACL checks
* @ param boolean $use_freebusy = true should freebusy rights are taken into account , default true , can be set to false eg . for a search
*
* @ return array
*/
public function enum_mailing_list ( $id , $ignore_acl = false , $use_freebusy = true )
{
$contact_list = array ();
$contacts = new Api\Contacts ();
2017-08-02 19:14:31 +02:00
if ( $contacts -> check_list (( int ) substr ( $id , 1 ), ACL :: READ ) || ( int ) substr ( $id , 1 ) < 0 )
2016-07-12 19:22:25 +02:00
{
$options = array ( 'list' => substr ( $id , 1 ));
$lists = $contacts -> search ( '' , true , '' , '' , '' , false , 'AND' , false , $options );
if ( ! $lists )
{
return $contact_list ;
}
foreach ( $lists as & $contact )
{
2016-09-01 17:26:56 +02:00
// Check for user account
if (( $account_id = $GLOBALS [ 'egw' ] -> accounts -> name2id ( $contact [ 'id' ], 'person_id' )))
{
$contact = '' . $account_id ;
}
else
{
$contact = 'c' . $contact [ 'id' ];
}
2016-07-12 19:22:25 +02:00
if ( $ignore_acl || $this -> check_perms ( ACL :: READ | self :: ACL_READ_FOR_PARTICIPANTS | ( $use_freebusy ? self :: ACL_FREEBUSY : 0 ), 0 , $contact ))
{
if ( $contact && ! in_array ( $contact , $contact_list )) // already added?
{
$contact_list [] = $contact ;
}
}
}
}
return $contact_list ;
}
2017-01-18 18:29:44 +01:00
2005-11-23 15:21:20 +01:00
/**
* Add group - members as participants with status 'G'
*
* @ param array $event event - array
* @ return int number of added participants
*/
function enum_groups ( & $event )
{
$added = 0 ;
2020-03-11 16:25:24 +01:00
foreach ( array_keys (( array ) $event [ 'participants' ]) as $uid )
2005-11-23 15:21:20 +01:00
{
if ( is_numeric ( $uid ) && $GLOBALS [ 'egw' ] -> accounts -> get_type ( $uid ) == 'g' &&
2020-03-11 16:25:24 +01:00
( $members = $GLOBALS [ 'egw' ] -> accounts -> members ( $uid , true )))
2005-11-23 15:21:20 +01:00
{
2020-03-11 16:25:24 +01:00
foreach ( $members as $member )
2005-11-23 15:21:20 +01:00
{
if ( ! isset ( $event [ 'participants' ][ $member ]))
{
$event [ 'participants' ][ $member ] = 'G' ;
++ $added ;
}
}
}
}
return $added ;
}
2004-08-01 17:36:04 +02:00
/**
2011-04-06 14:46:21 +02:00
* Resolve users to add memberships for users and members for groups
2004-08-01 17:36:04 +02:00
*
2011-04-06 14:46:21 +02:00
* @ param int | array $_users
2015-07-16 14:10:48 +02:00
* @ param boolean $no_enum_groups = true
* @ param boolean $ignore_acl = false
* @ param boolean $use_freebusy = true should freebusy rights are taken into account , default true , can be set to false eg . for a search
2011-04-06 14:46:21 +02:00
* @ return array of user - ids
2004-08-01 17:36:04 +02:00
*/
2011-08-16 12:20:40 +02:00
private function resolve_users ( $_users , $no_enum_groups = true , $ignore_acl = false , $use_freebusy = true )
2004-08-01 17:36:04 +02:00
{
2011-04-06 14:46:21 +02:00
if ( ! is_array ( $_users ))
2004-08-01 17:36:04 +02:00
{
2011-04-06 14:46:21 +02:00
$_users = $_users ? array ( $_users ) : array ();
2004-08-01 17:36:04 +02:00
}
// only query calendars of users, we have READ-grants from
$users = array ();
2011-04-06 14:46:21 +02:00
foreach ( $_users as $user )
2004-08-01 17:36:04 +02:00
{
2009-12-04 11:22:33 +01:00
$user = trim ( $user );
2016-07-06 21:18:36 +02:00
// Handle email lists
if ( ! is_numeric ( $user ) && $user [ 0 ] == 'l' )
{
2016-07-12 19:22:25 +02:00
foreach ( $this -> enum_mailing_list ( $user , $ignore_acl , $use_freebusy ) as $contact )
2016-07-06 21:18:36 +02:00
{
2016-07-12 19:22:25 +02:00
if ( $contact && ! in_array ( $contact , $users )) // already added?
2016-07-06 21:18:36 +02:00
{
2016-07-12 19:22:25 +02:00
$users [] = $contact ;
2016-07-06 21:18:36 +02:00
}
}
continue ;
}
2016-05-01 19:47:59 +02:00
if ( $ignore_acl || $this -> check_perms ( ACL :: READ | self :: ACL_READ_FOR_PARTICIPANTS | ( $use_freebusy ? self :: ACL_FREEBUSY : 0 ), 0 , $user ))
2004-08-01 17:36:04 +02:00
{
2006-10-11 20:52:39 +02:00
if ( $user && ! in_array ( $user , $users )) // already added?
2005-12-02 17:43:23 +01:00
{
2016-07-19 22:09:58 +02:00
// General expansion check
if ( ! is_numeric ( $user ) && $this -> resources [ $user [ 0 ]][ 'info' ])
{
$info = $this -> resource_info ( $user );
if ( $info && $info [ 'resources' ])
{
foreach ( $info [ 'resources' ] as $_user )
{
if ( $_user && ! in_array ( $_user , $users ))
{
$users [] = $_user ;
}
}
continue ;
}
}
2005-12-02 17:43:23 +01:00
$users [] = $user ;
}
2005-11-24 12:21:29 +01:00
}
elseif ( $GLOBALS [ 'egw' ] -> accounts -> get_type ( $user ) != 'g' )
{
continue ; // for non-groups (eg. users), we stop here if we have no read-rights
}
2006-03-05 11:26:03 +01:00
// the further code is only for real users
if ( ! is_numeric ( $user )) continue ;
2005-11-24 12:21:29 +01:00
// for groups we have to include the members
if ( $GLOBALS [ 'egw' ] -> accounts -> get_type ( $user ) == 'g' )
{
2023-03-24 16:16:06 +01:00
// Include the group itself to catch group invitations
$users [] = $user ;
if ( $no_enum_groups )
{
continue ;
}
2009-11-19 19:56:04 +01:00
2016-03-06 17:09:58 +01:00
$members = $GLOBALS [ 'egw' ] -> accounts -> members ( $user , true );
2023-03-24 16:16:06 +01:00
if ( is_array ( $members ))
2005-11-09 00:15:14 +01:00
{
2005-11-24 12:21:29 +01:00
foreach ( $members as $member )
2005-11-09 00:15:14 +01:00
{
2005-11-24 12:21:29 +01:00
// use only members which gave the user a read-grant
2023-03-24 16:16:06 +01:00
if ( ! in_array ( $member , $users ) &&
( $ignore_acl || $this -> check_perms ( Acl :: READ | ( $use_freebusy ? self :: ACL_FREEBUSY : 0 ), 0 , $member )))
2005-11-09 00:15:14 +01:00
{
2016-03-06 17:09:58 +01:00
$users [] = $member ;
2005-11-09 00:15:14 +01:00
}
}
}
2005-11-24 12:21:29 +01:00
}
else // for users we have to include all the memberships, to get the group-events
{
2016-03-06 17:09:58 +01:00
$memberships = $GLOBALS [ 'egw' ] -> accounts -> memberships ( $user , true );
2005-11-24 12:21:29 +01:00
if ( is_array ( $memberships ))
2005-11-23 15:21:20 +01:00
{
2005-11-24 12:21:29 +01:00
foreach ( $memberships as $group )
2005-11-23 15:21:20 +01:00
{
2016-03-06 17:09:58 +01:00
if ( ! in_array ( $group , $users ))
2005-11-23 15:21:20 +01:00
{
2016-03-06 17:09:58 +01:00
$users [] = $group ;
2005-11-23 15:21:20 +01:00
}
}
}
2004-08-01 17:36:04 +02:00
}
}
2011-04-06 14:46:21 +02:00
return $users ;
}
/**
* Searches / lists calendar entries , including repeating ones
*
* @ param array $params array with the following keys
* start date startdate of the search / list , defaults to today
* end date enddate of the search / list , defaults to start + one day
* users int | array integer user - id or array of user - id ' s to use , defaults to the current user
* cat_id int | array category - id or array of cat - id ' s ( incl . all sub - categories ), default 0 = all
2012-09-26 16:30:47 +02:00
* filter string all ( not rejected ), accepted , unknown , tentative , rejected , hideprivate or everything ( incl . rejected , deleted )
2011-04-06 14:46:21 +02:00
* query string pattern so search for , if unset or empty all matching entries are returned ( no search )
* Please Note : a search never returns repeating events more then once AND does not honor start + end date !!!
* daywise boolean on True it returns an array with YYYYMMDD strings as keys and an array with events
* ( events spanning multiple days are returned each day again ( ! )) otherwise it returns one array with
* the events ( default ), not honored in a search ==> always returns an array of events !
* date_format string date - formats : 'ts' = timestamp ( default ), 'array' = array , or string with format for date
* offset boolean | int false ( default ) to return all entries or integer offset to return only a limited result
* enum_recuring boolean if true or not set ( default ) or daywise is set , each recurence of a recuring events is returned ,
* otherwise the original recuring event ( with the first start - + enddate ) is returned
* num_rows int number of entries to return , default or if 0 , max_entries from the prefs
* order column - names plus optional DESC | ASC separted by comma
2017-09-05 19:01:48 +02:00
* private_allowed array Array of user IDs that are allowed when clearing private
* info , defaults to users
2016-05-01 19:47:59 +02:00
* ignore_acl if set and true no check_perms for a general Acl :: READ grants is performed
2011-04-06 14:46:21 +02:00
* enum_groups boolean if set and true , group - members will be added as participants with status 'G'
* cols string | array columns to select , if set an iterator will be returned
* append string to append to the query , eg . GROUP BY
* cfs array if set , query given custom fields or all for empty array , none are returned , if not set ( default )
2012-03-12 09:20:36 +01:00
* master_only boolean default false , true only take into account participants / status from master ( for AS )
2015-07-16 14:10:48 +02:00
* @ param string $sql_filter = null sql to be and ' ed into query ( fully quoted ), default none
2011-04-06 14:46:21 +02:00
* @ return iterator | array | boolean array of events or array with YYYYMMDD strings / array of events pairs ( depending on $daywise param )
* or false if there are no read - grants from _any_ of the requested users or iterator / recordset if cols are given
*/
function & search ( $params , $sql_filter = null )
{
$params_in = $params ;
$params [ 'sql_filter' ] = $sql_filter ; // dont allow to set it via UI or xmlrpc
// check if any resource wants to hook into
2015-07-16 14:10:48 +02:00
foreach ( $this -> resources as $data )
2011-04-06 14:46:21 +02:00
{
if ( isset ( $data [ 'search_filter' ]))
{
$params = ExecMethod ( $data [ 'search_filter' ], $params );
}
}
2018-04-09 16:02:00 +02:00
if ( empty ( $params [ 'users' ]) ||
is_array ( $params [ 'users' ]) && count ( $params [ 'users' ]) == 1 && empty ( $params [ 'users' ][ 0 ])) // null or '' casted to an array
2011-04-06 14:46:21 +02:00
{
// for a search use all account you have read grants from
$params [ 'users' ] = $params [ 'query' ] ? array_keys ( $this -> grants ) : $this -> user ;
}
// resolve users to add memberships for users and members for groups
2011-08-16 12:20:40 +02:00
// for search, do NOT use freebusy rights, as it would allow to probe the content of event entries
2023-06-09 18:27:28 +02:00
$users = $this -> resolve_users ( $params [ 'users' ], $params [ 'filter' ] == 'no-enum-groups' , $params [ 'ignore_acl' ] ? ? null , empty ( $params [ 'query' ]));
if ( ! empty ( $params [ 'private_allowed' ]))
2018-01-11 17:33:33 +01:00
{
$params [ 'private_allowed' ] = $this -> resolve_users ( $params [ 'private_allowed' ], $params [ 'filter' ] == 'no-enum-groups' , $params [ 'ignore_acl' ], empty ( $params [ 'query' ]));
}
2011-08-16 12:20:40 +02:00
// supply so with private_grants, to not query them again from the database
if ( ! empty ( $params [ 'query' ]))
{
$params [ 'private_grants' ] = array ();
foreach ( $this -> grants as $user => $rights )
{
2016-05-01 19:47:59 +02:00
if ( $rights & Acl :: PRIVAT ) $params [ 'private_grants' ][] = $user ;
2011-08-16 12:20:40 +02:00
}
}
2011-04-06 14:46:21 +02:00
2009-11-19 19:56:04 +01:00
// replace (by so not understood filter 'no-enum-groups' with 'default' filter
if ( $params [ 'filter' ] == 'no-enum-groups' )
{
$params [ 'filter' ] = 'default' ;
}
2008-05-08 17:02:35 +02:00
// if we have no grants from the given user(s), we directly return no events / an empty array,
2005-11-09 00:15:14 +01:00
// as calling the so-layer without users would give the events of all users (!)
2017-01-18 18:29:44 +01:00
if ( ! count ( $users ) && ! $params [ 'ignore_acl' ])
2005-11-09 00:15:14 +01:00
{
2006-03-05 11:26:03 +01:00
return false ;
2005-11-09 00:15:14 +01:00
}
if ( isset ( $params [ 'start' ])) $start = $this -> date2ts ( $params [ 'start' ]);
if ( isset ( $params [ 'end' ]))
{
$end = $this -> date2ts ( $params [ 'end' ]);
$this -> check_move_horizont ( $end );
}
2004-08-01 17:36:04 +02:00
$daywise = ! isset ( $params [ 'daywise' ]) ? False : !! $params [ 'daywise' ];
2011-04-05 17:32:20 +02:00
$params [ 'enum_recuring' ] = $enum_recuring = $daywise || ! isset ( $params [ 'enum_recuring' ]) || !! $params [ 'enum_recuring' ];
2004-08-01 17:36:04 +02:00
$cat_id = isset ( $params [ 'cat_id' ]) ? $params [ 'cat_id' ] : 0 ;
$filter = isset ( $params [ 'filter' ]) ? $params [ 'filter' ] : 'all' ;
2005-11-09 00:15:14 +01:00
$offset = isset ( $params [ 'offset' ]) && $params [ 'offset' ] !== false ? ( int ) $params [ 'offset' ] : false ;
2011-04-05 17:32:20 +02:00
// socal::search() returns rejected group-invitations, as only the user not also the group is rejected
// as we cant remove them efficiantly in SQL, we kick them out here, but only if just one user is displayed
2024-02-08 10:24:39 +01:00
$users_in = ( array )( $params_in [ 'users' ] ? ? []);
2012-09-26 16:30:47 +02:00
$remove_rejected_by_user = ! in_array ( $filter , array ( 'all' , 'rejected' , 'everything' )) &&
2011-04-09 16:41:15 +02:00
count ( $users_in ) == 1 && $users_in [ 0 ] > 0 ? $users_in [ 0 ] : null ;
//error_log(__METHOD__.'('.array2string($params_in).", $sql_filter) params[users]=".array2string($params['users']).' --> remove_rejected_by_user='.array2string($remove_rejected_by_user));
2011-04-05 17:32:20 +02:00
2004-08-01 17:36:04 +02:00
if ( $this -> debug && ( $this -> debug > 1 || $this -> debug == 'search' ))
{
2010-11-28 12:01:44 +01:00
$this -> debug_message ( 'calendar_bo::search(%1) start=%2, end=%3, daywise=%4, cat_id=%5, filter=%6, query=%7, offset=%8, num_rows=%9, order=%10, sql_filter=%11)' ,
2009-09-29 21:58:51 +02:00
True , $params , $start , $end , $daywise , $cat_id , $filter , $params [ 'query' ], $offset ,( int ) $params [ 'num_rows' ], $params [ 'order' ], $params [ 'sql_filter' ]);
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
// date2ts(,true) converts to server time, db2data converts again to user-time
$events =& $this -> so -> search ( isset ( $start ) ? $this -> date2ts ( $start , true ) : null , isset ( $end ) ? $this -> date2ts ( $end , true ) : null ,
2024-02-08 10:24:39 +01:00
$users , $cat_id , $filter , $offset ,( int )( $params [ 'num_rows' ] ? ? 0 ), $params , $remove_rejected_by_user );
2009-05-05 00:52:48 +02:00
if ( isset ( $params [ 'cols' ]))
{
return $events ;
}
2005-11-09 00:15:14 +01:00
$this -> total = $this -> so -> total ;
$this -> db2data ( $events , isset ( $params [ 'date_format' ]) ? $params [ 'date_format' ] : 'ts' );
2008-05-08 17:02:35 +02:00
2009-09-29 21:58:51 +02:00
//echo "<p align=right>remove_rejected_by_user=$remove_rejected_by_user, filter=$filter, params[users]=".print_r($param['users'])."</p>\n";
2005-11-09 00:15:14 +01:00
foreach ( $events as $id => $event )
2004-08-01 17:36:04 +02:00
{
2023-06-09 18:27:28 +02:00
if ( ! empty ( $params [ 'enum_groups' ]) && $this -> enum_groups ( $event ))
2005-11-23 15:21:20 +01:00
{
$events [ $id ] = $event ;
}
2015-07-16 14:10:48 +02:00
$matches = null ;
2010-01-22 00:36:05 +01:00
if ( ! ( int ) $event [ 'id' ] && preg_match ( '/^([a-z_]+)([0-9]+)$/' , $event [ 'id' ], $matches ))
{
$is_private = self :: integration_get_private ( $matches [ 1 ], $matches [ 2 ], $event );
}
else
{
2016-05-01 19:47:59 +02:00
$is_private = ! $this -> check_perms ( Acl :: READ , $event );
2010-01-22 00:36:05 +01:00
}
2023-06-09 18:27:28 +02:00
if ( empty ( $params [ 'ignore_acl' ]) && ( $is_private || ( ! $event [ 'public' ] && $filter == 'hideprivate' )))
2004-08-01 17:36:04 +02:00
{
2023-06-09 18:27:28 +02:00
$this -> clear_private_infos ( $events [ $id ], $params [ 'private_allowed' ] ? : $users );
2004-08-01 17:36:04 +02:00
}
}
2005-11-09 00:15:14 +01:00
if ( $daywise )
2004-08-01 17:36:04 +02:00
{
2005-11-09 00:15:14 +01:00
if ( $this -> debug && ( $this -> debug > 2 || $this -> debug == 'search' ))
{
$this -> debug_message ( 'socalendar::search daywise sorting from %1 to %2 of %3' , False , $start , $end , $events );
}
// create empty entries for each day in the reported time
2010-02-07 15:37:27 +01:00
for ( $ts = $start ; $ts <= $end ; $ts += DAY_s ) // good enough for array creation, but see while loop below.
2005-11-09 00:15:14 +01:00
{
$daysEvents [ $this -> date2string ( $ts )] = array ();
}
foreach ( $events as $k => $event )
{
$e_start = max ( $this -> date2ts ( $event [ 'start' ]), $start );
// $event['end']['raw']-1 to allow events to end on a full hour/day without the need to enter it as minute=59
$e_end = min ( $this -> date2ts ( $event [ 'end' ]) - 1 , $end );
2004-08-01 17:36:04 +02:00
2005-11-09 00:15:14 +01:00
// add event to each day in the reported time
2010-02-07 15:37:27 +01:00
$ts = $e_start ;
// $ts += DAY_s in a 'for' loop does not work for daylight savings in week view
// because the day is longer than DAY_s: Fullday events will be added twice.
2015-07-16 14:10:48 +02:00
$ymd = null ;
2010-02-07 15:37:27 +01:00
while ( $ts <= $e_end )
2005-11-09 00:15:14 +01:00
{
$daysEvents [ $ymd = $this -> date2string ( $ts )][] =& $events [ $k ];
2010-02-07 15:37:27 +01:00
$ts = strtotime ( " +1 day " , $ts );
2005-11-09 00:15:14 +01:00
}
if ( $ymd != ( $last = $this -> date2string ( $e_end )))
{
$daysEvents [ $last ][] =& $events [ $k ];
2008-05-08 17:02:35 +02:00
}
2005-11-09 00:15:14 +01:00
}
$events =& $daysEvents ;
if ( $this -> debug && ( $this -> debug > 2 || $this -> debug == 'search' ))
2004-08-01 17:36:04 +02:00
{
2005-11-09 00:15:14 +01:00
$this -> debug_message ( 'socalendar::search daywise events=%1' , False , $events );
2004-08-01 17:36:04 +02:00
}
}
2005-11-09 00:15:14 +01:00
if ( $this -> debug && ( $this -> debug > 0 || $this -> debug == 'search' ))
{
2010-11-28 12:01:44 +01:00
$this -> debug_message ( 'calendar_bo::search(%1)=%2' , True , $params , $events );
2005-11-09 00:15:14 +01:00
}
2011-04-05 17:32:20 +02:00
//error_log(__METHOD__."() returning ".count($events)." entries, total=$this->total ".function_backtrace());
2005-11-09 00:15:14 +01:00
return $events ;
}
2008-05-08 17:02:35 +02:00
2010-01-22 00:36:05 +01:00
/**
* Get integration data for a given app of a part ( value for a certain key ) of it
2010-01-29 22:42:54 +01:00
*
2010-01-22 00:36:05 +01:00
* @ param string $app
* @ param string $part
2021-03-12 20:34:07 +01:00
* @ param boole $try_load = false true : load if not yet loaded
2010-01-22 00:36:05 +01:00
* @ return array
*/
2021-03-12 20:34:07 +01:00
static function integration_get_data ( $app , $part = null , $try_load = false )
2010-01-22 00:36:05 +01:00
{
2015-07-16 14:10:48 +02:00
static $integration_data = null ;
2010-01-29 22:42:54 +01:00
2010-01-22 00:36:05 +01:00
if ( ! isset ( $integration_data ))
{
2021-03-12 20:34:07 +01:00
$integration_data = calendar_so :: get_integration_data ( $try_load );
2010-01-22 00:36:05 +01:00
}
2010-01-29 22:42:54 +01:00
2010-01-22 00:36:05 +01:00
if ( ! isset ( $integration_data [ $app ])) return null ;
2010-01-29 22:42:54 +01:00
2010-01-22 00:36:05 +01:00
return $part ? $integration_data [ $app ][ $part ] : $integration_data [ $app ];
}
2010-01-29 22:42:54 +01:00
2021-03-12 20:34:07 +01:00
/**
* Check if an integration event is deletable
*
* @ param string $app
* @ param array $event
* @ return bool
*/
static function integration_deletable ( $app , array $event )
{
$app_data = self :: integration_get_data ( $app , 'deletable' );
if ( empty ( $app_data ) || is_bool ( $app_data ))
{
return ( bool ) $app_data ;
}
return ( bool )( is_callable ( $app_data ) ? $app_data ( $event ) : ExecMethod2 ( $app_data , $event ));
}
2010-01-22 00:36:05 +01:00
/**
* Get private attribute for an integration event
2010-01-29 22:42:54 +01:00
*
2010-01-22 00:36:05 +01:00
* Attribute 'is_private' is either a boolean value , eg . false to make all events of $app public
* or an ExecMethod callback with parameters $id , $event
2010-01-29 22:42:54 +01:00
*
2010-01-22 00:36:05 +01:00
* @ param string $app
* @ param int | string $id
* @ return string
*/
static function integration_get_private ( $app , $id , $event )
{
$app_data = self :: integration_get_data ( $app , 'is_private' );
2010-01-29 22:42:54 +01:00
2010-01-22 00:36:05 +01:00
// no method, fall back to link title
if ( is_null ( $app_data ))
{
2016-05-01 19:47:59 +02:00
$is_private = ! Link :: title ( $app , $id );
2010-01-22 00:36:05 +01:00
}
// boolean value to make all events of $app public (false) or private (true)
elseif ( is_bool ( $app_data ))
{
$is_private = $app_data ;
}
else
{
$is_private = ( bool ) ExecMethod2 ( $app_data , $id , $event );
}
2010-01-31 00:54:08 +01:00
//echo '<p>'.__METHOD__."($app,$id,) app_data=".array2string($app_data).' returning '.array2string($is_private)."</p>\n";
2010-01-22 00:36:05 +01:00
return $is_private ;
}
2005-11-09 00:15:14 +01:00
/**
* Clears all non - private info from a privat event
*
2016-05-01 19:47:59 +02:00
* That function only returns the infos allowed to be viewed by people without Acl :: PRIVAT grants
2005-11-09 00:15:14 +01:00
*
* @ param array & $event
* @ param array $allowed_participants ids of the allowed participants , eg . the ones the search is over or eg . the owner of the calendar
*/
function clear_private_infos ( & $event , $allowed_participants = array ())
{
2012-07-25 10:07:10 +02:00
if ( $event == false ) return ;
2012-03-12 09:20:36 +01:00
if ( ! is_array ( $event [ 'participants' ])) error_log ( __METHOD__ . '(' . array2string ( $event ) . ', ' . array2string ( $allowed_participants ) . ') NO PARTICIPANTS ' . function_backtrace ());
2005-11-09 00:15:14 +01:00
$event = array (
2009-07-08 12:22:11 +02:00
'id' => $event [ 'id' ],
'start' => $event [ 'start' ],
'end' => $event [ 'end' ],
2015-10-09 19:37:01 +02:00
'whole_day' => $event [ 'whole_day' ],
2009-11-26 11:27:46 +01:00
'tzid' => $event [ 'tzid' ],
2009-07-08 12:22:11 +02:00
'title' => lang ( 'private' ),
2010-05-14 10:35:16 +02:00
'modified' => $event [ 'modified' ],
'owner' => $event [ 'owner' ],
2014-04-08 15:12:41 +02:00
'uid' => $event [ 'uid' ],
2010-05-14 10:35:16 +02:00
'etag' => $event [ 'etag' ],
2009-07-08 12:22:11 +02:00
'participants' => array_intersect_key ( $event [ 'participants' ], array_flip ( $allowed_participants )),
'public' => 0 ,
'category' => $event [ 'category' ], // category is visible anyway, eg. by using planner by cat
'non_blocking' => $event [ 'non_blocking' ],
2012-09-27 11:02:43 +02:00
'caldav_name' => $event [ 'caldav_name' ],
2015-10-09 19:37:01 +02:00
// we need full recurrence information, as they are relevant free/busy information
) + ( $event [ 'recur_type' ] ? array (
'recur_type' => $event [ 'recur_type' ],
'recur_interval' => $event [ 'recur_interval' ],
'recur_data' => $event [ 'recur_data' ],
'recur_enddate' => $event [ 'recur_enddate' ],
'recur_exception' => $event [ 'recur_exception' ],
) : array (
'reference' => $event [ 'reference' ],
'recurrence' => $event [ 'recurrence' ],
));
2005-11-09 00:15:14 +01:00
}
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
/**
* check and evtl . move the horizont ( maximum date for unlimited recuring events ) to a new date
*
* @ internal automaticaly called by search
2015-07-16 14:10:48 +02:00
* @ param mixed $_new_horizont time to set the horizont to ( user - time )
2005-11-09 00:15:14 +01:00
*/
2015-07-16 14:10:48 +02:00
function check_move_horizont ( $_new_horizont )
2005-11-09 00:15:14 +01:00
{
if (( int ) $this -> debug >= 2 || $this -> debug == 'check_move_horizont' )
{
2015-07-16 14:10:48 +02:00
$this -> debug_message ( 'calendar_bo::check_move_horizont(%1) horizont=%2' , true , $_new_horizont ,( int ) $this -> config [ 'horizont' ]);
2005-11-09 00:15:14 +01:00
}
2015-07-16 14:10:48 +02:00
$new_horizont = $this -> date2ts ( $_new_horizont , true ); // now we are in server-time, where this function operates
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
if ( $new_horizont <= $this -> config [ 'horizont' ]) // no move necessary
{
2011-06-14 20:33:26 +02:00
if ( $this -> debug == 'check_move_horizont' ) $this -> debug_message ( 'calendar_bo::check_move_horizont(%1) horizont=%2 is bigger ==> nothing to do' , true , $new_horizont ,( int ) $this -> config [ 'horizont' ]);
2005-11-09 00:15:14 +01:00
return ;
2004-08-01 17:36:04 +02:00
}
2010-05-03 18:43:42 +02:00
if ( ! empty ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'calendar_horizont' ]))
{
$maxdays = abs ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'calendar_horizont' ]);
}
if ( empty ( $maxdays )) $maxdays = 1000 ; // old default
if ( $new_horizont > time () + $maxdays * DAY_s ) // some user tries to "look" more then the maximum number of days in the future
{
2011-06-14 20:33:26 +02:00
if ( $this -> debug == 'check_move_horizont' ) $this -> debug_message ( 'calendar_bo::check_move_horizont(%1) horizont=%2 new horizont more then %3 days from now --> ignoring it' , true , $new_horizont ,( int ) $this -> config [ 'horizont' ], $maxdays );
2016-05-01 19:47:59 +02:00
$this -> warnings [ 'horizont' ] = lang ( 'Requested date %1 outside allowed range of %2 days: recurring events obmitted!' , Api\DateTime :: to ( $new_horizont , true ), $maxdays );
2011-06-14 20:33:26 +02:00
return ;
2010-05-03 18:43:42 +02:00
}
2005-11-09 00:15:14 +01:00
if ( $new_horizont < time () + 31 * DAY_s )
2004-08-01 17:36:04 +02:00
{
2005-11-09 00:15:14 +01:00
$new_horizont = time () + 31 * DAY_s ;
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
$old_horizont = $this -> config [ 'horizont' ];
$this -> config [ 'horizont' ] = $new_horizont ;
2010-02-22 11:02:33 +01:00
// create further recurrences for all recurring and not yet (at the old horizont) ended events
2005-11-09 00:15:14 +01:00
if (( $recuring = $this -> so -> unfinished_recuring ( $old_horizont )))
2004-08-01 17:36:04 +02:00
{
2011-06-14 20:33:26 +02:00
@ set_time_limit ( 0 ); // disable time-limit, in case it takes longer to calculate the recurrences
2005-11-09 00:15:14 +01:00
foreach ( $this -> read ( array_keys ( $recuring )) as $cal_id => $event )
2004-08-01 17:36:04 +02:00
{
2005-11-09 00:15:14 +01:00
if ( $this -> debug == 'check_move_horizont' )
{
2010-11-28 12:01:44 +01:00
$this -> debug_message ( 'calendar_bo::check_move_horizont(%1): calling set_recurrences(%2,%3)' , true , $new_horizont , $event , $old_horizont );
2005-11-09 00:15:14 +01:00
}
// insert everything behind max(cal_start), which can be less then $old_horizont because of bugs in the past
2016-05-01 19:47:59 +02:00
$this -> set_recurrences ( $event , Api\DateTime :: server2user ( $recuring [ $cal_id ] + 1 )); // set_recurences operates in user-time!
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
}
// update the horizont
2016-05-01 19:47:59 +02:00
Api\Config :: save_value ( 'horizont' , $this -> config [ 'horizont' ], 'calendar' );
2008-05-08 17:02:35 +02:00
2011-06-14 20:33:26 +02:00
if ( $this -> debug == 'check_move_horizont' ) $this -> debug_message ( 'calendar_bo::check_move_horizont(%1) new horizont=%2, exiting' , true , $new_horizont ,( int ) $this -> config [ 'horizont' ]);
2005-11-09 00:15:14 +01:00
}
/**
2010-02-22 11:02:33 +01:00
* set all recurrences for an event until the defined horizont $this -> config [ 'horizont' ]
2009-11-12 11:11:23 +01:00
*
* This methods operates in usertime , while $this -> config [ 'horizont' ] is in servertime !
2005-11-09 00:15:14 +01:00
*
* @ param array $event
2015-07-16 14:10:48 +02:00
* @ param mixed $start = 0 minimum start - time for new recurrences or ! $start = since the start of the event
2005-11-09 00:15:14 +01:00
*/
function set_recurrences ( $event , $start = 0 )
{
2010-01-29 22:42:54 +01:00
if ( $this -> debug && (( int ) $this -> debug >= 2 || $this -> debug == 'set_recurrences' || $this -> debug == 'check_move_horizont' ))
2005-11-09 00:15:14 +01:00
{
2010-11-28 12:01:44 +01:00
$this -> debug_message ( 'calendar_bo::set_recurrences(%1,%2)' , true , $event , $start );
2005-11-09 00:15:14 +01:00
}
2010-01-29 22:42:54 +01:00
// check if the caller gave us enough information and if not read it from the DB
if ( ! isset ( $event [ 'participants' ]) || ! isset ( $event [ 'start' ]) || ! isset ( $event [ 'end' ]))
2006-03-09 22:40:35 +01:00
{
2018-12-18 18:20:23 +01:00
$event_read = current ( $this -> so -> read ( $event [ 'id' ]));
2010-01-29 22:42:54 +01:00
if ( ! isset ( $event [ 'participants' ]))
{
$event [ 'participants' ] = $event_read [ 'participants' ];
}
if ( ! isset ( $event [ 'start' ]) || ! isset ( $event [ 'end' ]))
{
2017-05-10 21:47:13 +02:00
$event [ 'start' ] = $this -> date2usertime ( $event_read [ 'start' ]);
$event [ 'end' ] = $this -> date2usertime ( $event_read [ 'end' ]);
2010-01-29 22:42:54 +01:00
}
2006-03-09 22:40:35 +01:00
}
2005-11-09 00:15:14 +01:00
if ( ! $start ) $start = $event [ 'start' ];
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
$events = array ();
2017-10-23 17:56:43 +02:00
2009-11-12 11:11:23 +01:00
$this -> insert_all_recurrences ( $event , $start , $this -> date2usertime ( $this -> config [ 'horizont' ]), $events );
2013-08-15 14:23:38 +02:00
$exceptions = array ();
foreach (( array ) $event [ 'recur_exception' ] as $exception )
{
2016-05-01 19:47:59 +02:00
$exceptions [] = Api\DateTime :: to ( $exception , true ); // true = date
2013-08-15 14:23:38 +02:00
}
2005-11-09 00:15:14 +01:00
foreach ( $events as $event )
{
2016-05-01 19:47:59 +02:00
$is_exception = in_array ( Api\DateTime :: to ( $event [ 'start' ], true ), $exceptions );
2010-05-01 18:25:10 +02:00
$start = $this -> date2ts ( $event [ 'start' ], true );
if ( $event [ 'whole_day' ])
{
2017-06-07 21:19:20 +02:00
$start = new Api\DateTime ( $event [ 'start' ], Api\DateTime :: $server_timezone );
$start -> setTime ( 0 , 0 , 0 );
$start = $start -> format ( 'ts' );
2016-05-01 19:47:59 +02:00
$time = $this -> so -> startOfDay ( new Api\DateTime ( $event [ 'end' ], Api\DateTime :: $user_timezone ));
2010-05-01 18:25:10 +02:00
$time -> setTime ( 23 , 59 , 59 );
$end = $this -> date2ts ( $time , true );
}
else
{
$end = $this -> date2ts ( $event [ 'end' ], true );
}
2016-05-01 19:47:59 +02:00
//error_log(__METHOD__."() start=".Api\DateTime::to($start).", is_exception=".array2string($is_exception));
2013-08-15 14:23:38 +02:00
$this -> so -> recurrence ( $event [ 'id' ], $start , $end , $event [ 'participants' ], $is_exception );
2005-11-09 00:15:14 +01:00
}
}
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
/**
2010-11-04 14:30:11 +01:00
* Convert data read from the db , eg . convert server to user - time
*
* Also make sure all timestamps comming from DB as string are converted to integer ,
2016-05-01 19:47:59 +02:00
* to avoid misinterpretation by Api\DateTime as Ymd string .
2005-11-09 00:15:14 +01:00
*
* @ param array & $events array of event - arrays ( reference )
2015-07-16 14:10:48 +02:00
* @ param $date_format = 'ts' date - formats : 'ts' = timestamp , 'server' = timestamp in server - time , 'array' = array or string with date - format
2005-11-09 00:15:14 +01:00
*/
function db2data ( & $events , $date_format = 'ts' )
{
2010-11-28 12:01:44 +01:00
if ( ! is_array ( $events )) echo " <p>calendar_bo::db2data( \$ events, $date_format ) \$ events is no array<br /> \n " . function_backtrace () . " </p> \n " ;
2010-04-23 15:52:45 +02:00
foreach ( $events as & $event )
2005-11-09 00:15:14 +01:00
{
2009-11-04 16:00:08 +01:00
// convert timezone id of event to tzid (iCal id like 'Europe/Berlin')
2012-03-22 15:02:06 +01:00
if ( empty ( $event [ 'tzid' ]) && ( ! $event [ 'tz_id' ] || ! ( $event [ 'tzid' ] = calendar_timezones :: id2tz ( $event [ 'tz_id' ]))))
2009-11-04 16:00:08 +01:00
{
2016-05-01 19:47:59 +02:00
$event [ 'tzid' ] = Api\DateTime :: $server_timezone -> getName ();
2009-11-04 16:00:08 +01:00
}
2010-11-04 14:30:11 +01:00
// database returns timestamps as string, convert them to integer
2016-05-01 19:47:59 +02:00
// to avoid misinterpretation by Api\DateTime as Ymd string
2010-11-04 14:30:11 +01:00
// (this will fail on 32bit systems for times > 2038!)
2016-05-01 19:47:59 +02:00
$event [ 'start' ] = ( int ) $event [ 'start' ]; // this is for isWholeDay(), which also calls Api\DateTime
2010-11-04 14:30:11 +01:00
$event [ 'end' ] = ( int ) $event [ 'end' ];
2010-12-21 03:45:40 +01:00
$event [ 'whole_day' ] = self :: isWholeDay ( $event );
2010-04-23 15:52:45 +02:00
if ( $event [ 'whole_day' ] && $date_format != 'server' )
2010-04-23 08:15:18 +02:00
{
// Adjust dates to user TZ
2016-05-01 19:47:59 +02:00
$stime =& $this -> so -> startOfDay ( new Api\DateTime (( int ) $event [ 'start' ], Api\DateTime :: $server_timezone ), $event [ 'tzid' ]);
$event [ 'start' ] = Api\DateTime :: to ( $stime , $date_format );
$time =& $this -> so -> startOfDay ( new Api\DateTime (( int ) $event [ 'end' ], Api\DateTime :: $server_timezone ), $event [ 'tzid' ]);
2010-04-23 08:15:18 +02:00
$time -> setTime ( 23 , 59 , 59 );
2016-05-01 19:47:59 +02:00
$event [ 'end' ] = Api\DateTime :: to ( $time , $date_format );
2010-05-06 21:16:43 +02:00
if ( ! empty ( $event [ 'recurrence' ]))
{
2016-05-01 19:47:59 +02:00
$time =& $this -> so -> startOfDay ( new Api\DateTime (( int ) $event [ 'recurrence' ], Api\DateTime :: $server_timezone ), $event [ 'tzid' ]);
$event [ 'recurrence' ] = Api\DateTime :: to ( $time , $date_format );
2010-05-06 21:16:43 +02:00
}
2010-05-03 18:43:42 +02:00
if ( ! empty ( $event [ 'recur_enddate' ]))
{
2016-05-01 19:47:59 +02:00
$time =& $this -> so -> startOfDay ( new Api\DateTime (( int ) $event [ 'recur_enddate' ], Api\DateTime :: $server_timezone ), $event [ 'tzid' ]);
2010-05-03 18:43:42 +02:00
$time -> setTime ( 23 , 59 , 59 );
2016-05-01 19:47:59 +02:00
$event [ 'recur_enddate' ] = Api\DateTime :: to ( $time , $date_format );
2010-05-03 18:43:42 +02:00
}
2017-01-18 18:29:44 +01:00
$timestamps = array ( 'modified' , 'created' , 'deleted' );
2010-04-23 08:15:18 +02:00
}
else
{
2017-01-18 18:29:44 +01:00
$timestamps = array ( 'start' , 'end' , 'modified' , 'created' , 'recur_enddate' , 'recurrence' , 'recur_date' , 'deleted' );
2010-04-23 08:15:18 +02:00
}
2005-11-09 00:15:14 +01:00
// we convert here from the server-time timestamps to user-time and (optional) to a different date-format!
2010-04-23 08:15:18 +02:00
foreach ( $timestamps as $ts )
2004-08-01 17:36:04 +02:00
{
2010-04-23 08:15:18 +02:00
if ( ! empty ( $event [ $ts ]))
{
2010-11-04 14:30:11 +01:00
$event [ $ts ] = $this -> date2usertime (( int ) $event [ $ts ], $date_format );
2010-04-23 08:15:18 +02:00
}
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
// same with the recur exceptions
if ( isset ( $event [ 'recur_exception' ]) && is_array ( $event [ 'recur_exception' ]))
2004-08-01 17:36:04 +02:00
{
2010-02-22 11:02:33 +01:00
foreach ( $event [ 'recur_exception' ] as & $date )
2004-08-01 17:36:04 +02:00
{
2010-04-23 08:15:18 +02:00
if ( $event [ 'whole_day' ] && $date_format != 'server' )
{
// Adjust dates to user TZ
2016-05-01 19:47:59 +02:00
$time =& $this -> so -> startOfDay ( new Api\DateTime (( int ) $date , Api\DateTime :: $server_timezone ), $event [ 'tzid' ]);
$date = Api\DateTime :: to ( $time , $date_format );
2010-04-23 08:15:18 +02:00
}
else
{
2010-11-04 14:30:11 +01:00
$date = $this -> date2usertime (( int ) $date , $date_format );
2010-04-23 08:15:18 +02:00
}
2004-08-01 17:36:04 +02:00
}
}
2005-11-09 00:15:14 +01:00
// same with the alarms
if ( isset ( $event [ 'alarm' ]) && is_array ( $event [ 'alarm' ]))
2004-08-01 17:36:04 +02:00
{
2010-02-22 11:02:33 +01:00
foreach ( $event [ 'alarm' ] as & $alarm )
2005-11-09 00:15:14 +01:00
{
2010-11-04 14:30:11 +01:00
$alarm [ 'time' ] = $this -> date2usertime (( int ) $alarm [ 'time' ], $date_format );
2005-11-09 00:15:14 +01:00
}
2004-08-01 17:36:04 +02:00
}
}
2005-11-09 00:15:14 +01:00
}
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
/**
* convert a date from server to user - time
*
2009-11-04 22:16:08 +01:00
* @ param int $ts timestamp in server - time
2015-07-16 14:10:48 +02:00
* @ param string $date_format = 'ts' date - formats : 'ts' = timestamp , 'server' = timestamp in server - time , 'array' = array or string with date - format
2009-11-04 16:00:08 +01:00
* @ return mixed depending of $date_format
2005-11-09 00:15:14 +01:00
*/
function date2usertime ( $ts , $date_format = 'ts' )
{
2009-10-07 15:29:06 +02:00
if ( empty ( $ts ) || $date_format == 'server' ) return $ts ;
2008-05-08 17:02:35 +02:00
2016-05-01 19:47:59 +02:00
return Api\DateTime :: server2user ( $ts , $date_format );
2004-08-01 17:36:04 +02:00
}
/**
* Reads a calendar - entry
*
2009-08-04 19:14:16 +02:00
* @ param int | array | string $ids id or array of id ' s of the entries to read , or string with a single uid
2015-07-16 14:10:48 +02:00
* @ param mixed $date = null date to specify a single event of a series
2005-11-09 00:15:14 +01:00
* @ param boolean $ignore_acl should we ignore the acl , default False for a single id , true for multiple id ' s
2015-07-16 14:10:48 +02:00
* @ param string $date_format = 'ts' date - formats : 'ts' = timestamp , 'server' = timestamp in servertime , 'array' = array , or string with date - format
2016-05-01 19:47:59 +02:00
* @ param array | int $clear_private_infos_users = null if not null , return events with self :: ACL_FREEBUSY too ,
2010-12-02 22:50:22 +01:00
* but call clear_private_infos () with the given users
2018-06-27 18:26:42 +02:00
* @ param boolean $read_recurrence = false true : read the exception , not the series master ( only for recur_date && $ids = '<uid>' ! )
2010-02-22 11:02:33 +01:00
* @ return boolean | array event or array of id => event pairs , false if the acl - check went wrong , null if $ids not found
2004-08-01 17:36:04 +02:00
*/
2018-06-27 18:26:42 +02:00
function read ( $ids , $date = null , $ignore_acl = False , $date_format = 'ts' , $clear_private_infos_users = null , $read_recurrence = false )
2004-08-01 17:36:04 +02:00
{
2011-04-08 16:20:01 +02:00
if ( ! $ids ) return false ;
2005-11-09 00:15:14 +01:00
if ( $date ) $date = $this -> date2ts ( $date );
2010-05-20 17:12:59 +02:00
2010-05-18 12:03:21 +02:00
$return = null ;
2004-08-01 17:36:04 +02:00
2016-05-01 19:47:59 +02:00
$check = $clear_private_infos_users ? self :: ACL_FREEBUSY : Acl :: READ ;
2010-12-02 22:50:22 +01:00
if ( $ignore_acl || is_array ( $ids ) || ( $return = $this -> check_perms ( $check , $ids , 0 , $date_format , $date )))
2004-08-01 17:36:04 +02:00
{
2008-05-10 22:10:45 +02:00
if ( is_array ( $ids ) || ! isset ( self :: $cached_event [ 'id' ]) || self :: $cached_event [ 'id' ] != $ids ||
2018-06-27 18:26:42 +02:00
self :: $cached_event_date_format != $date_format || $read_recurrence ||
2024-02-08 10:24:39 +01:00
! empty ( self :: $cached_event [ 'recur_type' ]) && self :: $cached_event_date != $date )
2004-08-01 17:36:04 +02:00
{
2018-06-27 18:26:42 +02:00
$events = $this -> so -> read ( $ids , $date ? $this -> date2ts ( $date , true ) : 0 , $read_recurrence );
2006-12-22 20:51:56 +01:00
2005-11-09 00:15:14 +01:00
if ( $events )
2004-08-01 17:36:04 +02:00
{
2005-11-09 00:15:14 +01:00
$this -> db2data ( $events , $date_format );
2008-05-08 17:02:35 +02:00
2005-11-09 00:15:14 +01:00
if ( is_array ( $ids ))
2004-11-07 15:38:00 +01:00
{
2005-11-09 00:15:14 +01:00
$return =& $events ;
}
else
{
2008-05-10 22:10:45 +02:00
self :: $cached_event = array_shift ( $events );
self :: $cached_event_date_format = $date_format ;
2009-07-15 22:35:56 +02:00
self :: $cached_event_date = $date ;
2010-12-02 22:50:22 +01:00
$return = self :: $cached_event ;
2004-11-07 15:38:00 +01:00
}
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
}
else
{
2010-04-14 10:49:49 +02:00
$return = self :: $cached_event ;
2004-08-01 17:36:04 +02:00
}
}
2016-05-01 19:47:59 +02:00
if ( $clear_private_infos_users && ! is_array ( $ids ) && ! $this -> check_perms ( Acl :: READ , $return ))
2010-12-02 22:50:22 +01:00
{
$this -> clear_private_infos ( $return , ( array ) $clear_private_infos_users );
}
2004-08-01 17:36:04 +02:00
if ( $this -> debug && ( $this -> debug > 1 || $this -> debug == 'read' ))
{
2010-12-02 23:11:05 +01:00
$this -> debug_message ( 'calendar_bo::read(%1,%2,%3,%4,%5)=%6' , True , $ids , $date , $ignore_acl , $date_format , $clear_private_infos_users , $return );
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
return $return ;
2004-08-01 17:36:04 +02:00
}
/**
2023-07-24 17:08:05 +02:00
* Inserts all repetitions of $event in the timespan between $start and $end into $events
2004-08-01 17:36:04 +02:00
*
2009-11-12 11:11:23 +01:00
* The new entries are just appended to $events , so $events is no longer sorted by startdate !!!
2004-08-01 17:36:04 +02:00
*
2009-11-12 11:11:23 +01:00
* Recurrences get calculated by rrule iterator implemented in calendar_rrule class .
2004-08-01 17:36:04 +02:00
*
2009-08-04 19:14:16 +02:00
* @ param array $event repeating event whos repetions should be inserted
* @ param mixed $start start - date
* @ param mixed $end end - date
* @ param array $events where the repetions get inserted
2009-11-12 11:11:23 +01:00
* @ param array $recur_exceptions with date ( in Ymd ) as key ( and True as values ), seems not to be used anymore
2004-08-01 17:36:04 +02:00
*/
2015-07-16 14:10:48 +02:00
function insert_all_recurrences ( $event , $_start , $end , & $events )
2004-08-01 17:36:04 +02:00
{
2009-11-12 11:11:23 +01:00
if (( int ) $this -> debug >= 3 || $this -> debug == 'set_recurrences' || $this -> debug == 'check_move_horizont' || $this -> debug == 'insert_all_recurrences' )
2005-11-09 00:15:14 +01:00
{
2015-07-16 14:10:48 +02:00
$this -> debug_message ( __METHOD__ . '(%1,%2,%3,&$events)' , true , $event , $_start , $end );
2005-11-09 00:15:14 +01:00
}
2015-07-16 14:10:48 +02:00
$end_in = $end ;
2008-05-08 17:02:35 +02:00
2015-07-16 14:10:48 +02:00
$start = $this -> date2ts ( $_start );
2005-11-09 00:15:14 +01:00
$event_start_ts = $this -> date2ts ( $event [ 'start' ]);
2009-11-12 11:11:23 +01:00
$event_length = $this -> date2ts ( $event [ 'end' ]) - $event_start_ts ; // we use a constant event-length, NOT a constant end-time!
2004-08-01 17:36:04 +02:00
2009-11-12 11:11:23 +01:00
// if $end is before recur_enddate, use it instead
if ( ! $event [ 'recur_enddate' ] || $this -> date2ts ( $event [ 'recur_enddate' ]) > $this -> date2ts ( $end ))
2004-08-01 17:36:04 +02:00
{
2016-05-01 19:47:59 +02:00
//echo "<p>recur_enddate={$event['recur_enddate']}=".Api\DateTime::to($event['recur_enddate'])." > end=$end=".Api\DateTime::to($end)." --> using end instead of recur_enddate</p>\n";
2011-06-14 20:33:26 +02:00
// insert at least the event itself, if it's behind the horizont
$event [ 'recur_enddate' ] = $this -> date2ts ( $end ) < $this -> date2ts ( $event [ 'end' ]) ? $event [ 'end' ] : $end ;
2004-08-01 17:36:04 +02:00
}
2017-06-01 19:20:38 +02:00
$event [ 'recur_enddate' ] = is_a ( $event [ 'recur_enddate' ], 'DateTime' ) ?
$event [ 'recur_enddate' ] :
new Api\DateTime ( $event [ 'recur_enddate' ], calendar_timezones :: DateTimeZone ( $event [ 'tzid' ]));
2017-10-23 17:56:43 +02:00
2013-08-15 14:23:38 +02:00
// unset exceptions, as we need to add them as recurrence too, but marked as exception
unset ( $event [ 'recur_exception' ]);
2009-11-12 11:11:23 +01:00
// loop over all recurrences and insert them, if they are after $start
2022-06-07 22:33:22 +02:00
$rrule = calendar_rrule :: event2rrule ( $event , ! $event [ 'whole_day' ], // true = we operate in usertime, like the rest of calendar_bo
// For whole day events, just stay in server time
$event [ 'whole_day' ] ? Api\DateTime :: $server_timezone -> getName () : Api\DateTime :: $user_timezone -> getName ()
);
2009-11-12 11:11:23 +01:00
foreach ( $rrule as $time )
2004-08-01 17:36:04 +02:00
{
2022-06-07 22:33:22 +02:00
// $time is in timezone of event, convert it to usertime used here
2017-06-07 21:19:20 +02:00
if ( $event [ 'whole_day' ])
{
// All day events are processed in server timezone
$time -> setTime ( 0 , 0 , 0 );
}
2022-06-07 22:33:22 +02:00
else
{
$time -> setUser ();
}
2009-11-12 11:11:23 +01:00
if (( $ts = $this -> date2ts ( $time )) < $start - $event_length )
2005-02-10 01:13:37 +01:00
{
2009-11-12 11:11:23 +01:00
//echo "<p>".$time." --> ignored as $ts < $start-$event_length</p>\n";
continue ; // to early or original event (returned by interator too)
2005-02-10 01:13:37 +01:00
}
2010-02-25 18:05:24 +01:00
$ts_end = $ts + $event_length ;
// adjust ts_end for whole day events in case it does not fit due to
// spans over summer/wintertime adjusted days
if ( $event [ 'whole_day' ] && ( $arr_end = $this -> date2array ( $ts_end )) &&
! ( $arr_end [ 'hour' ] == 23 && $arr_end [ 'minute' ] == 59 && $arr_end [ 'second' ] == 59 ))
{
$arr_end [ 'hour' ] = 23 ;
$arr_end [ 'minute' ] = 59 ;
$arr_end [ 'second' ] = 59 ;
$ts_end_guess = $this -> date2ts ( $arr_end );
if ( $ts_end_guess - $ts_end > DAY_s / 2 )
{
$ts_end = $ts_end_guess - DAY_s ; // $ts_end_guess was one day too far in the future
}
else
{
$ts_end = $ts_end_guess ; // $ts_end_guess was ok
}
}
2010-04-14 10:49:49 +02:00
2009-11-12 11:11:23 +01:00
$event [ 'start' ] = $ts ;
2010-02-25 18:05:24 +01:00
$event [ 'end' ] = $ts_end ;
2009-11-12 11:11:23 +01:00
$events [] = $event ;
}
if ( $this -> debug && (( int ) $this -> debug > 2 || $this -> debug == 'set_recurrences' || $this -> debug == 'check_move_horizont' || $this -> debug == 'insert_all_recurrences' ))
2004-08-01 17:36:04 +02:00
{
2009-11-12 11:11:23 +01:00
$event [ 'start' ] = $event_start_ts ;
$event [ 'end' ] = $event_start_ts + $event_length ;
2015-07-16 14:10:48 +02:00
$this -> debug_message ( __METHOD__ . '(%1,start=%2,end=%3,events) events=%5' , True , $event , $_start , $end_in , $events );
2004-08-01 17:36:04 +02:00
}
}
/**
* Adds one repetion of $event for $date_ymd to the $events array , after adjusting its start - and end - time
*
2009-08-04 19:14:16 +02:00
* @ param array $events array in which the event gets inserted
* @ param array $event event to insert , it has start - and end - date of the first recurrence , not of $date_ymd
* @ param int | string $date_ymd of the date of the event
2004-08-01 17:36:04 +02:00
*/
function add_adjusted_event ( & $events , $event , $date_ymd )
{
$event_in = $event ;
// calculate the new start- and end-time
2005-11-09 00:15:14 +01:00
$length_s = $this -> date2ts ( $event [ 'end' ]) - $this -> date2ts ( $event [ 'start' ]);
$event_start_arr = $this -> date2array ( $event [ 'start' ]);
2004-08-01 17:36:04 +02:00
$date_arr = $this -> date2array (( string ) $date_ymd );
2005-11-09 00:15:14 +01:00
$date_arr [ 'hour' ] = $event_start_arr [ 'hour' ];
$date_arr [ 'minute' ] = $event_start_arr [ 'minute' ];
$date_arr [ 'second' ] = $event_start_arr [ 'second' ];
2004-08-01 17:36:04 +02:00
unset ( $date_arr [ 'raw' ]); // else date2ts would use it
2005-11-09 00:15:14 +01:00
$event [ 'start' ] = $this -> date2ts ( $date_arr );
$event [ 'end' ] = $event [ 'start' ] + $length_s ;
2004-08-01 17:36:04 +02:00
$events [] = $event ;
if ( $this -> debug && ( $this -> debug > 2 || $this -> debug == 'add_adjust_event' ))
{
2010-11-28 12:01:44 +01:00
$this -> debug_message ( 'calendar_bo::add_adjust_event(,%1,%2) as %3' , True , $event_in , $date_ymd , $event );
2004-08-01 17:36:04 +02:00
}
}
2006-03-05 11:26:03 +01:00
/**
* Fetch information about a resource
*
* We do some caching here , as the resource itself might not do it .
*
* @ param string $uid string with one - letter resource - type and numerical resource - id , eg . " r19 "
2009-08-04 19:14:16 +02:00
* @ return array | boolean array with keys res_id , cat_id , name , useable ( name definied by max_quantity in $this -> resources ), rights , responsible or false if $uid is not found
2006-03-05 11:26:03 +01:00
*/
function resource_info ( $uid )
{
static $res_info_cache = array ();
2008-05-08 17:02:35 +02:00
2016-05-01 19:47:59 +02:00
if ( ! is_scalar ( $uid )) throw new Api\Exception\WrongParameter ( __METHOD__ . '(' . array2string ( $uid ) . ') parameter must be scalar' );
2011-03-28 14:04:34 +02:00
2006-03-05 11:26:03 +01:00
if ( ! isset ( $res_info_cache [ $uid ]))
{
2008-05-08 17:02:35 +02:00
if ( is_numeric ( $uid ))
{
2009-07-15 22:35:56 +02:00
$info = array (
2009-07-08 12:29:06 +02:00
'res_id' => $uid ,
'email' => $GLOBALS [ 'egw' ] -> accounts -> id2name ( $uid , 'account_email' ),
'name' => trim ( $GLOBALS [ 'egw' ] -> accounts -> id2name ( $uid , 'account_firstname' ) . ' ' .
$GLOBALS [ 'egw' ] -> accounts -> id2name ( $uid , 'account_lastname' )),
'type' => $GLOBALS [ 'egw' ] -> accounts -> get_type ( $uid ),
2011-10-17 17:44:26 +02:00
'app' => 'accounts' ,
2008-05-08 17:02:35 +02:00
);
}
else
{
list ( $info ) = $this -> resources [ $uid [ 0 ]][ 'info' ] ? ExecMethod ( $this -> resources [ $uid [ 0 ]][ 'info' ], substr ( $uid , 1 )) : false ;
if ( $info )
{
$info [ 'type' ] = $uid [ 0 ];
2024-02-06 20:46:43 +01:00
if ( empty ( $info [ 'email' ]) && $info [ 'responsible' ])
2008-05-08 17:02:35 +02:00
{
$info [ 'email' ] = $GLOBALS [ 'egw' ] -> accounts -> id2name ( $info [ 'responsible' ], 'account_email' );
}
2011-10-17 17:44:26 +02:00
$info [ 'app' ] = $this -> resources [ $uid [ 0 ]][ 'app' ];
2008-05-08 17:02:35 +02:00
}
}
$res_info_cache [ $uid ] = $info ;
2006-03-05 11:26:03 +01:00
}
if ( $this -> debug && ( $this -> debug > 2 || $this -> debug == 'resource_info' ))
{
2010-11-28 12:01:44 +01:00
$this -> debug_message ( 'calendar_bo::resource_info(%1) = %2' , True , $uid , $res_info_cache [ $uid ]);
2006-03-05 11:26:03 +01:00
}
return $res_info_cache [ $uid ];
}
2004-08-01 17:36:04 +02:00
/**
* Checks if the current user has the necessary ACL rights
*
* The check is performed on an event or generally on the cal of an other user
*
* Note : Participating in an event is considered as haveing read - access on that event ,
* even if you have no general read - grant from that user .
*
2016-05-01 19:47:59 +02:00
* @ param int $needed necessary ACL right : Acl :: { READ | EDIT | DELETE }
2005-11-09 00:15:14 +01:00
* @ param mixed $event event as array or the event - id or 0 for a general check
* @ param int $other uid to check ( if event == 0 ) or 0 to check against $this -> user
2015-07-16 14:10:48 +02:00
* @ param string $date_format = 'ts' date - format used for reading : 'ts' = timestamp , 'array' = array , 'string' = iso8601 string for xmlrpc
* @ param mixed $date_to_read = null date used for reading , internal param for the caching
* @ param int $user = null for which user to check , default current user
2006-06-24 18:04:06 +02:00
* @ return boolean true permission granted , false for permission denied or null if event not found
2004-08-01 17:36:04 +02:00
*/
2011-06-26 17:41:21 +02:00
function check_perms ( $needed , $event = 0 , $other = 0 , $date_format = 'ts' , $date_to_read = null , $user = null )
2004-08-01 17:36:04 +02:00
{
2011-06-26 17:41:21 +02:00
if ( ! $user ) $user = $this -> user ;
if ( $user == $this -> user )
{
$grants = $this -> grants ;
}
else
{
$grants = $GLOBALS [ 'egw' ] -> acl -> get_grants ( 'calendar' , true , $user );
}
2005-11-09 00:15:14 +01:00
if ( $other && ! is_numeric ( $other ))
{
2006-03-05 11:26:03 +01:00
$resource = $this -> resource_info ( $other );
return $needed & $resource [ 'rights' ];
2005-11-09 00:15:14 +01:00
}
2004-08-01 17:36:04 +02:00
if ( is_int ( $event ) && $event == 0 )
{
2011-06-26 17:41:21 +02:00
$owner = $other ? $other : $user ;
2004-08-01 17:36:04 +02:00
}
else
{
if ( ! is_array ( $event ))
{
2010-05-18 12:03:21 +02:00
$event = $this -> read ( $event , $date_to_read , true , $date_format ); // = no ACL check !!!
2004-08-01 17:36:04 +02:00
}
if ( ! is_array ( $event ))
{
2023-06-09 18:27:28 +02:00
if ( ! empty ( $this -> xmlrpc ))
2004-08-01 17:36:04 +02:00
{
$GLOBALS [ 'server' ] -> xmlrpc_error ( $GLOBALS [ 'xmlrpcerr' ][ 'not_exist' ], $GLOBALS [ 'xmlrpcstr' ][ 'not_exist' ]);
}
2006-06-24 18:04:06 +02:00
return null ; // event not found
2004-08-01 17:36:04 +02:00
}
$owner = $event [ 'owner' ];
$private = ! $event [ 'public' ];
}
2024-02-08 10:24:39 +01:00
$grant = $grants [ $owner ] ? ? null ;
2010-11-04 14:30:11 +01:00
2011-01-04 20:27:17 +01:00
// now any ACL rights (but invite rights!) implicate FREEBUSY rights (at least READ has to include FREEBUSY)
2016-05-01 19:47:59 +02:00
if ( $grant & ~ self :: ACL_INVITE ) $grant |= self :: ACL_FREEBUSY ;
2010-11-04 14:30:11 +01:00
2016-05-01 19:47:59 +02:00
if ( is_array ( $event ) && ( $needed == Acl :: READ || $needed == self :: ACL_FREEBUSY ))
2004-08-01 17:36:04 +02:00
{
// Check if the $user is one of the participants or has a read-grant from one of them
2004-09-08 14:20:56 +02:00
// in that case he has an implicite READ grant for that event
2004-08-01 17:36:04 +02:00
//
2008-12-11 14:44:47 +01:00
if ( $event [ 'participants' ] && is_array ( $event [ 'participants' ]))
2004-08-01 17:36:04 +02:00
{
2015-07-16 14:10:48 +02:00
foreach ( array_keys ( $event [ 'participants' ]) as $uid )
2004-08-01 17:36:04 +02:00
{
2012-08-09 10:41:29 +02:00
if ( $uid == $user || $uid < 0 && in_array ( $user , ( array ) $GLOBALS [ 'egw' ] -> accounts -> members ( $uid , true )))
2008-12-11 14:44:47 +01:00
{
2011-06-26 17:46:30 +02:00
// if we are a participant, we have an implicite FREEBUSY, READ and PRIVAT grant
2016-05-01 19:47:59 +02:00
$grant |= self :: ACL_FREEBUSY | Acl :: READ | Acl :: PRIVAT ;
2008-12-11 14:44:47 +01:00
break ;
}
2024-02-06 20:46:43 +01:00
elseif ( isset ( $grants [ $uid ]) && ( $grants [ $uid ] & Acl :: READ ))
2008-12-11 14:44:47 +01:00
{
// if we have a READ grant from a participant, we dont give an implicit privat grant too
2020-03-04 20:17:34 +01:00
$grant |= self :: ACL_FREEBUSY | Acl :: READ ;
2008-12-11 14:44:47 +01:00
// we cant break here, as we might be a participant too, and would miss the privat grant
}
elseif ( ! is_numeric ( $uid ))
{
2016-05-01 19:47:59 +02:00
// if the owner only grants self::ACL_FREEBUSY we are not interested in the recources explicit rights
if ( $grant == self :: ACL_FREEBUSY ) continue ;
2008-12-11 14:44:47 +01:00
// if we have a resource as participant
$resource = $this -> resource_info ( $uid );
2011-06-26 17:41:21 +02:00
$grant |= $resource [ 'rights' ];
2008-12-11 14:44:47 +01:00
}
2008-05-08 17:02:35 +02:00
}
2004-08-01 17:36:04 +02:00
}
}
2016-05-01 19:47:59 +02:00
if ( $GLOBALS [ 'egw' ] -> accounts -> get_type ( $owner ) == 'g' && $needed == Acl :: ADD )
2004-08-01 17:36:04 +02:00
{
$access = False ; // a group can't be the owner of an event
}
else
{
2011-06-26 17:41:21 +02:00
$access = $user == $owner || $grant & $needed
2024-02-06 20:46:43 +01:00
&& ( $needed == self :: ACL_FREEBUSY || empty ( $private ) || $grant & Acl :: PRIVAT );
2004-08-01 17:36:04 +02:00
}
2012-05-15 12:35:40 +02:00
// do NOT allow users to purge deleted events, if we dont have 'userpurge' enabled
2016-05-01 19:47:59 +02:00
if ( $access && $needed == Acl :: DELETE && $event [ 'deleted' ] &&
2013-01-22 16:54:23 +01:00
! $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ] &&
2012-05-15 12:35:40 +02:00
$GLOBALS [ 'egw_info' ][ 'server' ][ 'calendar_delete_history' ] != 'userpurge' )
2011-04-27 18:28:38 +02:00
{
$access = false ;
}
2004-08-01 17:36:04 +02:00
if ( $this -> debug && ( $this -> debug > 2 || $this -> debug == 'check_perms' ))
{
2011-06-26 17:41:21 +02:00
$this -> debug_message ( 'calendar_bo::check_perms(%1,%2,other=%3,%4,%5,user=%6)=%7' , True , ACL_TYPE_IDENTIFER . $needed , $event , $other , $date_format , $date_to_read , $user , $access );
2004-08-01 17:36:04 +02:00
}
2011-06-26 17:41:21 +02:00
//error_log(__METHOD__."($needed,".array2string($event).",$other,...,$user) returning ".array2string($access));
2004-08-01 17:36:04 +02:00
return $access ;
}
/**
2010-02-25 18:05:24 +01:00
* Converts several date - types to a timestamp and optionally converts user - to server - time
2004-08-01 17:36:04 +02:00
*
2009-08-04 19:14:16 +02:00
* @ param mixed $date date to convert , should be one of the following types
2005-11-09 00:15:14 +01:00
* string ( ! ) in form YYYYMMDD or iso8601 YYYY - MM - DDThh : mm : ss or YYYYMMDDThhmmss
2004-08-01 17:36:04 +02:00
* int already a timestamp
* array with keys 'second' , 'minute' , 'hour' , 'day' or 'mday' ( depricated ! ), 'month' and 'year'
2015-07-16 14:10:48 +02:00
* @ param boolean $user2server = False conversion between user - and server - time ; default False == Off
2004-08-01 17:36:04 +02:00
*/
2009-10-07 15:29:06 +02:00
static function date2ts ( $date , $user2server = False )
2004-08-01 17:36:04 +02:00
{
2016-05-01 19:47:59 +02:00
return $user2server ? Api\DateTime :: user2server ( $date , 'ts' ) : Api\DateTime :: to ( $date , 'ts' );
2004-08-01 17:36:04 +02:00
}
/**
2010-02-25 18:05:24 +01:00
* Converts a date to an array and optionally converts server - to user - time
2004-08-01 17:36:04 +02:00
*
2009-08-04 19:14:16 +02:00
* @ param mixed $date date to convert
2015-07-16 14:10:48 +02:00
* @ param boolean $server2user conversation between user - and server - time default False == Off
2004-10-08 00:11:18 +02:00
* @ return array with keys 'second' , 'minute' , 'hour' , 'day' , 'month' , 'year' , 'raw' ( timestamp ) and 'full' ( Ymd - string )
2004-08-01 17:36:04 +02:00
*/
2009-10-07 15:29:06 +02:00
static function date2array ( $date , $server2user = False )
2004-08-01 17:36:04 +02:00
{
2016-05-01 19:47:59 +02:00
return $server2user ? Api\DateTime :: server2user ( $date , 'array' ) : Api\DateTime :: to ( $date , 'array' );
2004-08-01 17:36:04 +02:00
}
/**
* Converts a date as timestamp or array to a date - string and optionaly converts server - to user - time
*
2005-11-09 00:15:14 +01:00
* @ param mixed $date integer timestamp or array with ( 'year' , 'month' , .. , 'second' ) to convert
2015-07-16 14:10:48 +02:00
* @ param boolean $server2user conversation between user - and server - time default False == Off , not used if $format ends with \Z
* @ param string $format = 'Ymd' format of the date to return , eg . 'Y-m-d\TH:i:sO' ( 2005 - 11 - 01 T15 : 30 : 00 + 0100 )
2005-11-09 00:15:14 +01:00
* @ return string date formatted according to $format
2004-08-01 17:36:04 +02:00
*/
2009-10-07 15:29:06 +02:00
static function date2string ( $date , $server2user = False , $format = 'Ymd' )
2004-08-01 17:36:04 +02:00
{
2016-05-01 19:47:59 +02:00
return $server2user ? Api\DateTime :: server2user ( $date , $format ) : Api\DateTime :: to ( $date , $format );
2004-08-01 17:36:04 +02:00
}
2005-11-09 00:15:14 +01:00
/**
* Formats a date given as timestamp or array
*
* @ param mixed $date integer timestamp or array with ( 'year' , 'month' , .. , 'second' ) to convert
2015-07-16 14:10:48 +02:00
* @ param string | boolean $format = '' default common_prefs [ dateformat ], common_prefs [ timeformat ], false = time only , true = date only
2005-11-09 00:15:14 +01:00
* @ return string the formated date ( incl . time )
*/
2009-10-07 15:29:06 +02:00
static function format_date ( $date , $format = '' )
2005-11-09 00:15:14 +01:00
{
2016-05-01 19:47:59 +02:00
return Api\DateTime :: to ( $date , $format );
2005-11-09 00:15:14 +01:00
}
2004-08-01 17:36:04 +02:00
/**
* Gives out a debug - message with certain parameters
*
* All permanent debug - messages in the calendar should be done by this function !!!
* ( In future they may be logged or sent as xmlrpc - faults back . )
*
* Permanent debug - message need to make sure NOT to give secret information like passwords !!!
*
* This function do NOT honor the setting of the debug variable , you may use it like
* if ( $this -> debug > N ) $this -> debug_message ( 'Error ;-)' );
*
* The parameters get formated depending on their type . ACL - values need a ACL_TYPE_IDENTIFER prefix .
*
2009-08-04 19:14:16 +02:00
* @ param string $msg message with parameters / variables like lang (), eg . '%1'
2015-07-16 14:10:48 +02:00
* @ param boolean $backtrace = True include a function - backtrace , default True = On
2004-08-01 17:36:04 +02:00
* should only be set to False = Off , if your code ensures a call with backtrace = On was made before !!!
2009-08-04 19:14:16 +02:00
* @ param mixed $param a variable number of parameters , to be inserted in $msg
2004-08-01 17:36:04 +02:00
* arrays get serialized with print_r () !
*/
2009-12-03 19:20:07 +01:00
static function debug_message ( $msg , $backtrace = True )
2004-08-01 17:36:04 +02:00
{
static $acl2string = array (
2009-07-08 12:22:11 +02:00
0 => 'ACL-UNKNOWN' ,
2016-05-01 19:47:59 +02:00
Acl :: READ => 'ACL_READ' ,
Acl :: ADD => 'ACL_ADD' ,
Acl :: EDIT => 'ACL_EDIT' ,
Acl :: DELETE => 'ACL_DELETE' ,
Acl :: PRIVAT => 'ACL_PRIVATE' ,
self :: ACL_FREEBUSY => 'ACL_FREEBUSY' ,
2004-08-01 17:36:04 +02:00
);
for ( $i = 2 ; $i < func_num_args (); ++ $i )
{
$param = func_get_arg ( $i );
if ( is_null ( $param ))
{
$param = 'NULL' ;
}
else
{
switch ( gettype ( $param ))
{
case 'string' :
if ( substr ( $param , 0 , strlen ( ACL_TYPE_IDENTIFER )) == ACL_TYPE_IDENTIFER )
{
$param = ( int ) substr ( $param , strlen ( ACL_TYPE_IDENTIFER ));
2006-12-22 20:51:56 +01:00
$param = ( isset ( $acl2string [ $param ]) ? $acl2string [ $param ] : $acl2string [ 0 ]) . " ( $param ) " ;
2004-08-01 17:36:04 +02:00
}
else
{
$param = " ' $param ' " ;
}
break ;
2016-07-06 12:45:22 +02:00
case 'EGroupware\\Api\\DateTime' :
2009-11-12 11:11:23 +01:00
case 'egw_time' :
case 'datetime' :
$p = $param ;
unset ( $param );
$param = $p -> format ( 'l, Y-m-d H:i:s' ) . ' (' . $p -> getTimeZone () -> getName () . ')' ;
break ;
2004-08-01 17:36:04 +02:00
case 'array' :
case 'object' :
2015-07-16 14:10:48 +02:00
$param = array2string ( $param );
2004-08-01 17:36:04 +02:00
break ;
case 'boolean' :
$param = $param ? 'True' : 'False' ;
break ;
2004-12-12 13:24:24 +01:00
case 'integer' :
2005-11-09 00:15:14 +01:00
if ( $param >= mktime ( 0 , 0 , 0 , 1 , 1 , 2000 )) $param = adodb_date ( 'Y-m-d H:i:s' , $param ) . " ( $param ) " ;
2004-12-12 13:24:24 +01:00
break ;
2004-08-01 17:36:04 +02:00
}
}
$msg = str_replace ( '%' . ( $i - 1 ), $param , $msg );
}
2016-07-06 12:45:22 +02:00
error_log ( $msg );
2010-11-28 12:01:44 +01:00
if ( $backtrace ) error_log ( function_backtrace ( 1 ));
2004-08-01 17:36:04 +02:00
}
/**
2005-11-09 00:15:14 +01:00
* Formats one or two dates ( range ) as long date ( full monthname ), optionaly with a time
2004-08-01 17:36:04 +02:00
*
2015-07-16 14:10:48 +02:00
* @ param mixed $_first first date
* @ param mixed $last = 0 last date if != 0 ( default )
* @ param boolean $display_time = false should a time be displayed too
* @ param boolean $display_day = false should a day - name prefix the date , eg . monday June 20 , 2006
2004-08-01 17:36:04 +02:00
* @ return string with formated date
*/
2015-07-16 14:10:48 +02:00
function long_date ( $_first , $last = 0 , $display_time = false , $display_day = false )
2004-08-01 17:36:04 +02:00
{
2015-07-16 14:10:48 +02:00
$first = $this -> date2array ( $_first );
2004-08-01 17:36:04 +02:00
if ( $last )
{
$last = $this -> date2array ( $last );
}
$datefmt = $this -> common_prefs [ 'dateformat' ];
2005-11-09 00:15:14 +01:00
$timefmt = $this -> common_prefs [ 'timeformat' ] == 12 ? 'h:i a' : 'H:i' ;
2004-08-01 17:36:04 +02:00
$month_before_day = strtolower ( $datefmt [ 0 ]) == 'm' ||
2009-07-08 12:29:06 +02:00
strtolower ( $datefmt [ 2 ]) == 'm' && $datefmt [ 4 ] == 'd' ;
2004-08-01 17:36:04 +02:00
2006-06-20 21:55:06 +02:00
if ( $display_day )
{
2008-05-08 17:02:35 +02:00
$range = lang ( adodb_date ( 'l' , $first [ 'raw' ])) . ( $this -> common_prefs [ 'dateformat' ][ 0 ] != 'd' ? ' ' : ', ' );
2006-06-20 21:55:06 +02:00
}
2004-08-01 17:36:04 +02:00
for ( $i = 0 ; $i < 5 ; $i += 2 )
{
switch ( $datefmt [ $i ])
{
case 'd' :
$range .= $first [ 'day' ] . ( $datefmt [ 1 ] == '.' ? '.' : '' );
if ( $first [ 'month' ] != $last [ 'month' ] || $first [ 'year' ] != $last [ 'year' ])
{
if ( ! $month_before_day )
{
$range .= ' ' . lang ( strftime ( '%B' , $first [ 'raw' ]));
}
if ( $first [ 'year' ] != $last [ 'year' ] && $datefmt [ 0 ] != 'Y' )
{
$range .= ( $datefmt [ 0 ] != 'd' ? ', ' : ' ' ) . $first [ 'year' ];
}
2005-11-09 00:15:14 +01:00
if ( $display_time )
{
$range .= ' ' . adodb_date ( $timefmt , $first [ 'raw' ]);
}
2004-08-01 17:36:04 +02:00
if ( ! $last )
{
return $range ;
}
$range .= ' - ' ;
if ( $first [ 'year' ] != $last [ 'year' ] && $datefmt [ 0 ] == 'Y' )
{
$range .= $last [ 'year' ] . ', ' ;
}
if ( $month_before_day )
{
$range .= lang ( strftime ( '%B' , $last [ 'raw' ]));
}
}
else
{
2005-11-09 00:15:14 +01:00
if ( $display_time )
{
$range .= ' ' . adodb_date ( $timefmt , $first [ 'raw' ]);
}
2004-08-01 17:36:04 +02:00
$range .= ' - ' ;
}
$range .= ' ' . $last [ 'day' ] . ( $datefmt [ 1 ] == '.' ? '.' : '' );
break ;
case 'm' :
case 'M' :
$range .= ' ' . lang ( strftime ( '%B' , $month_before_day ? $first [ 'raw' ] : $last [ 'raw' ])) . ' ' ;
break ;
case 'Y' :
2006-06-20 21:55:06 +02:00
if ( $datefmt [ 0 ] != 'm' )
{
$range .= ' ' . ( $datefmt [ 0 ] == 'Y' ? $first [ 'year' ] . ( $datefmt [ 2 ] == 'd' ? ', ' : ' ' ) : $last [ 'year' ] . ' ' );
}
2004-08-01 17:36:04 +02:00
break ;
}
}
2005-11-09 00:15:14 +01:00
if ( $display_time && $last )
{
$range .= ' ' . adodb_date ( $timefmt , $last [ 'raw' ]);
}
2006-06-20 21:55:06 +02:00
if ( $datefmt [ 4 ] == 'Y' && $datefmt [ 0 ] == 'm' )
{
$range .= ', ' . $last [ 'year' ];
}
2004-08-01 17:36:04 +02:00
return $range ;
}
2008-05-08 17:02:35 +02:00
2006-06-20 21:55:06 +02:00
/**
* Displays a timespan , eg . $both ? " 10:00 - 13:00: 3h " ( 10 : 00 am - 1 pm : 3 h ) : " 10:00 3h " ( 10 : 00 am 3 h )
*
* @ param int $start_m start time in minutes since 0 h
* @ param int $end_m end time in minutes since 0 h
2015-07-16 14:10:48 +02:00
* @ param boolean $both = false display the end - time too , duration is always displayed
2006-06-20 21:55:06 +02:00
*/
function timespan ( $start_m , $end_m , $both = false )
{
$duration = $end_m - $start_m ;
if ( $end_m == 24 * 60 - 1 ) ++ $duration ;
$duration = floor ( $duration / 60 ) . lang ( 'h' ) . ( $duration % 60 ? $duration % 60 : '' );
2016-05-04 21:07:54 +02:00
$timespan = $t = Api\DateTime :: to ( '20000101T' . sprintf ( '%02d' , $start_m / 60 ) . sprintf ( '%02d' , $start_m % 60 ) . '00' , false );
2008-05-08 17:02:35 +02:00
2006-06-20 21:55:06 +02:00
if ( $both ) // end-time too
{
2016-05-04 21:07:54 +02:00
$timespan .= ' - ' . Api\DateTime :: to ( '20000101T' . sprintf ( '%02d' , $end_m / 60 ) . sprintf ( '%02d' , $end_m % 60 ) . '00' , false );
2006-06-20 21:55:06 +02:00
// dont double am/pm if they are the same in both times
if ( $this -> common_prefs [ 'timeformat' ] == 12 && substr ( $timespan , - 2 ) == substr ( $t , - 2 ))
{
$timespan = str_replace ( $t , substr ( $t , 0 , - 3 ), $timespan );
}
$timespan .= ':' ;
}
return $timespan . ' ' . $duration ;
}
2004-08-01 17:36:04 +02:00
2005-11-09 00:15:14 +01:00
/**
* Converts a participant into a ( readable ) user - or resource - name
*
2009-08-04 19:14:16 +02:00
* @ param string | int $id id of user or resource
2015-07-16 14:10:48 +02:00
* @ param string | boolean $use_type = false type - letter or false
* @ param boolean $append_email = false append email ( Name < email > )
2005-11-09 00:15:14 +01:00
* @ return string with name
*/
2011-05-27 22:32:46 +02:00
function participant_name ( $id , $use_type = false , $append_email = false )
2005-11-09 00:15:14 +01:00
{
static $id2lid = array ();
2011-05-27 22:32:46 +02:00
static $id2email = array ();
2008-05-08 17:02:35 +02:00
2006-03-05 11:26:03 +01:00
if ( $use_type && $use_type != 'u' ) $id = $use_type . $id ;
2005-11-09 00:15:14 +01:00
if ( ! isset ( $id2lid [ $id ]))
{
2006-03-05 11:26:03 +01:00
if ( ! is_numeric ( $id ))
2005-11-09 00:15:14 +01:00
{
2008-05-08 17:02:35 +02:00
$id2lid [ $id ] = '#' . $id ;
if (( $info = $this -> resource_info ( $id )))
{
$id2lid [ $id ] = $info [ 'name' ] ? $info [ 'name' ] : $info [ 'email' ];
2011-05-27 22:32:46 +02:00
if ( $info [ 'name' ]) $id2email [ $id ] = $info [ 'email' ];
2008-05-08 17:02:35 +02:00
}
2005-11-09 00:15:14 +01:00
}
else
{
2016-05-01 19:47:59 +02:00
$id2lid [ $id ] = Api\Accounts :: username ( $id );
2011-05-27 22:32:46 +02:00
$id2email [ $id ] = $GLOBALS [ 'egw' ] -> accounts -> id2name ( $id , 'account_email' );
2005-11-09 00:15:14 +01:00
}
}
2023-06-09 18:27:28 +02:00
return $id2lid [ $id ] . (( $append_email || is_string ( $id ) && $id [ 0 ] == 'e' ) && ! empty ( $id2email [ $id ]) ? ' <' . $id2email [ $id ] . '>' : '' );
2005-11-09 00:15:14 +01:00
}
2004-08-01 17:36:04 +02:00
/**
* Converts participants array of an event into array of ( readable ) participant - names with status
*
2005-11-23 15:21:20 +01:00
* @ param array $event event - data
2015-07-16 14:10:48 +02:00
* @ param boolean $long_status = false should the long / verbose status or an icon be use
* @ param boolean $show_group_invitation = false show group - invitations ( status == 'G' ) or not ( default )
2004-08-01 17:36:04 +02:00
* @ return array with id / names with status pairs
*/
2006-12-13 08:28:20 +01:00
function participants ( $event , $long_status = false , $show_group_invitation = false )
2004-08-01 17:36:04 +02:00
{
2014-03-20 17:10:52 +01:00
//error_log(__METHOD__.__LINE__.array2string($event['participants']));
2006-12-13 08:28:20 +01:00
$names = array ();
2011-09-13 11:05:33 +02:00
foreach (( array ) $event [ 'participants' ] as $id => $status )
2004-08-01 17:36:04 +02:00
{
2014-03-20 17:10:52 +01:00
if ( ! is_string ( $status )) continue ;
2015-07-16 14:10:48 +02:00
$quantity = $role = null ;
2009-08-06 13:29:05 +02:00
calendar_so :: split_status ( $status , $quantity , $role );
2009-08-04 19:14:16 +02:00
2006-03-16 19:03:43 +01:00
if ( $status == 'G' && ! $show_group_invitation ) continue ; // dont show group-invitation
2005-11-23 15:21:20 +01:00
2012-05-15 15:23:11 +02:00
$lang_status = lang ( $this -> verbose_status [ $status ]);
2006-12-13 08:28:20 +01:00
if ( ! $long_status )
2006-12-06 14:56:17 +01:00
{
2009-08-04 19:14:16 +02:00
switch ( $status [ 0 ])
2006-12-13 08:28:20 +01:00
{
case 'A' : // accepted
2016-05-01 19:47:59 +02:00
$status = Api\Html :: image ( 'calendar' , 'accepted' , $lang_status );
2009-07-08 12:22:11 +02:00
break ;
2006-12-13 08:28:20 +01:00
case 'R' : // rejected
2016-05-01 19:47:59 +02:00
$status = Api\Html :: image ( 'calendar' , 'rejected' , $lang_status );
2009-07-08 12:22:11 +02:00
break ;
2006-12-13 08:28:20 +01:00
case 'T' : // tentative
2016-05-01 19:47:59 +02:00
$status = Api\Html :: image ( 'calendar' , 'tentative' , $lang_status );
2009-07-08 12:22:11 +02:00
break ;
2006-12-13 08:28:20 +01:00
case 'U' : // no response = unknown
2016-05-01 19:47:59 +02:00
$status = Api\Html :: image ( 'calendar' , 'needs-action' , $lang_status );
2009-07-08 12:22:11 +02:00
break ;
2010-02-17 14:29:28 +01:00
case 'D' : // delegated
2016-05-01 19:47:59 +02:00
$status = Api\Html :: image ( 'calendar' , 'forward' , $lang_status );
2010-02-17 14:29:28 +01:00
break ;
2006-12-13 08:28:20 +01:00
case 'G' : // group invitation
2009-07-08 12:22:11 +02:00
// Todo: Image, seems not to be used
2012-05-15 15:23:11 +02:00
$status = '(' . $lang_status . ')' ;
2009-07-08 12:22:11 +02:00
break ;
2006-12-13 08:28:20 +01:00
}
2006-12-06 14:56:17 +01:00
}
2006-12-13 08:28:20 +01:00
else
2004-08-01 17:36:04 +02:00
{
2012-05-15 15:23:11 +02:00
$status = '(' . $lang_status . ')' ;
2004-08-01 17:36:04 +02:00
}
2016-05-01 19:47:59 +02:00
$names [ $id ] = Api\Html :: htmlspecialchars ( $this -> participant_name ( $id )) . ( $quantity > 1 ? ' (' . $quantity . ')' : '' ) . ' ' . $status ;
2009-08-06 13:29:05 +02:00
// add role, if not a regular participant
if ( $role != 'REQ-PARTICIPANT' )
{
2009-10-12 21:16:42 +02:00
if ( isset ( $this -> roles [ $role ]))
{
2009-10-13 10:58:06 +02:00
$role = lang ( $this -> roles [ $role ]);
2009-10-12 21:16:42 +02:00
}
2009-08-06 13:29:05 +02:00
// allow to use cats as roles (beside regular iCal ones)
2009-10-12 21:16:42 +02:00
elseif ( substr ( $role , 0 , 6 ) == 'X-CAT-' && ( $cat_id = ( int ) substr ( $role , 6 )) > 0 )
2009-08-06 13:29:05 +02:00
{
$role = $GLOBALS [ 'egw' ] -> categories -> id2name ( $cat_id );
}
else
{
$role = lang ( str_replace ( 'X-' , '' , $role ));
}
$names [ $id ] .= ' ' . $role ;
}
2004-08-01 17:36:04 +02:00
}
2012-11-13 12:23:29 +01:00
natcasesort ( $names );
2004-08-01 17:36:04 +02:00
return $names ;
}
/**
* Converts category string of an event into array of ( readable ) category - names
*
2009-08-04 19:14:16 +02:00
* @ param string $category cat - id ( multiple id ' s commaseparated )
* @ param int $color color of the category , if multiple cats , the color of the last one with color is returned
2004-08-01 17:36:04 +02:00
* @ return array with id / names
*/
function categories ( $category , & $color )
{
static $id2cat = array ();
$cats = array ();
$color = 0 ;
2009-12-01 11:24:55 +01:00
2004-08-01 17:36:04 +02:00
foreach ( explode ( ',' , $category ) as $cat_id )
{
if ( ! $cat_id ) continue ;
if ( ! isset ( $id2cat [ $cat_id ]))
{
2016-05-01 19:47:59 +02:00
$id2cat [ $cat_id ] = Api\Categories :: read ( $cat_id );
2004-08-01 17:36:04 +02:00
}
$cat = $id2cat [ $cat_id ];
2015-07-16 14:10:48 +02:00
$parts = null ;
2013-08-15 14:23:38 +02:00
if ( is_array ( $cat [ 'data' ]) && ! empty ( $cat [ 'data' ][ 'color' ]))
{
$color = $cat [ 'data' ][ 'color' ];
}
elseif ( preg_match ( '/(#[0-9A-Fa-f]{6})/' , $cat [ 'description' ], $parts ))
2004-08-01 17:36:04 +02:00
{
2013-08-15 14:23:38 +02:00
$color = $parts [ 1 ];
2004-08-01 17:36:04 +02:00
}
$cats [ $cat_id ] = stripslashes ( $cat [ 'name' ]);
}
return $cats ;
}
2009-05-05 00:39:27 +02:00
/**
* This is called only by list_cals () . It was moved here to remove fatal error in php5 beta4
*/
2014-07-23 14:30:39 +02:00
private static function _list_cals_add ( $id , & $users , & $groups )
2004-08-01 17:36:04 +02:00
{
2016-05-01 19:47:59 +02:00
$name = Api\Accounts :: username ( $id );
2011-03-24 10:26:39 +01:00
if ( ! ( $egw_name = $GLOBALS [ 'egw' ] -> accounts -> id2name ( $id )))
{
return ; // do not return no longer existing accounts which eg. still mentioned in acl
}
2005-11-09 00:15:14 +01:00
if (( $type = $GLOBALS [ 'egw' ] -> accounts -> get_type ( $id )) == 'g' )
2004-08-01 17:36:04 +02:00
{
$arr = & $groups ;
}
else
{
$arr = & $users ;
}
2011-03-24 18:19:31 +01:00
$arr [ $id ] = array (
2009-07-08 12:22:11 +02:00
'grantor' => $id ,
'value' => ( $type == 'g' ? 'g_' : '' ) . $id ,
2010-10-10 00:49:10 +02:00
'name' => $name ,
'sname' => $egw_name
2004-08-01 17:36:04 +02:00
);
}
/**
2009-05-05 00:39:27 +02:00
* generate list of user - / group - calendars for the selectbox in the header
*
2011-03-24 10:26:39 +01:00
* @ return array alphabeticaly sorted array with users first and then groups : array ( 'grantor' => $id , 'value' => [ 'g_' . ] $id , 'name' => $name )
2009-05-05 00:39:27 +02:00
*/
2004-08-01 17:36:04 +02:00
function list_cals ()
{
2014-07-23 14:30:39 +02:00
return self :: list_calendars ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ], $this -> grants );
}
/**
* generate list of user - / group - calendars or a given user
*
* @ param int $user account_id of user to generate list for
2015-07-16 14:10:48 +02:00
* @ param array $grants = null calendar grants from user , or null to query them from acl class
2014-07-23 14:30:39 +02:00
*/
public static function list_calendars ( $user , array $grants = null )
{
if ( is_null ( $grants )) $grants = $GLOBALS [ 'egw' ] -> acl -> get_grants ( 'calendar' , true , $user );
2004-08-01 17:36:04 +02:00
$users = $groups = array ();
2014-07-23 14:30:39 +02:00
foreach ( array_keys ( $grants ) as $id )
2004-08-01 17:36:04 +02:00
{
2014-07-23 14:30:39 +02:00
self :: _list_cals_add ( $id , $users , $groups );
2004-08-01 17:36:04 +02:00
}
2016-03-06 17:09:58 +01:00
if (( $memberships = $GLOBALS [ 'egw' ] -> accounts -> memberships ( $user , true )))
2004-08-01 17:36:04 +02:00
{
2016-03-06 17:09:58 +01:00
foreach ( $memberships as $group )
2004-08-01 17:36:04 +02:00
{
2016-03-06 17:09:58 +01:00
self :: _list_cals_add ( $group , $users , $groups );
2004-08-01 17:36:04 +02:00
2016-05-01 19:47:59 +02:00
if (( $account_perms = $GLOBALS [ 'egw' ] -> acl -> get_ids_for_location ( $group , Acl :: READ , 'calendar' )))
2004-08-01 17:36:04 +02:00
{
foreach ( $account_perms as $id )
{
2014-07-23 14:30:39 +02:00
self :: _list_cals_add ( $id , $users , $groups );
2004-08-01 17:36:04 +02:00
}
}
}
}
2014-07-23 14:30:39 +02:00
usort ( $users , array ( __CLASS__ , 'name_cmp' ));
usort ( $groups , array ( __CLASS__ , 'name_cmp' ));
2004-08-01 17:36:04 +02:00
2011-03-24 10:26:39 +01:00
return array_merge ( $users , $groups ); // users first and then groups, both alphabeticaly
}
/**
* Compare function for sort by value of key 'name'
*
* @ param array $a
* @ param array $b
* @ return int
*/
2014-07-23 14:30:39 +02:00
public static function name_cmp ( array $a , array $b )
2011-03-24 10:26:39 +01:00
{
return strnatcasecmp ( $a [ 'name' ], $b [ 'name' ]);
2004-08-01 17:36:04 +02:00
}
2008-05-08 17:02:35 +02:00
2005-12-02 16:34:45 +01:00
/**
2009-11-12 11:11:23 +01:00
* Convert the recurrence - information of an event , into a human readable string
2005-12-02 16:34:45 +01:00
*
* @ param array $event
2008-05-08 17:02:35 +02:00
* @ return string
2005-12-02 16:34:45 +01:00
*/
function recure2string ( $event )
{
2010-10-04 12:07:52 +02:00
if ( ! is_array ( $event )) return false ;
2009-11-12 11:11:23 +01:00
return ( string ) calendar_rrule :: event2rrule ( $event );
2005-12-02 16:34:45 +01:00
}
2004-08-01 17:36:04 +02:00
/**
* Read the holidays for a given $year
*
2005-11-09 00:15:14 +01:00
* The holidays get cached in the session ( performance ), so changes in holidays or birthdays do NOT affect a current session !!!
*
2015-07-16 14:10:48 +02:00
* @ param int $year = 0 year , defaults to 0 = current year
2004-08-01 17:36:04 +02:00
* @ return array indexed with Ymd of array of holidays . A holiday is an array with the following fields :
* name : string
2016-05-04 19:15:18 +02:00
* title : optional string with description
2004-08-01 17:36:04 +02:00
* day : numerical day in month
* month : numerical month
2005-11-09 00:15:14 +01:00
* occurence : numerical year or 0 for every year
2004-08-01 17:36:04 +02:00
*/
function read_holidays ( $year = 0 )
{
2005-11-09 00:15:14 +01:00
if ( ! $year ) $year = ( int ) date ( 'Y' , $this -> now_su );
2017-04-04 17:36:28 +02:00
$holidays = calendar_holidays :: read (
2016-05-04 19:15:18 +02:00
! empty ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'ical_holiday_url' ]) ?
$GLOBALS [ 'egw_info' ][ 'server' ][ 'ical_holiday_url' ] :
2024-01-18 20:58:56 +01:00
$GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'country' ], $year ,
$GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'lang' ]);
2008-05-08 17:02:35 +02:00
2017-04-04 17:36:28 +02:00
// search for birthdays
if ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'hide_birthdays' ] != 'yes' )
{
$contacts = new Api\Contacts ();
foreach ( $contacts -> get_addressbooks () as $owner => $name )
2005-11-09 00:15:14 +01:00
{
2018-01-12 18:50:10 +01:00
$birthdays = $contacts -> read_birthdays ( $owner , $year );
// Add them in, being careful not to override any existing
foreach ( $birthdays as $date => $bdays )
{
if ( ! array_key_exists ( $date , $holidays ))
{
$holidays [ $date ] = array ();
}
2018-02-16 17:29:26 +01:00
foreach ( $bdays as $birthday )
{
// Skip if name / date are already there - duplicate contacts
if ( in_array ( $birthday [ 'name' ], array_column ( $holidays [ $date ], 'name' ))) continue ;
$holidays [ $date ][] = $birthday ;
}
2018-01-12 18:50:10 +01:00
}
2005-11-09 00:15:14 +01:00
}
}
2017-04-04 17:36:28 +02:00
2005-11-09 00:15:14 +01:00
if (( int ) $this -> debug >= 2 || $this -> debug == 'read_holidays' )
{
2017-04-04 17:36:28 +02:00
$this -> debug_message ( 'calendar_bo::read_holidays(%1)=%2' , true , $year , $holidays );
2004-08-01 17:36:04 +02:00
}
2017-04-04 17:36:28 +02:00
return $holidays ;
2004-08-01 17:36:04 +02:00
}
2014-11-19 21:10:07 +01:00
2014-10-28 10:54:52 +01:00
/**
* Get translated calendar event fields , presenting as link title options
*
* @ param type $event
* @ return array array of selected calendar fields
*/
2016-05-02 22:22:47 +02:00
public static function get_link_options ( $event = array ())
2014-10-28 10:54:52 +01:00
{
2015-07-16 14:10:48 +02:00
unset ( $event ); // not used, but required by function signature
2014-10-28 10:54:52 +01:00
$options = array (
'end' => lang ( 'End date' ),
'id' => lang ( 'ID' ),
2019-06-18 19:43:37 +02:00
'owner' => lang ( 'Owner' ),
2014-10-28 10:54:52 +01:00
'category' => lang ( 'Category' ),
'location' => lang ( 'Location' ),
'creator' => lang ( 'Creator' ),
'participants' => lang ( 'Participants' )
);
return $options ;
}
2014-11-19 21:10:07 +01:00
2005-11-09 00:15:14 +01:00
/**
* get title for an event identified by $event
2008-05-08 17:02:35 +02:00
*
2005-11-09 00:15:14 +01:00
* Is called as hook to participate in the linking
*
2009-08-04 19:14:16 +02:00
* @ param int | array $entry int cal_id or array with event
* @ param string | boolean string with title , null if not found or false if not read perms
2005-11-09 00:15:14 +01:00
*/
function link_title ( $event )
{
2010-09-03 20:04:48 +02:00
if ( ! is_array ( $event ) && strpos ( $event , '-' ) !== false )
{
list ( $id , $recur ) = explode ( '-' , $event , 2 );
$event = $this -> read ( $id , $recur );
2010-11-04 14:30:11 +01:00
}
2010-09-03 20:04:48 +02:00
else if ( ! is_array ( $event ) && ( int ) $event > 0 )
2005-11-09 00:15:14 +01:00
{
$event = $this -> read ( $event );
}
if ( ! is_array ( $event ))
{
2006-06-24 18:04:06 +02:00
return $event ;
2005-11-09 00:15:14 +01:00
}
2014-10-28 10:54:52 +01:00
$type = explode ( ',' , $this -> cal_prefs [ 'link_title' ]);
if ( is_array ( $type ))
{
foreach ( $type as & $val )
{
switch ( $val )
{
case 'end' :
case 'modified' :
$extra_fields [ $val ] = $this -> format_date ( $event [ $val ]);
break ;
case 'participants' :
2022-10-18 19:49:36 +02:00
foreach ( array_keys (( array ) $event [ $val ]) as $key )
2014-10-28 10:54:52 +01:00
{
2016-05-01 19:47:59 +02:00
$extra_fields [ $val ] = Api\Accounts :: id2name ( $key , 'account_fullname' );
2014-11-19 21:10:07 +01:00
}
2014-10-28 10:54:52 +01:00
break ;
case 'modifier' :
case 'creator' :
case 'owner' :
2016-05-01 19:47:59 +02:00
$extra_fields [ $val ] = Api\Accounts :: id2name ( $event [ $val ], 'account_fullname' );
2014-10-28 10:54:52 +01:00
break ;
2018-10-10 18:35:31 +02:00
case 'category' :
$extra_fields [ $val ] = Api\Categories :: id2name ( $event [ $val ]);
break ;
2014-10-28 10:54:52 +01:00
default :
$extra_fields [] = $event [ $val ];
}
}
$str_fields = implode ( ', ' , $extra_fields );
if ( is_array ( $extra_fields )) return $this -> format_date ( $event [ 'start' ]) . ': ' . $event [ 'title' ] . ( $str_fields ? ', ' . $str_fields : '' );
}
2005-11-09 00:15:14 +01:00
return $this -> format_date ( $event [ 'start' ]) . ': ' . $event [ 'title' ];
}
/**
* query calendar for events matching $pattern
*
* Is called as hook to participate in the linking
*
* @ param string $pattern pattern to search
2009-08-04 19:14:16 +02:00
* @ return array with cal_id - title pairs of the matching entries
2005-11-09 00:15:14 +01:00
*/
2009-12-08 23:36:43 +01:00
function link_query ( $pattern , Array & $options = array ())
2005-11-09 00:15:14 +01:00
{
$result = array ();
2009-12-08 23:36:43 +01:00
$query = array (
'query' => $pattern ,
2012-05-22 19:08:00 +02:00
'offset' => $options [ 'start' ],
'order' => 'cal_start DESC' ,
2009-12-08 23:36:43 +01:00
);
if ( $options [ 'num_rows' ]) {
$query [ 'num_rows' ] = $options [ 'num_rows' ];
}
foreach (( array ) $this -> search ( $query ) as $event )
2005-11-09 00:15:14 +01:00
{
$result [ $event [ 'id' ]] = $this -> link_title ( $event );
}
2009-12-08 23:36:43 +01:00
$options [ 'total' ] = $this -> total ;
2005-11-09 00:15:14 +01:00
return $result ;
}
2008-05-08 17:02:35 +02:00
2008-10-07 11:03:01 +02:00
/**
2011-06-26 17:41:21 +02:00
* Check access to the file store
2008-10-07 11:03:01 +02:00
*
* @ param int $id id of entry
2016-05-01 19:47:59 +02:00
* @ param int $check Acl :: READ for read and Acl :: EDIT for write or delete access
2015-07-16 14:10:48 +02:00
* @ param string $rel_path = null currently not used in calendar
* @ param int $user = null for which user to check , default current user
2008-10-07 11:03:01 +02:00
* @ return boolean true if access is granted or false otherwise
*/
2011-06-26 17:41:21 +02:00
function file_access ( $id , $check , $rel_path , $user = null )
2008-10-07 11:03:01 +02:00
{
2015-07-16 14:10:48 +02:00
unset ( $rel_path ); // not used, but required by function signature
2011-06-26 17:41:21 +02:00
return $this -> check_perms ( $check , $id , 0 , 'ts' , null , $user );
2008-10-07 11:03:01 +02:00
}
2005-11-09 00:15:14 +01:00
/**
* sets the default prefs , if they are not already set ( on a per pref . basis )
*
* It sets a flag in the app - session - data to be called only once per session
*/
function check_set_default_prefs ()
{
2016-05-01 19:47:59 +02:00
if ( $this -> cal_prefs [ 'interval' ] && ( $set = Api\Cache :: getSession ( 'calendar' , 'default_prefs_set' )))
2005-11-09 00:15:14 +01:00
{
return ;
}
2016-05-01 19:47:59 +02:00
Api\Cache :: setSession ( 'calendar' , 'default_prefs_set' , 'set' );
2005-11-09 00:15:14 +01:00
$default_prefs =& $GLOBALS [ 'egw' ] -> preferences -> default [ 'calendar' ];
2009-10-19 19:04:11 +02:00
$forced_prefs =& $GLOBALS [ 'egw' ] -> preferences -> forced [ 'calendar' ];
2005-11-09 00:15:14 +01:00
$subject = lang ( 'Calendar Event' ) . ' - $$action$$: $$startdate$$ $$title$$' . " \n " ;
2009-10-19 19:04:11 +02:00
$values = array (
2009-07-08 12:22:11 +02:00
'notifyAdded' => $subject . lang ( 'You have a meeting scheduled for %1' , '$$startdate$$' ),
'notifyCanceled' => $subject . lang ( 'Your meeting scheduled for %1 has been canceled' , '$$startdate$$' ),
'notifyModified' => $subject . lang ( 'Your meeting that had been scheduled for %1 has been rescheduled to %2' , '$$olddate$$' , '$$startdate$$' ),
2018-03-26 16:02:42 +02:00
'notifyDisinvited' => $subject . lang ( 'You have been uninvited from the meeting at %1' , '$$startdate$$' ),
2009-07-08 12:22:11 +02:00
'notifyResponse' => $subject . lang ( 'On %1 %2 %3 your meeting request for %4' , '$$date$$' , '$$fullname$$' , '$$action$$' , '$$startdate$$' ),
'notifyAlarm' => lang ( 'Alarm for %1 at %2 in %3' , '$$title$$' , '$$startdate$$' , '$$location$$' ) . " \n " . lang ( 'Here is your requested alarm.' ),
2009-10-19 19:04:11 +02:00
'interval' => 30 ,
2005-11-09 00:15:14 +01:00
);
2009-10-19 19:04:11 +02:00
foreach ( $values as $var => $default )
2005-11-09 00:15:14 +01:00
{
2009-10-19 19:04:11 +02:00
$type = substr ( $var , 0 , 6 ) == 'notify' ? 'forced' : 'default' ;
// only set, if neither default nor forced pref exists
if (( ! isset ( $default_prefs [ $var ]) || ( string ) $default_prefs [ $var ] === '' ) && ( ! isset ( $forced_prefs [ $var ]) || ( string ) $forced_prefs [ $var ] === '' ))
2005-11-09 00:15:14 +01:00
{
2009-10-19 19:04:11 +02:00
$GLOBALS [ 'egw' ] -> preferences -> add ( 'calendar' , $var , $default , 'default' ); // always store default, even if we have a forced too
if ( $type == 'forced' ) $GLOBALS [ 'egw' ] -> preferences -> add ( 'calendar' , $var , $default , 'forced' );
2005-11-09 00:15:14 +01:00
$this -> cal_prefs [ $var ] = $default ;
$need_save = True ;
}
}
if ( $need_save )
{
$GLOBALS [ 'egw' ] -> preferences -> save_repository ( False , 'default' );
2009-10-19 19:04:11 +02:00
$GLOBALS [ 'egw' ] -> preferences -> save_repository ( False , 'forced' );
2005-11-09 00:15:14 +01:00
}
}
2008-05-08 17:02:35 +02:00
2006-07-15 01:24:56 +02:00
/**
* Get the freebusy URL of a user
*
2009-08-04 19:14:16 +02:00
* @ param int | string $user account_id or account_lid
2015-07-16 14:10:48 +02:00
* @ param string $pw = null password
2006-07-15 01:24:56 +02:00
*/
2010-06-26 13:35:11 +02:00
static function freebusy_url ( $user = '' , $pw = null )
2006-07-15 01:24:56 +02:00
{
if ( is_numeric ( $user )) $user = $GLOBALS [ 'egw' ] -> accounts -> id2name ( $user );
2010-11-04 14:30:11 +01:00
2010-06-26 13:35:11 +02:00
$credentials = '' ;
2010-11-04 14:30:11 +01:00
2010-06-26 13:35:11 +02:00
if ( $pw )
{
$credentials = '&password=' . urlencode ( $pw );
}
elseif ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'calendar' ][ 'freebusy' ] == 2 )
{
$credentials = $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_lid' ]
. ':' . $GLOBALS [ 'egw_info' ][ 'user' ][ 'passwd' ];
$credentials = '&cred=' . base64_encode ( $credentials );
}
2019-11-15 13:54:34 +01:00
return Api\Framework :: getUrl ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ]) .
'/calendar/freebusy.php/?user=' . urlencode ( $user ) . $credentials ;
2006-07-15 01:24:56 +02:00
}
2009-07-15 22:35:56 +02:00
/**
* Check if the event is the whole day
*
2009-08-04 19:14:16 +02:00
* @ param array $event event
* @ return boolean true if whole day event , false othwerwise
2009-07-15 22:35:56 +02:00
*/
2010-12-21 03:45:40 +01:00
public static function isWholeDay ( $event )
2009-07-15 22:35:56 +02:00
{
// check if the event is the whole day
2010-12-21 03:45:40 +01:00
$start = self :: date2array ( $event [ 'start' ]);
$end = self :: date2array ( $event [ 'end' ]);
2009-08-04 19:14:16 +02:00
return ! $start [ 'hour' ] && ! $start [ 'minute' ] && $end [ 'hour' ] == 23 && $end [ 'minute' ] == 59 ;
2009-07-15 22:35:56 +02:00
}
2010-11-26 22:32:10 +01:00
/**
2010-12-21 03:45:40 +01:00
* Get the etag for an entry
2010-11-26 22:32:10 +01:00
*
2013-02-26 09:48:50 +01:00
* As all update routines ( incl . set_status and add / delete alarms ) update ( series master ) modified timestamp ,
* we do NOT need any special handling for series master anymore
*
2015-07-16 14:10:48 +02:00
* @ param array | int | string $entry array with event or cal_id , or cal_id : recur_date for virtual exceptions
2011-10-20 22:10:04 +02:00
* @ param string & $schedule_tag = null on return schedule - tag ( egw_cal . cal_id : egw_cal . cal_etag , no participant modifications ! )
2010-11-26 22:32:10 +01:00
* @ return string | boolean string with etag or false
*/
2013-02-26 09:48:50 +01:00
function get_etag ( $entry , & $schedule_tag = null )
2010-11-26 22:32:10 +01:00
{
if ( ! is_array ( $entry ))
{
2023-06-09 18:27:28 +02:00
list ( $id , $recur_date ) = explode ( ':' , $entry ) + [ null , null ];
2015-07-16 14:10:48 +02:00
$entry = $this -> read ( $id , $recur_date , true , 'server' );
2010-11-26 22:32:10 +01:00
}
2012-09-26 13:09:28 +02:00
$etag = $schedule_tag = $entry [ 'id' ] . ':' . $entry [ 'etag' ];
2023-07-24 17:08:05 +02:00
$etag .= ':' . Api\DateTime :: user2server ( $entry [ 'modified' ], 'ts' );
2010-11-26 22:32:10 +01:00
2023-07-24 17:08:05 +02:00
//error_log(__METHOD__ . "($entry[id],$client_share_uid_exceptions) entry=".array2string($entry)." --> etag=$etag");
2010-11-26 22:32:10 +01:00
return $etag ;
}
2010-12-02 23:27:32 +01:00
/**
* Query ctag for calendar
*
2012-09-27 17:46:08 +02:00
* @ param int | string | array $user integer user - id or array of user - id ' s to use , defaults to the current user
2015-07-16 14:10:48 +02:00
* @ param string $filter = 'owner' all ( not rejected ), accepted , unknown , tentative , rejected or hideprivate
* @ param boolean $master_only = false only check recurance master ( egw_cal_user . recur_date = 0 )
2012-03-12 09:20:36 +01:00
* @ return integer
2010-12-02 23:27:32 +01:00
*/
2012-03-12 09:20:36 +01:00
public function get_ctag ( $user , $filter = 'owner' , $master_only = false )
2010-12-02 23:27:32 +01:00
{
2011-04-06 14:46:21 +02:00
if ( $this -> debug > 1 ) $startime = microtime ( true );
2010-12-02 23:27:32 +01:00
2011-04-06 14:46:21 +02:00
// resolve users to add memberships for users and members for groups
$users = $this -> resolve_users ( $user );
2012-03-12 09:20:36 +01:00
$ctag = $users ? $this -> so -> get_ctag ( $users , $filter == 'owner' , $master_only ) : 0 ; // no rights, return 0 as ctag (otherwise we get SQL error!)
2010-12-02 23:27:32 +01:00
2016-02-23 16:04:30 +01:00
if ( $this -> debug > 1 ) error_log ( __METHOD__ . " ( $user , ' $filter ', $master_only ) = $ctag = " . date ( 'Y-m-d H:i:s' , $ctag ) . " took " . ( microtime ( true ) - $startime ) . " secs " );
2010-12-02 23:27:32 +01:00
return $ctag ;
}
2011-05-30 16:21:27 +02:00
2013-05-10 12:54:36 +02:00
/**
* Hook for infolog to set some extra data and links
*
* @ param array $data event - array preset by infolog plus
* @ param int $data [ id ] cal_id
* @ return array with key => value pairs to set in new event and link_app / link_id arrays
*/
function infolog_set ( $data )
{
if ( ! ( $calendar = $this -> read ( $data [ 'id' ])))
{
return array ();
}
$content = array (
2016-05-01 19:47:59 +02:00
'info_cat' => $GLOBALS [ 'egw' ] -> categories -> check_list ( Acl :: READ , $calendar [ 'category' ]),
2013-05-10 12:54:36 +02:00
'info_priority' => $calendar [ 'priority' ] ,
'info_public' => $calendar [ 'public' ] != 'private' ,
'info_subject' => $calendar [ 'title' ],
'info_des' => $calendar [ 'description' ],
'info_location' => $calendar [ 'location' ],
'info_startdate' => $calendar [ 'range_start' ],
//'info_enddate' => $calendar['range_end'] ? $calendar['range_end'] : $calendar['uid']
'info_contact' => 'calendar:' . $data [ 'id' ],
);
unset ( $content [ 'id' ]);
// Add calendar link to infolog entry
$content [ 'link_app' ][] = $calendar [ 'info_link' ][ 'app' ];
$content [ 'link_id' ][] = $calendar [ 'info_link' ][ 'id' ];
// Copy claendar's links
2016-05-01 19:47:59 +02:00
foreach ( Link :: get_links ( 'calendar' , $calendar [ 'id' ], '' , 'link_lastmod DESC' , true ) as $link )
2013-05-10 12:54:36 +02:00
{
2016-05-01 19:47:59 +02:00
if ( $link [ 'app' ] != Link :: VFS_APPNAME )
2013-05-10 12:54:36 +02:00
{
$content [ 'link_app' ][] = $link [ 'app' ];
$content [ 'link_id' ][] = $link [ 'id' ];
}
if ( $link [ 'app' ] == 'addressbook' ) // prefering contact as primary contact over calendar entry set above
{
$content [ 'info_contact' ] = 'addressbook:' . $link [ 'id' ];
}
}
// Copy same custom fields
2016-05-01 19:47:59 +02:00
foreach ( array_keys ( Api\Storage\Customfields :: get ( 'infolog' )) as $name )
2013-05-10 12:54:36 +02:00
{
if ( $this -> customfields [ $name ]) $content [ '#' . $name ] = $calendar [ '#' . $name ];
}
//error_log(__METHOD__.'('.array2string($data).') calendar='.array2string($calendar).' returning '.array2string($content));
return $content ;
}
2011-05-30 16:21:27 +02:00
/**
* Hook for timesheet to set some extra data and links
*
* @ param array $data
* @ param int $data [ id ] cal_id : recurrence
* @ return array with key => value pairs to set in new timesheet and link_app / link_id arrays
*/
function timesheet_set ( $data )
{
$set = array ();
list ( $id , $recurrence ) = explode ( ':' , $data [ 'id' ]);
if (( int ) $id && ( $event = $this -> read ( $id , $recurrence )))
{
$set [ 'ts_start' ] = $event [ 'start' ];
$set [ 'ts_title' ] = $this -> link_title ( $event );
2016-05-01 19:47:59 +02:00
$set [ 'start_time' ] = Api\DateTime :: to ( $event [ 'start' ], 'H:i' );
2011-05-30 16:21:27 +02:00
$set [ 'ts_description' ] = $event [ 'description' ];
if ( $this -> isWholeDay ( $event )) $event [ 'end' ] ++ ; // whole day events are 1sec short
$set [ 'ts_duration' ] = ( $event [ 'end' ] - $event [ 'start' ]) / 60 ;
$set [ 'ts_quantity' ] = ( $event [ 'end' ] - $event [ 'start' ]) / 3600 ;
$set [ 'end_time' ] = null ; // unset end-time
$set [ 'cat_id' ] = ( int ) $event [ 'category' ];
2012-10-08 16:53:51 +02:00
2016-05-01 19:47:59 +02:00
foreach ( Link :: get_links ( 'calendar' , $id , '' , 'link_lastmod DESC' , true ) as $link )
2012-10-08 16:53:51 +02:00
{
2016-05-01 19:47:59 +02:00
if ( $link [ 'app' ] != 'timesheet' && $link [ 'app' ] != Link :: VFS_APPNAME )
2012-10-08 16:53:51 +02:00
{
$set [ 'link_app' ][] = $link [ 'app' ];
$set [ 'link_id' ][] = $link [ 'id' ];
}
}
2011-05-30 16:21:27 +02:00
}
return $set ;
}
2022-04-26 21:04:16 +02:00
}