mirror of
https://github.com/VTECRM/vtenext.git
synced 2026-02-26 16:18:47 +00:00
590 lines
17 KiB
PHP
590 lines
17 KiB
PHP
<?php
|
|
/*************************************
|
|
* SPDX-FileCopyrightText: 2009-2020 Vtenext S.r.l. <info@vtenext.com>
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
************************************/
|
|
|
|
//crmv@38878
|
|
class VTEvcalendar extends vcalendar {
|
|
|
|
var $vevent_mapping = array(
|
|
'class' => array('component'=>'visibility','function'=>'handleCLASS','type'=>'string'),
|
|
'description' => array('component'=>'description','function'=>'handleDESCRIPTION','type'=>'string'),
|
|
'dtstart' => array('component'=>array('date_start','time_start'),'type'=>'datetime'),
|
|
'dtend' => array('component'=>array('due_date','time_end'),'type'=>'datetime'),
|
|
'dtstamp' => array('component'=>array('date_start','time_start'),'type'=>'datetime'),
|
|
'location' => array('component'=>'location','function'=>'setBlankIfNull','type'=>'string'),
|
|
'status' => array('component'=>'eventstatus','function'=>'handleSTATUS','type'=>'string'),
|
|
'summary' => array('component'=>'subject','type'=>'string'),
|
|
'priority' => array('component'=>'priority','type'=>'string'),
|
|
'resources' => array('component'=>array('location','eventstatus'),'type'=>'string'),
|
|
'uid' => array('component'=>'ical_uuid','type'=>'string'), // crmv@68357
|
|
'sequence' => array('component'=>'recurr_idx','type'=>'integer'), // crmv@81126
|
|
'organizer' => array('component'=>'activityid','type'=>'organizer'), // crmv@68357
|
|
'attendee' => array('component'=>'activityid','type'=>'invitee'), // crmv@68357
|
|
'rrule' => array('component'=>'activityid','type'=>'recurrence'), // crmv@185576
|
|
);
|
|
|
|
var $vevent_field_mapping = array(
|
|
'priority'=>'taskpriority',
|
|
);
|
|
|
|
var $vtodo_mapping = array(
|
|
'description' => array('component'=>'description','function'=>'handleDESCRIPTION','type'=>'string'),
|
|
'dtstamp' => array('component'=>array('date_start','time_start'),'type'=>'datetime'),
|
|
'dtstart' => array('component'=>array('date_start','time_start'),'type'=>'datetime'),
|
|
'due' => array('component'=>array('due_date'),'type'=>'datetime'),
|
|
'status' => array('component'=>'status','function'=>'handleSTATUS','type'=>'string'),
|
|
'summary' => array('component'=>'subject','type'=>'string'),
|
|
'priority' => array('component'=>'priority','type'=>'string'),
|
|
'resources' => array('component'=>array('status'),'type'=>'string'),
|
|
'uid' => array('component'=>'ical_uuid','type'=>'string'), // crmv@68357
|
|
);
|
|
|
|
var $vtodo_field_mapping = array(
|
|
'status'=>'taskstatus',
|
|
'priority'=>'taskpriority'
|
|
);
|
|
|
|
// crmv@68357
|
|
protected $todo_fields = null;
|
|
protected $event_fields = null;
|
|
protected $event_keys = null;
|
|
protected $todo_keys = null;
|
|
|
|
protected $keyvals_to_replace = array(
|
|
'events'=> array('taskpriority'=>'priority', 'assigned_user_id' => 'smownerid'),
|
|
'todo' => array('taskpriority'=>'priority','taskstatus'=>'status')
|
|
);
|
|
protected $keys_ical_replace = array(
|
|
'events' => array(), // es: 'date_start' => 'dtstart'
|
|
'todo' => array(),
|
|
);
|
|
|
|
public function generateFromSql($sql, $params = array()) {
|
|
global $adb;
|
|
|
|
require('vteversion.php'); // crmv@181168
|
|
|
|
// execute query
|
|
$calendar_results = $adb->pquery($sql, $params);
|
|
|
|
// create the calendar instance
|
|
$myical = new iCalendar;
|
|
$myical->add_property('PRODID', "-//VTECRM//NONSGML $enterprise_mode $enterprise_current_version//EN");
|
|
|
|
// add the timezone
|
|
$tz = $this->generateTimezone();
|
|
if ($tz && $tz->is_valid()) $myical->add_component($tz);
|
|
|
|
// add the events/todos
|
|
while ($this_event = $adb->FetchByAssoc($calendar_results, -1, false)) {
|
|
$ev = $this->generateFromDbRow($this_event);
|
|
if ($ev === false) continue;
|
|
$myical->add_component($ev);
|
|
}
|
|
|
|
return $myical;
|
|
}
|
|
|
|
// crmv@69568
|
|
public function generateFromFields($fields) {
|
|
|
|
// add some values, do make it like a retrieved row
|
|
if (!isset($fields['smownerid']) && isset($fields['assigned_user_id'])) {
|
|
$fields['smownerid'] = $fields['assigned_user_id'];
|
|
}
|
|
if (!isset($fields['activityid']) && isset($fields['record_id'])) {
|
|
$fields['activityid'] = $fields['record_id'];
|
|
}
|
|
if (!isset($fields['priority']) && isset($fields['taskpriority'])) {
|
|
$fields['priority'] = $fields['taskpriority'];
|
|
}
|
|
|
|
require('vteversion.php'); // crmv@181168
|
|
|
|
// create the calendar instance
|
|
$myical = new iCalendar;
|
|
$myical->add_property('PRODID', "-//VTECRM//NONSGML $enterprise_mode $enterprise_current_version//EN");
|
|
|
|
// add the timezone
|
|
$tz = $this->generateTimezone();
|
|
if ($tz && $tz->is_valid()) $myical->add_component($tz);
|
|
|
|
// add the event/todo
|
|
$ev = $this->generateFromDbRow($fields);
|
|
if ($ev !== false) {
|
|
$myical->add_component($ev);
|
|
}
|
|
|
|
return $myical;
|
|
}
|
|
// crmv@69568e
|
|
|
|
public function generateFromDbRow($datarow) {
|
|
if ($datarow['activitytype'] != 'Task') {
|
|
$ev = $this->generateEventFromDbRow($datarow);
|
|
} else {
|
|
$ev = $this->generateTodoFromDbRow($datarow);
|
|
}
|
|
return $ev;
|
|
}
|
|
|
|
public function generateEventFromDbRow($datarow) {
|
|
$this->loadEventFields();
|
|
|
|
$id = $datarow['activityid'];
|
|
|
|
$temp = $this->event_keys;
|
|
foreach ($temp as $key=>$val) {
|
|
$newkey = $key;
|
|
if (array_key_exists($key, $this->keys_ical_replace['events'])) {
|
|
unset($temp[$key]);
|
|
$newkey = $this->keys_ical_replace['events'][$key];
|
|
}
|
|
//crmv@29407
|
|
if (in_array($key,Array('date_start','due_date'))){
|
|
$datarow[$key] = substr($datarow[$key],0,10);
|
|
}
|
|
//crmv@29407 e
|
|
$temp[$newkey] = $datarow[$key];
|
|
}
|
|
$temp['id'] = $id;
|
|
$ev = new iCalendar_event;
|
|
$ev->assign_values($temp);
|
|
// add some more properties
|
|
$ev->add_property('TRANSP', 'OPAQUE');
|
|
if (!$ev->is_valid()) return false;
|
|
|
|
if (!empty($temp['reminder_time'])) {
|
|
$al = new iCalendar_alarm;
|
|
$al->assign_values($temp);
|
|
if ($al->is_valid()) $ev->add_component($al);
|
|
}
|
|
|
|
return $ev;
|
|
}
|
|
|
|
public function generateTodoFromDbRow($datarow) {
|
|
$this->loadTodoFields();
|
|
|
|
$id = $datarow['activityid'];
|
|
|
|
$temp = $this->todo_keys;
|
|
foreach($temp as $key=>$val){
|
|
$newkey = $key;
|
|
if (array_key_exists($key, $this->keys_ical_replace['todo'])) {
|
|
unset($temp[$key]);
|
|
$newkey = $this->keys_ical_replace['todo'][$key];
|
|
}
|
|
//crmv@29407
|
|
if (in_array($key,Array('date_start','due_date'))){
|
|
$datarow[$key] = substr($datarow[$key],0,10);
|
|
}
|
|
//crmv@29407 e
|
|
$temp[$newkey] = $datarow[$key];
|
|
}
|
|
$ev = new iCalendar_todo;
|
|
$ev->assign_values($temp);
|
|
$ev->add_property('TRANSP', 'OPAQUE');
|
|
if (!$ev->is_valid()) return false;
|
|
|
|
return $ev;
|
|
}
|
|
|
|
public function generateTimezone() {
|
|
global $default_timezone;
|
|
|
|
$tz = new iCalendar_timezone;
|
|
if(!empty($default_timezone)){
|
|
$tzid = explode('/',$default_timezone);
|
|
} else {
|
|
$default_timezone = date_default_timezone_get();
|
|
$tzid = explode('/',$default_timezone);
|
|
}
|
|
|
|
$dtz = new DateTimeZone($default_timezone);
|
|
|
|
// get all transitions for one year back/ahead
|
|
$year = 86400 * 360;
|
|
$from = $to = 0;
|
|
$transitions = $dtz->getTransitions($from - $year, $to + $year);
|
|
|
|
if (!empty($tzid[1])) {
|
|
$tz->add_property('TZID', $tzid[1]);
|
|
} else {
|
|
$tz->add_property('TZID', $tzid[0]);
|
|
}
|
|
|
|
$std = null; $dst = null;
|
|
foreach ($transitions as $i => $trans) {
|
|
$cmp = null;
|
|
|
|
// skip the first entry...
|
|
if ($i == 0) {
|
|
// ... but remember the offset for the next TZOFFSETFROM value
|
|
$tzfrom = $trans['offset'] / 3600;
|
|
continue;
|
|
}
|
|
|
|
// daylight saving time definition
|
|
if ($trans['isdst']) {
|
|
$t_dst = $trans['ts'];
|
|
$dst = new iCalendar_timezone_daylight();
|
|
$cmp = $dst;
|
|
}
|
|
// standard time definition
|
|
else {
|
|
$t_std = $trans['ts'];
|
|
$std = new iCalendar_timezone_standard();
|
|
$cmp = $std;
|
|
}
|
|
|
|
if ($cmp) {
|
|
$dt = new DateTime($trans['time']);
|
|
$offset = $trans['offset'] / 3600;
|
|
|
|
$cmp->add_property('DTSTART', $dt->format('Ymd\THis'));
|
|
$cmp->add_property('TZOFFSETFROM', sprintf('%s%02d%02d', $tzfrom >= 0 ? '+' : '', floor($tzfrom), ($tzfrom - floor($tzfrom)) * 60));
|
|
$cmp->add_property('TZOFFSETTO', sprintf('%s%02d%02d', $offset >= 0 ? '+' : '', floor($offset), ($offset - floor($offset)) * 60));
|
|
|
|
// add abbreviated timezone name if available
|
|
if (!empty($trans['abbr'])) {
|
|
//$cmp->TZNAME = $trans['abbr'];
|
|
$cmp->add_property('TZNAME', $trans['abbr']);
|
|
}
|
|
|
|
$tzfrom = $offset;
|
|
$tz->add_component($cmp);
|
|
}
|
|
|
|
// we covered the entire date range
|
|
if ($std && $dst && min($t_std, $t_dst) < $from && max($t_std, $t_dst) > $to) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $tz;
|
|
}
|
|
|
|
// load the info about the event fields
|
|
protected function loadEventFields() {
|
|
global $current_user;
|
|
|
|
if (is_null($this->event_fields)) $this->event_fields = getColumnFields('Events');
|
|
if (is_null($this->event_keys)) {
|
|
$this->event_keys = array();
|
|
foreach ($this->event_fields as $key=>$val) {
|
|
if (getFieldVisibilityPermission('Events',$current_user->id,$key) == 0) {
|
|
if (!array_key_exists($key, $this->keyvals_to_replace['events'])) {
|
|
$this->event_keys[$key] = 'yes';
|
|
} else {
|
|
$this->event_keys[$this->keyvals_to_replace['events'][$key]] = 'yes';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected function loadTodoFields() {
|
|
global $current_user;
|
|
|
|
if (is_null($this->todo_fields)) $this->todo_fields = getColumnFields('Calendar');
|
|
if (is_null($this->todo_keys)) {
|
|
$this->todo_keys = array();
|
|
foreach($this->todo_fields as $key=>$val){
|
|
if (getFieldVisibilityPermission('Calendar',$current_user->id,$key) == 0) {
|
|
if (!array_key_exists($key, $this->keyvals_to_replace['todo'])) {
|
|
$this->todo_keys[$key] = 'yes';
|
|
} else {
|
|
$this->todo_keys[$this->keyvals_to_replace['todo'][$key]] = 'yes';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function generateArray($ical_activity,$activitytype){
|
|
global $current_user;
|
|
|
|
$activity = array();
|
|
if($activitytype == 'vevent'){
|
|
$modtype = 'Events';
|
|
} else {
|
|
$modtype = 'Calendar';
|
|
}
|
|
|
|
$mapping = $activitytype.'_mapping';
|
|
$field_mapping = $activitytype.'field_mapping';
|
|
|
|
foreach($this->$mapping as $key=>$comp){
|
|
$type = $comp['type'];
|
|
$component = $comp['component'];
|
|
$function = $comp['function'];
|
|
if(!is_array($component)){
|
|
if ($type == 'invitee') {
|
|
// invitations
|
|
if (!is_array($activity['invitees'])) $activity['invitees'] = array();
|
|
while ($invit = $ical_activity->getProperty($key, false, true)) {
|
|
$vteInvitee = $this->getVteInvitee($invit);
|
|
if ($vteInvitee) $activity['invitees'][] = $vteInvitee;
|
|
}
|
|
} elseif ($type == 'organizer') {
|
|
$org = $ical_activity->getProperty($key, false, true);
|
|
$vteInvitee = $this->getVteInvitee($org, false);
|
|
if ($vteInvitee) $activity['organizer'] = $vteInvitee;
|
|
// crmv@185576
|
|
} elseif ($type == 'recurrence') {
|
|
$rrule = $ical_activity->getProperty($key, false, true);
|
|
$rtype = RecurringType::fromRRule($rrule['value'], $activity);
|
|
if ($rtype) {
|
|
$activity['recurringtype'] = $rtype->getRecurringType();
|
|
$activity['recurrence'] = $rtype;
|
|
$repLabel = $rtype->getDisplayRecurringInfo();
|
|
$activity['recurrence_text'] = $repLabel['full_text'];
|
|
}
|
|
// crmv@185576e
|
|
} else {
|
|
if(isset($this->$field_mapping) && isset($this->$field_mapping[$component])){ // crmv@74794
|
|
if(getFieldVisibilityPermission($modtype,$current_user->id,$this->$field_mapping[$component])=='0')
|
|
$activity[$this->$field_mapping[$component]] = $ical_activity->getProperty($key);
|
|
else
|
|
$activity[$this->$field_mapping[$component]] = '';
|
|
} else {
|
|
if(getFieldVisibilityPermission($modtype,$current_user->id,$component)=='0') {
|
|
// crmv@81052
|
|
$property = $ical_activity->getProperty($key);
|
|
if ($property === false && $type == 'string') $property = '';
|
|
$activity[$component] = $property;
|
|
// crmv@81052e
|
|
} else {
|
|
$activity[$component] = '';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$temp = $ical_activity->getProperty($key);
|
|
$count = 0;
|
|
if($type == 'string'){
|
|
$values = $temp;
|
|
} else if($type == 'datetime'){
|
|
$values = $this->strtodatetime($temp);
|
|
}
|
|
foreach($component as $index){
|
|
if(!isset($activity[$index])){
|
|
if(isset($this->$field_mapping) && isset($this->$field_mapping[$index])){ // crmv@74794
|
|
if(getFieldVisibilityPermission($modtype,$current_user->id,$this->$field_mapping[$index])=='0')
|
|
$activity[$this->$field_mapping[$index]] = $values[$count];
|
|
else
|
|
$activity[$this->$field_mapping[$index]] = '';
|
|
} else {
|
|
if(getFieldVisibilityPermission($modtype,$current_user->id,$index)=='0')
|
|
$activity[$index] = $values[$count];
|
|
else
|
|
$activity[$index] = '';
|
|
}
|
|
}
|
|
$count++;
|
|
}
|
|
unset($values);
|
|
}
|
|
|
|
if(isset($function) && method_exists($this,$function)){
|
|
$activity[$component] = $this->$function($component,$activity[$component]);
|
|
}
|
|
}
|
|
|
|
if($activitytype == 'vevent'){
|
|
$activity['activitytype'] = 'Meeting';
|
|
|
|
// crmv@90495
|
|
// fix status, if it's in the future
|
|
$now = date('Y-m-d H:i');
|
|
$eventStart = $activity['date_start'].' '.$activity['time_start'];
|
|
if ($activity['eventstatus'] == 'Held' && $eventStart >= $now) {
|
|
$activity['eventstatus'] = 'Planned';
|
|
}
|
|
// crmv@90495e
|
|
|
|
// set the reminder
|
|
$valarm = $ical_activity->getProperty('valarm');
|
|
if(!empty($valarm)){
|
|
$temp = str_replace("PT",'',$valarm['trigger']);
|
|
$duration_type = $temp[strlen($temp)-1];
|
|
$duration = intval($temp);
|
|
if($duration_type=='H'){
|
|
$reminder_time = $duration*60;
|
|
} else if($duration_type=='M'){
|
|
$reminder_time = $duration;
|
|
}
|
|
$activity['reminder_time'] = $reminder_time;
|
|
}
|
|
} else {
|
|
$activity['activitytype'] = 'Task';
|
|
}
|
|
|
|
// look for and existing record with same uid
|
|
if (!empty($activity['ical_uuid'])) {
|
|
if (!$this->calendarFocus) $this->calendarFocus = CRMEntity::getInstance('Calendar');
|
|
$crmid = $this->calendarFocus->getCrmidFromUuid($activity['ical_uuid'], $activity['recurr_idx']); // crmv@81126
|
|
if ($crmid > 0) {
|
|
$activity['activityid'] = $crmid;
|
|
}
|
|
}
|
|
|
|
return $activity;
|
|
}
|
|
|
|
function getVteInvitee($invitee, $searchVteRecord = true) {
|
|
$result = null;
|
|
$mail = $invitee['value'];
|
|
if (preg_match('/^mailto:(.+)$/i', $mail, $matches)) {
|
|
$result = array();
|
|
$mail = $matches[1];
|
|
$result['email'] = $mail;
|
|
$result['partecipation'] = $this->handlePARTSTAT($invitee['params']['PARTSTAT']);
|
|
$result['cname'] = $invitee['params']['CN'] ?: $mail;
|
|
|
|
// now fond a record from the vte
|
|
if ($searchVteRecord) {
|
|
$rec = $this->searchVteInvitee($mail);
|
|
if ($rec) $result['record'] = $rec;
|
|
}
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
// Search in the VTE for a User or Contact with this email. Only the first match is returned, Users have priority
|
|
function searchVteInvitee($email) {
|
|
if (!$this->helperObject) {
|
|
require_once('include/Webservices/VtenextCRMObject.php');//crmv@207871
|
|
$this->helperObject = new VtenextCRMObject('Events', false);//crmv@207871
|
|
}
|
|
|
|
$rec = null;
|
|
$list = $this->helperObject->lookForInvitee($email, true, true); // crmv@189222
|
|
if (is_array($list) && count($list) > 0) {
|
|
if ($list[0] && $list[0]['crmid'] > 0) {
|
|
$rec = $list[0];
|
|
$rec['entityname'] = getEntityName($rec['module'], $rec['crmid'], true);
|
|
if (is_array($rec['entityname'])) {
|
|
$rec['entityname'] = $rec['entityname'][$rec['crmid']];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $rec;
|
|
}
|
|
|
|
function handlePARTSTAT($value) {
|
|
switch($value){
|
|
case 'ACCEPTED':
|
|
$value = 2;
|
|
break;
|
|
case 'DECLINED':
|
|
$value = 1;
|
|
break;
|
|
default:
|
|
$value = 0;
|
|
break;
|
|
}
|
|
return $value;
|
|
}
|
|
|
|
function handleCLASS($fieldname,$value){
|
|
switch($value){
|
|
case 'PUBLIC':
|
|
$value = 'Public';
|
|
break;
|
|
case 'PRIVATE':
|
|
$value = 'Private';
|
|
break;
|
|
default:
|
|
$value = 'Standard';
|
|
break;
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
function handleSTATUS($fieldname,$value){
|
|
//event
|
|
if ($fieldname == 'eventstatus') {
|
|
switch ($value) {
|
|
case 'TENTATIVE':
|
|
$value = 'Planned';
|
|
break;
|
|
case 'CONFIRMED':
|
|
$value = 'Held';
|
|
break;
|
|
case 'CANCELLED':
|
|
$value = 'Not Held';
|
|
break;
|
|
default:
|
|
$value = 'Planned';
|
|
break;
|
|
}
|
|
} else {
|
|
//todo
|
|
switch ($value) {
|
|
case 'NEEDS-ACTION':
|
|
$value = 'Pending Input';
|
|
break;
|
|
case 'COMPLETED':
|
|
$value = 'Completed';
|
|
break;
|
|
case 'IN-PROCESS':
|
|
$value = 'In Progress';
|
|
break;
|
|
case 'CANCELLED':
|
|
$value = 'Deferred';
|
|
break;
|
|
default:
|
|
$value = 'Planned';
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
// crmv@68357e
|
|
|
|
function setBlankIfNull($fieldname,$value){
|
|
if(empty($value)){
|
|
$value = '';
|
|
}
|
|
return $value;
|
|
}
|
|
|
|
function handleDESCRIPTION($fieldname,$value){
|
|
if(!empty($value)){
|
|
$value = str_replace('\r\n',"\r\n",$value);
|
|
$value = str_replace('\n',"\n",$value);
|
|
}
|
|
return $value;
|
|
}
|
|
|
|
// crmv@68357 - use the timezone (only utc for now)
|
|
function strtodatetime($date){
|
|
global $default_timezone;
|
|
|
|
if ($date['tz'] == 'Z') {
|
|
$inputTz = new DateTimeZone('UTC');
|
|
} else {
|
|
$inputTz = new DateTimeZone($default_timezone);
|
|
}
|
|
$dt = new DateTime('now', $inputTz);
|
|
$dt->setDate($date['year'], $date['month'], $date['day']);
|
|
$dt->setTime(intval($date['hour']), intval($date['min']), intval($date['sec']));
|
|
$dt->setTimezone(new DateTimeZone($default_timezone));
|
|
$output = array(
|
|
$dt->format('Y-m-d'),
|
|
$dt->format('H:i'),
|
|
);
|
|
return $output;
|
|
}
|
|
// crmv@68357e
|
|
|
|
}
|
|
//crmv@38878
|