<?php /** * * SugarCRM Community Edition is a customer relationship management program developed by * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. * * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. * Copyright (C) 2011 - 2024 SalesAgility Ltd. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License version 3 as published by the * Free Software Foundation with the addition of the following permission added * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License along with * this program; if not, see http://www.gnu.org/licenses or write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. * * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License version 3. * * In accordance with Section 7(b) of the GNU Affero General Public License version 3, * these Appropriate Legal Notices must retain the display of the "Powered by * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not * reasonably feasible for technical reasons, the Appropriate Legal Notices must * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". */ if (!defined('sugarEntry') || !sugarEntry) { die('Not A Valid Entry Point'); } require_once 'include/utils/activity_utils.php'; #[\AllowDynamicProperties] class CalendarActivity { public $sugar_bean; public $start_time; public $end_time; /** * CalendarActivity constructor. * @param $args */ public function __construct($args) { // if we've passed in an array, then this is a free/busy slot // and does not have a sugarbean associated to it global $timedate; if (is_array($args)) { $this->start_time = clone $args[0]; $this->end_time = clone $args[1]; $this->sugar_bean = null; $timedate->tzGMT($this->start_time); $timedate->tzGMT($this->end_time); return; } // else do regular constructor.. $sugar_bean = $args; $this->sugar_bean = $sugar_bean; if ($sugar_bean->object_name === 'Task') { if (!empty($this->sugar_bean->date_start)) { $this->start_time = $timedate->fromUser($this->sugar_bean->date_start); } else { $this->start_time = $timedate->fromUser($this->sugar_bean->date_due); } if (empty($this->start_time)) { return; } $this->end_time = $timedate->fromUser($this->sugar_bean->date_due); } else { $this->start_time = $timedate->fromUser($this->sugar_bean->date_start); if (empty($this->start_time)) { return; } $hours = $this->sugar_bean->duration_hours; if (empty($hours)) { $hours = 0; } $mins = $this->sugar_bean->duration_minutes; if (empty($mins)) { $mins = 0; } $this->end_time = $this->start_time->get("+$hours hours $mins minutes"); } // Convert it back to database time so we can properly manage it for getting the proper start and end dates $timedate->tzGMT($this->start_time); $timedate->tzGMT($this->end_time); } /** * Get where clause for fetching entries from DB for within two dates timespan * @param string $table_name t * @param string $rel_table table for accept status, not used in Tasks * @param SugarDateTime $start_ts_obj start date * @param SugarDateTime $end_ts_obj end date * @param string $field_name date field in table * @param string $field_end_date * @return string */ public static function get_occurs_within_where_clause( $table_name, $rel_table, $start_ts_obj, $end_ts_obj, $field_name = 'date_start', $field_end_date = 'date_end' ) { return self::getOccursWhereClauseGeneral( $table_name, $rel_table, $start_ts_obj, $end_ts_obj, $field_name, $field_end_date, array('self', 'within') ); } /** * Get where clause for fetching entries from DB for until certain date timespan * @param string $table_name t * @param string $rel_table table for accept status, not used in Tasks * @param SugarDateTime $start_ts_obj start date * @param SugarDateTime $end_ts_obj end date * @param string $field_name date field in table * @param string $field_end_date * @return string */ public static function get_occurs_until_where_clause( $table_name, $rel_table, $start_ts_obj, $end_ts_obj, $field_name = 'date_start', $field_end_date = 'date_end' ) { return self::getOccursWhereClauseGeneral( $table_name, $rel_table, $start_ts_obj, $end_ts_obj, $field_name, $field_end_date, array('self', 'until') ); } /** * @param $user_focus * @param $start_date_time * @param $end_date_time * @return array */ public static function get_freebusy_activities($user_focus, $start_date_time, $end_date_time) { $act_list = array(); $vcal_focus = BeanFactory::newBean('vCals'); $vcal_str = $vcal_focus->get_vcal_freebusy($user_focus); $lines = explode("\n", $vcal_str); $utc = new DateTimeZone('UTC'); foreach ($lines as $line) { if (preg_match('/^FREEBUSY.*?:([^\/]+)\/([^\/]+)/i', $line, $matches)) { $dates_arr = array( SugarDateTime::createFromFormat(vCal::UTC_FORMAT, $matches[1], $utc), SugarDateTime::createFromFormat(vCal::UTC_FORMAT, $matches[2], $utc) ); $act_list[] = new CalendarActivity($dates_arr); } } return $act_list; } /** * Get array of activities * @param array $activities * @param string $user_id * @param boolean $show_tasks * @param SugarDateTime $view_start_time start date * @param SugarDateTime $view_end_time end date * @param string $view view; not used for now, left for compatibility * @param boolean $show_calls * @param boolean $show_completed use to allow filtering completed events * @return array */ public static function get_activities( $activities, $user_id, $show_tasks, $view_start_time, $view_end_time, $view, $show_calls = true, $show_completed = true ) { global $current_user; $act_list = array(); $seen_ids = array(); $complete = []; if (!$show_completed) { $complete['Calls'] = " AND calls.status = 'Planned' "; $complete['Meetings'] = " AND meetings.status = 'Planned' "; $complete['Tasks'] = " AND tasks.status != 'Completed' "; } foreach ($activities as $key => $activity) { if ($key === 'Tasks' && !$show_tasks || $key === 'Calls' && !$show_calls) { continue; } if (ACLController::checkAccess($key, 'list', true)) { /* END - SECURITY GROUPS */ $bean = BeanFactory::newBean($key); if ($current_user->id === $user_id) { $bean->disable_row_level_security = true; } switch ($key) { case 'Meetings': case 'Calls': $where = self::get_occurs_until_where_clause( $bean->table_name, isset($bean->rel_users_table) ? $bean->rel_users_table : null, $view_start_time, $view_end_time, $activity['start'], $activity['end'] ); break; default: $where = self::get_occurs_within_where_clause( $bean->table_name, isset($bean->rel_users_table) ? $bean->rel_users_table : null, $view_start_time, $view_end_time, $activity['start'], $activity['end'] ); break; } if (!empty($complete[$key])) { $where .= $complete[$key]; } $focus_list = build_related_list_by_user_id($bean, $user_id, $where); //require_once 'modules/SecurityGroups/SecurityGroup.php'; foreach ($focus_list as $focusBean) { if (isset($seen_ids[$focusBean->id])) { continue; } /* TODO update currently unused functionality, disabled as expensive $in_group = SecurityGroup::groupHasAccess($key, $focusBean->id, 'list'); $show_as_busy = !ACLController::checkAccess( $key, 'list', $current_user->id === $user_id, 'module', $in_group ); $focusBean->show_as_busy = $show_as_busy;*/ $seen_ids[$focusBean->id] = 1; $act = new CalendarActivity($focusBean); if (!empty($act)) { $act_list[] = $act; } } } } return $act_list; } /** * Get where clause for fetching entries from DB (is used by certain get_occurs.. methods) * @param string $table_name t * @param string $rel_table table for accept status, not used in Tasks * @param SugarDateTime $start_ts_obj start date * @param SugarDateTime $end_ts_obj end date * @param string $field_name date field in table * @param $field_end_date * @param array $callback callback function to generete specific SQL query-part * @return string */ protected static function getOccursWhereClauseGeneral( $table_name, $rel_table, $start_ts_obj, $end_ts_obj, $field_name, $field_end_date, $callback ) { $start = clone $start_ts_obj; $end = clone $end_ts_obj; $field_date = $table_name . '.' . $field_name; $field_end_date = $table_name . '.' . $field_end_date; $start_day = DBManagerFactory::getInstance()->convert("'{$start->asDb()}'", 'datetime'); $end_day = DBManagerFactory::getInstance()->convert("'{$end->asDb()}'", 'datetime'); $where = '('; $where .= call_user_func($callback, $field_date, $field_end_date, $start_day, $end_day); if (!empty($rel_table)) { $where .= " AND $rel_table.accept_status != 'decline'"; } $where .= ')'; return $where; } /** * Helper-method to generate within two dates sql clause * @param $field_date string table_name.field_name to compare * @param $field_date_end * @param $start_day string period start date * @param $end_day string period end date * @return string */ protected static function within($field_date, $field_date_end, $start_day, $end_day) { return "$field_date >= $start_day AND $field_date < $end_day"; } /** * Helper-method to generate until some date sql clause * @param $field_date string table_name.field_name to compare * @param $field_date_end * @param $start_day string period start date * @param $end_day string period end date * @return string */ protected static function until($field_date, $field_date_end, $start_day, $end_day) { return "($field_date >= $start_day AND $field_date < $end_day) OR ($field_date < $start_day AND $field_date_end > $start_day)"; } }