1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8//this script may only be included - so its better to die if called directly. 9if (strpos($_SERVER["SCRIPT_NAME"], basename(__FILE__)) !== false) { 10 header("location: index.php"); 11 exit; 12} 13 14if (! defined('ROLE_ORGANIZER')) { 15 define('ROLE_ORGANIZER', '6'); 16} 17if (! defined('weekInSeconds')) { 18 define('weekInSeconds', 604800); 19} 20 21/** 22 * 23 */ 24class CalendarLib extends TikiLib 25{ 26 /** 27 * @param $sort_mode 28 * @return string 29 */ 30 function convertSortMode($sort_mode, $fields = null) 31 { 32 $tmp = explode("_", $sort_mode); 33 if (count($tmp) == 2) { 34 if ($tmp[0] == "categoryName" || $tmp[0] == "locationName") { 35 return "name " . $tmp[1]; 36 } 37 } 38 return parent::convertSortMode($sort_mode, $fields); 39 } 40 41 /** 42 * @param int $offset 43 * @param $maxRecords 44 * @param string $sort_mode 45 * @param string $find 46 * @param string $user 47 * @return mixed 48 */ 49 function list_calendars($offset = 0, $maxRecords = -1, $sort_mode = 'name_asc', $find = '', $user = '') 50 { 51 $mid = ''; 52 $res = []; 53 $bindvars = []; 54 $join = ''; 55 56 if ($find) { 57 $mid = "and tcal.`name` like ?"; 58 $bindvars[] = '%' . $find . '%'; 59 } 60 61 if ($user) { 62 $mid = "and ( tcal.`user` = ? or tcali.`calendarInstanceId` IS NOT NULL )"; 63 $bindvars[] = $user; 64 $join .= ' left join `tiki_calendar_instances` tcali on tcal.calendarId = tcali.calendarId and tcali.`user` = ?'; 65 array_unshift($bindvars, $user); 66 } 67 68 $categlib = TikiLib::lib('categ'); 69 70 if ($jail = $categlib->get_jail()) { 71 $categlib->getSqlJoin($jail, 'calendar', 'tcal.`calendarId`', $join, $mid, $bindvars); 72 } 73 74 $query = "select tcal.* from `tiki_calendars` as tcal $join where 1=1 $mid order by tcal." . $this->convertSortMode($sort_mode); 75 $result = $this->query($query, $bindvars, $maxRecords, $offset); 76 $query_cant = "select count(*) from `tiki_calendars` as tcal $join where 1=1 $mid"; 77 $cant = $this->getOne($query_cant, $bindvars); 78 79 $res = []; 80 while ($r = $result->fetchRow()) { 81 $k = $r["calendarId"]; 82 $res2 = $this->query("select `optionName`,`value` from `tiki_calendar_options` where `calendarId`=?", [(int)$k]); 83 while ($r2 = $res2->fetchRow()) { 84 $r[$r2['optionName']] = $r2['value']; 85 } 86 if ($user) { 87 // override with per user instance values if those exist 88 $query = "select * from `tiki_calendar_instances` where calendarId = ? and user = ?"; 89 $instance_result = $this->query($query, [$r['calendarId'], $user]); 90 $instance = $instance_result->fetchRow(); 91 if ($instance) { 92 $r['name'] = $instance['name']; 93 $r['description'] = $instance['description']; 94 $r['order'] = $instance['order']; 95 $r['color'] = $instance['color']; 96 $r['timezone'] = $instance['timezone']; 97 $r['access'] = $instance['access']; 98 $r['calendarInstanceId'] = $instance['calendarInstanceId']; 99 } else { 100 $r['calendarInstanceId'] = 0; 101 } 102 } 103 $r['name'] = tra($r['name']); 104 $res["$k"] = $r; 105 } 106 $retval["data"] = $res; 107 $retval["cant"] = $cant; 108 return $retval; 109 } 110 111 /** 112 * @param $name 113 * @return mixed 114 */ 115 function get_calendarId_from_name($name) 116 { 117 $query = 'select `calendarId` from `tiki_calendars` where `name`=?'; 118 return $this->getOne($query, [$name]); 119 } 120 121 /** 122 * @param $calendarId 123 * @param $user 124 * @param $name 125 * @param $description 126 * @param array $customflags 127 * @param array $options 128 * @param $instanceId 129 * @return mixed 130 */ 131 function set_calendar($calendarId, $user, $name, $description, $customflags = [], $options = [], $instanceId = 0) 132 { 133 global $prefs; 134 $name = strip_tags($name); 135 $description = strip_tags($description); 136 $now = time(); 137 if ($instanceId > 0) { 138 // modification of a calendar instance 139 $finalEvent = 'tiki.calendar.update'; 140 $query = "update `tiki_calendar_instances` set `name`=?, `description`=?, `transparent`=?, `timezone`=?, `order`=?, `color`=? where `calendarInstanceId`=?"; 141 $bindvars = [$name,$description, @$options['transparent'], @$options['timezone'], @$options['order'], @$options['custombgcolor'], $instanceId]; 142 $result = $this->query($query, $bindvars); 143 } elseif ($calendarId > 0) { 144 // modification of a calendar 145 $finalEvent = 'tiki.calendar.update'; 146 $query = "update `tiki_calendars` set `name`=?, `user`=?, `description`=?, "; 147 $bindvars = [$name,$user,$description]; 148 foreach ($customflags as $k => $v) { 149 $query .= "`$k`=?, "; 150 $bindvars[] = $v; 151 } 152 $query .= "`lastmodif`=? where `calendarId`=?"; 153 $bindvars[] = $now; 154 $bindvars[] = $calendarId; 155 $result = $this->query($query, $bindvars); 156 // merge existing options in case passed array does not contain the full list (e.g. caldav integration) 157 $res = $this->query("select `optionName`,`value` from `tiki_calendar_options` where `calendarId`=?", [(int)$calendarId]); 158 while ($r = $res->fetchRow()) { 159 if (!isset($options[$r['optionName']])) { 160 $options[$r['optionName']] = $r['optionName'] == 'viewdays' ? unserialize($r['value']) : $r['value']; 161 } 162 } 163 } else { 164 // create a new calendar 165 $finalEvent = 'tiki.calendar.create'; 166 $query = 'insert into `tiki_calendars` (`name`,`user`,`description`,`created`,`lastmodif`'; 167 $bindvars = [$name,$user,$description,$now,$now]; 168 if (! empty($customflags)) { 169 $query .= ',`' . implode("`,`", array_keys($customflags)) . '`'; 170 } 171 $query .= ') values (?,?,?,?,?'; 172 if (! empty($customflags)) { 173 $query .= ',' . implode(",", array_fill(0, count($customflags), "?")); 174 foreach ($customflags as $k => $v) { 175 $bindvars[] = $v; 176 } 177 } 178 $query .= ')'; 179 $result = $this->query($query, $bindvars); 180 $calendarId = $this->GetOne("select `calendarId` from `tiki_calendars` where `created`=?", [$now]); 181 } 182 if ($instanceId == 0) { 183 $this->query('delete from `tiki_calendar_options` where `calendarId`=?', [(int)$calendarId]); 184 if (count($options)) { 185 if (isset($options['viewdays'])) { 186 $options['viewdays'] = serialize($options['viewdays']); 187 } else { 188 $options['viewdays'] = serialize($prefs['calendar_view_days']); 189 } 190 foreach ($options as $name => $value) { 191 $name = preg_replace('/[^-_a-zA-Z0-9]/', '', $name); 192 $this->query('insert into `tiki_calendar_options` (`calendarId`,`optionName`,`value`) values (?,?,?)', [(int)$calendarId,$name,$value]); 193 } 194 } 195 } 196 197 TikiLib::events()->trigger($finalEvent, [ 198 'type' => 'calendar', 199 'object' => $calendarId, 200 'user' => $GLOBALS['user'], 201 ]); 202 203 return $calendarId; 204 } 205 206 /** 207 * @param $calendarId 208 * @return array 209 */ 210 function get_calendar($calendarId) 211 { 212 global $prefs; 213 $res = $this->query("select * from `tiki_calendars` where `calendarId`=?", [(int)$calendarId]); 214 $cal = $res->fetchRow(); 215 $res2 = $this->query("select `optionName`,`value` from `tiki_calendar_options` where `calendarId`=?", [(int)$calendarId]); 216 while ($r = $res2->fetchRow()) { 217 $cal[$r['optionName']] = $r['value']; 218 } 219 if (! isset($cal['startday']) and ! isset($cal['endday'])) { 220 $cal['startday'] = 0; 221 $cal['endday'] = 23 * 60 * 60; 222 } 223 if (isset($cal['viewdays'])) { 224 $cal['viewdays'] = unserialize($cal['viewdays']); 225 } else { 226 $cal['viewdays'] = $prefs['calendar_view_days']; 227 } 228 $cal = array_merge(['allday' => 'n', 'nameoneachday' => 'n'], $cal); 229 return $cal; 230 } 231 232 function get_calendar_options($calendarId) 233 { 234 $opts = []; 235 $res = $this->query("select `optionName`,`value` from `tiki_calendar_options` where `calendarId`=?", [(int)$calendarId]); 236 while ($r = $res->fetchRow()) { 237 $opts[$r['optionName']] = $r['value']; 238 } 239 return $opts; 240 } 241 242 /** 243 * @param $calitemId 244 * @return mixed 245 */ 246 function get_calendarid($calitemId) 247 { 248 return $this->getOne("select `calendarId` from `tiki_calendar_items` where `calitemId`=?", [(int)$calitemId]); 249 } 250 251 /** 252 * @param $calendarId 253 */ 254 function drop_calendar($calendarId) 255 { 256 $transaction = $this->begin(); 257 258 // find and remove roles for all calendar items: 259 $query = "select `calitemId` from `tiki_calendar_items` where `calendarId`=?"; 260 $result = $this->query($query, [ $calendarId ]); 261 $allItemsFromCalendar = []; 262 while ($res = $result->fetchRow()) { 263 $allItemsFromCalendar[] = $res['calitemId']; 264 } 265 if (count($allItemsFromCalendar) > 0) { 266 $query = "delete from `tiki_calendar_roles` where `calitemId` in (" . implode(',', array_fill(0, count($allItemsFromCalendar), '?')) . ")"; 267 $this->query($query, [$allItemsFromCalendar]); 268 } 269 // remove calendar items, categories and locations: 270 $query = "delete from `tiki_calendar_items` where `calendarId`=?"; 271 $this->query($query, [$calendarId]); 272 $query = "delete from `tiki_calendar_categories` where `calendarId`=?"; 273 $this->query($query, [$calendarId]); 274 $query = "delete from `tiki_calendar_options` where `calendarId`=?"; 275 $this->query($query, [$calendarId]); 276 $query = "delete from `tiki_calendar_locations` where `calendarId`=?"; 277 $this->query($query, [$calendarId]); 278 $query = "delete from `tiki_calendar_instances` where `calendarId`=?"; 279 $this->query($query, [$calendarId]); 280 $query = "delete from `tiki_calendar_changes` where `calendarId`=?"; 281 $this->query($query, [$calendarId]); 282 // uncategorize calendar 283 $categlib = TikiLib::lib('categ'); 284 $categlib->uncategorize_object('calendar', $calendarId); 285 // now remove the calendar itself: 286 $query = "delete from `tiki_calendars` where `calendarId`=?"; 287 $dropResult = $this->query($query, [$calendarId]); 288 289 TikiLib::events()->trigger('tiki.calendar.delete', [ 290 'type' => 'calendar', 291 'object' => $calendarId, 292 'user' => $GLOBALS['user'], 293 ]); 294 295 $transaction->commit(); 296 return $dropResult; 297 } 298 299 /* tsart ans tstop are in user time - the data base is in server time */ 300 /** 301 * @param $calIds 302 * @param $user 303 * @param $tstart 304 * @param $tstop 305 * @param $offset 306 * @param $maxRecords 307 * @param string $sort_mode 308 * @param string $find 309 * @param array $customs 310 * @return array 311 */ 312 function list_raw_items($calIds, $user, $tstart, $tstop, $offset, $maxRecords, $sort_mode = 'start_asc', $find = '', $customs = []) 313 { 314 315 if (count($calIds) == 0) { 316 return []; 317 } 318 319 $where = []; 320 $bindvars = []; 321 foreach ($calIds as $calendarId) { 322 $where[] = "i.`calendarId`=?"; 323 $bindvars[] = (int)$calendarId; 324 } 325 326 $cond = "(" . implode(" or ", $where) . ") and "; 327 $cond .= " ((i.`start` > ? and i.`end` < ?) or (i.`start` < ? and i.`end` > ?))"; 328 329 $bindvars[] = (int)$tstart; 330 $bindvars[] = (int)$tstop; 331 $bindvars[] = (int)$tstop; 332 $bindvars[] = (int)$tstart; 333 334 $cond .= " and ((c.`personal`='y' and i.`user`=?) or c.`personal` != 'y')"; 335 $bindvars[] = $user; 336 337 $query = "select i.`calitemId` as `calitemId` "; 338 $queryCompl = ''; 339 $joinCompl = ''; 340 $tblRef = 'i.'; 341 342 if (substr($sort_mode, 0, 12) == "categoryName") { 343 $queryCompl = "`tiki_calendar_categories` as compl right join "; 344 $joinCompl = " on i.categoryId = compl.calcatid "; 345 $tblRef = "compl."; 346 } elseif (substr($sort_mode, 0, 12) == "locationName") { 347 $queryCompl = "`tiki_calendar_locations` as compl right join "; 348 $joinCompl = " on i.locationId = compl.callocid "; 349 $tblRef = "compl."; 350 } 351 352 $query .= 'from ' . $queryCompl . '`tiki_calendar_items` as i ' . $joinCompl . 353 " left join `tiki_calendars` as c on i.`calendarId`=c.`calendarId`" . 354 " where ($cond)" . 355 " order by " . 356 $tblRef . $this->convertSortMode($sort_mode) . ',i.' . $this->convertSortMode('calendarId_asc'); 357 358 $result = $this->query($query, $bindvars, $maxRecords, $offset); 359 $ret = []; 360 while ($res = $result->fetchRow()) { 361 $ret[] = $this->get_item($res["calitemId"], $customs); 362 } 363 return $ret; 364 } 365 366 /** 367 * @param $calIds 368 * @param $user 369 * @param $tstart 370 * @param $tstop 371 * @param $offset 372 * @param $maxRecords 373 * @param string $sort_mode 374 * @param string $find 375 * @param array $customs 376 * @return array 377 */ 378 function list_items($calIds, $user, $tstart, $tstop, $offset, $maxRecords, $sort_mode = 'start_asc', $find = '', $customs = []) 379 { 380 global $tiki_p_change_events, $prefs; 381 $ret = []; 382 $list = $this->list_raw_items($calIds, $user, $tstart, $tstop, $offset, $maxRecords, $sort_mode, $find, $customs); 383 foreach ($list as $res) { 384 $mloop = TikiLib::date_format("%m", $res['start']); 385 $dloop = TikiLib::date_format("%d", $res['start']); 386 $yloop = TikiLib::date_format("%Y", $res['start']); 387 $dstart = TikiLib::make_time(0, 0, 0, $mloop, $dloop, $yloop); 388 $dend = TikiLib::make_time(0, 0, 0, TikiLib::date_format("%m", $res['end']), TikiLib::date_format("%d", $res['end']), TikiLib::date_format("%Y", $res['end'])); 389 $tstart = TikiLib::date_format("%H%M", $res["start"]); 390 $tend = TikiLib::date_format("%H%M", $res["end"]); 391 for ($i = $dstart; $i <= $dend; $i = TikiLib::make_time(0, 0, 0, $mloop, ++$dloop, $yloop)) { 392 /* $head is in user time */ 393 if ($dstart == $dend) { 394 $head = TikiLib::date_format($prefs['short_time_format'], $res["start"]) . " - " . TikiLib::date_format($prefs['short_time_format'], $res["end"]); 395 } elseif ($i == $dstart) { 396 $head = TikiLib::date_format($prefs['short_time_format'], $res["start"]) . " ..."; 397 } elseif ($i == $dend) { 398 $head = " ... " . TikiLib::date_format($prefs['short_time_format'], $res["end"]); 399 } else { 400 $head = " ... " . tra("continued") . " ... "; 401 } 402 403 /* $i is timestamp unix of the beginning of a day */ 404 $ret["$i"][] = [ 405 'result' => $res, 406 'calitemId' => $res['calitemId'], 407 'calname' => tra($res['calname']), 408 'time' => $tstart, /* user time */ 409 'end' => $tend, /* user time */ 410 'type' => $res['status'], 411 'web' => $res['url'], 412 'startTimeStamp' => $res['start'], 413 'endTimeStamp' => $res['end'], 414 'nl' => $res['nlId'], 415 'prio' => $res['priority'], 416 'location' => $res['locationName'], 417 'category' => $res['categoryName'], 418 'name' => $res['name'], 419 'head' => $head, 420 'parsedDescription' => TikiLib::lib('parser')->parse_data($res['description'], ['is_html' => $prefs['calendar_description_is_html'] === 'y']), 421 'description' => str_replace("\n|\r", '', $res['description']), 422 'calendarId' => $res['calendarId'], 423 'status' => $res['status'], 424 'user' => $res['user'] 425 ]; 426 } 427 } 428 return $ret; 429 } 430 431 /** 432 * @param $calIds 433 * @param $user 434 * @param $tstart 435 * @param $tstop 436 * @param $offset 437 * @param $maxRecords 438 * @param string $sort_mode 439 * @param string $find 440 * @param array $customs 441 * @return array 442 */ 443 function list_items_by_day($calIds, $user, $tstart, $tstop, $offset, $maxRecords, $sort_mode = 'start_asc', $find = '', $customs = []) 444 { 445 global $prefs; 446 $ret = []; 447 $list = $this->list_raw_items($calIds, $user, $tstart, $tstop, $offset, $maxRecords, $sort_mode, $find, $customs); 448 foreach ($list as $res) { 449 $mloop = TikiLib::date_format("%m", $res['start']); 450 $dloop = TikiLib::date_format("%d", $res['start']); 451 $yloop = TikiLib::date_format("%Y", $res['start']); 452 $dstart = TikiLib::make_time(0, 0, 0, $mloop, $dloop, $yloop); 453 $dend = TikiLib::make_time(0, 0, 0, TikiLib::date_format("%m", $res['end']), TikiLib::date_format("%d", $res['end']), TikiLib::date_format("%Y", $res['end'])); 454 $tstart = TikiLib::date_format("%H%M", $res["start"]); 455 $tend = TikiLib::date_format("%H%M", $res["end"]); 456 for ($i = $dstart; $i <= $dend; $i = TikiLib::make_time(0, 0, 0, $mloop, ++$dloop, $yloop)) { 457 /* $head is in user time */ 458 if ($res['allday'] == '1') { 459 $head = tra('All day'); 460 } elseif ($dstart == $dend) { 461 $head = TikiLib::date_format($prefs['short_time_format'], $res["start"]) . " - " . TikiLib::date_format($prefs['short_time_format'], $res["end"]); 462 } elseif ($i == $dstart) { 463 $head = TikiLib::date_format($prefs['short_time_format'], $res["start"]) . " ..."; 464 } elseif ($i == $dend) { 465 $head = " ... " . TikiLib::date_format($prefs['short_time_format'], $res["end"]); 466 } else { 467 $head = " ... " . tra("continued") . " ... "; 468 } 469 470 /* $i is timestamp unix of the beginning of a day */ 471 $j = (isset($ret[$i]) && is_array($ret[$i])) ? count($ret[$i]) : 0; 472 473 $ret[$i][$j] = $res; 474 $ret[$i][$j]['head'] = $head; 475 $ret[$i][$j]['parsedDescription'] = TikiLib::lib('parser')->parse_data($res["description"], ['is_html' => $prefs['calendar_description_is_html'] === 'y']); 476 $ret[$i][$j]['description'] = str_replace("\n|\r", "", $res["description"]); 477 $ret[$i][$j]['visible'] = 'y'; 478 $ret[$i][$j]['where'] = $res['locationName']; 479 480 $ret[$i][$j]['show_description'] = 'y'; 481 /* 'time' => $tstart, /* user time */ 482 /* 'end' => $tend, /* user time */ 483 484 $ret[$i][$j]['group_description'] = htmlspecialchars($res['name']) . '<span class="calgrouptime">, ' . $head . '</span>'; 485 } 486 } 487 return $ret; 488 } 489 490 /** 491 * @param $calitemId 492 * @param array $customs 493 * @return mixed 494 */ 495 function get_item($calitemId, $customs = []) 496 { 497 global $user, $prefs; 498 499 $query = "select i.`calitemId` as `calitemId`, i.`calendarId` as `calendarId`, i.`user` as `user`, i.`start` as `start`, i.`end` as `end`, t.`name` as `calname`, "; 500 $query .= "i.`locationId` as `locationId`, l.`name` as `locationName`, i.`categoryId` as `categoryId`, c.`name` as `categoryName`, i.`priority` as `priority`, i.`nlId` as `nlId`, i.`uid` as `uid`, i.`uri` as `uri`, "; 501 $query .= "i.`status` as `status`, i.`url` as `url`, i.`lang` as `lang`, i.`name` as `name`, i.`description` as `description`, i.`created` as `created`, i.`lastmodif` as `lastModif`, i.`allday` as `allday`, "; 502 $query .= "t.`customlocations`, t.`customcategories`, t.`customlanguages`, t.`custompriorities`, t.`customsubscription`, t.`customparticipants`, i.`recurrenceId`, i.`recurrenceStart`, r.`uid` as `recurrenceUid`"; 503 504 foreach ($customs as $k => $v) { 505 $query .= ", i.`$k` as `$v`"; 506 } 507 508 $query .= " from `tiki_calendar_items` as i left join `tiki_calendar_locations` as l on i.`locationId`=l.`callocId` left join `tiki_calendar_recurrence` as r on i.`recurrenceId` = r.`recurrenceId`"; 509 $query .= " left join `tiki_calendar_categories` as c on i.`categoryId`=c.`calcatId` left join `tiki_calendars` as t on i.`calendarId`=t.`calendarId` where `calitemId`=?"; 510 $result = $this->query($query, [(int)$calitemId]); 511 $res = $result->fetchRow(); 512 513 if ($res) { 514 $query 515 = "select `username`, `role`, `partstat` from `tiki_calendar_roles` where `calitemId`=? order by `role`"; 516 $rezult = $this->query($query, [(int)$calitemId]); 517 $ppl = []; 518 $org = []; 519 while ($rez = $rezult->fetchRow()) { 520 if ($rez["role"] == ROLE_ORGANIZER) { 521 $org[] = $rez["username"]; 522 } elseif ($rez["username"]) { 523 $email = TikiLib::lib('user')->get_user_email($rez['username']); 524 if (! $email) { 525 $email = $rez["username"]; 526 } 527 $ppl[] = [ 528 'username' => $rez["username"], 529 'email' => $email, 530 'role' => $rez["role"], 531 'partstat' => $rez['partstat'] 532 ]; 533 } 534 } 535 $res["participants"] = $ppl; 536 $res["selected_participants"] = array_map(function($role){ return $role['username']; }, $ppl); 537 $res["organizers"] = $org; 538 $res['date_start'] = (int)$res['start']; 539 $res['date_end'] = (int)$res['end']; 540 $res['duration'] = $res['end'] - $res['start']; 541 $parserlib = TikiLib::lib('parser'); 542 $res['parsed'] = $parserlib->parse_data( 543 $res['description'], 544 ['is_html' => $prefs['calendar_description_is_html'] === 'y'] 545 ); 546 $res['parsedName'] = $parserlib->parse_data($res['name']); 547 } 548 return $res; 549 } 550 551 function get_item_by_uri($uri) 552 { 553 $result = $this->query("select calitemId from `tiki_calendar_items` where uri = ?", [$uri]); 554 $row = $result->fetchRow(); 555 if ($row) { 556 return $this->get_item($row['calitemId']); 557 } 558 $result = $this->query("select recurrenceId from `tiki_calendar_recurrence` where uri = ?", [$uri]); 559 $row = $result->fetchRow(); 560 if ($row) { 561 return new \CalRecurrence($row['recurrenceId']); 562 } 563 return null; 564 } 565 566 /** 567 * @param $user 568 * @param $calitemId 569 * @param $data 570 * @param array $customs 571 * @param bool $isBulk 572 * 573 * @return bool 574 * @throws Exception 575 */ 576 function set_item($user, $calitemId, $data, $customs = [], $isBulk = false) 577 { 578 global $prefs; 579 if (! isset($data['calendarId'])) { 580 return false; 581 } 582 $caldata = $this->get_calendar($data['calendarId']); 583 584 if ($caldata['customlocations'] == 'y') { 585 if (! $data["locationId"] and ! $data["newloc"]) { 586 $data['locationId'] = 0; 587 } 588 if (trim($data["newloc"])) { 589 $bindvars = [(int)$data["calendarId"],trim($data["newloc"])]; 590 $query = "delete from `tiki_calendar_locations` where `calendarId`=? and `name`=?"; 591 $this->query($query, $bindvars, -1, -1, false); 592 $query = "insert into `tiki_calendar_locations` (`calendarId`,`name`) values (?,?)"; 593 $this->query($query, $bindvars); 594 $data["locationId"] = $this->getOne("select `callocId` from `tiki_calendar_locations` where `calendarId`=? and `name`=?", $bindvars); 595 } 596 } else { 597 $data['locationId'] = 0; 598 } 599 600 if ($caldata['customcategories'] == 'y') { 601 if (! $data["categoryId"] and ! $data["newcat"]) { 602 $data['categoryId'] = 0; 603 } 604 if (trim($data["newcat"])) { 605 $query = "delete from `tiki_calendar_categories` where `calendarId`=? and `name`=?"; 606 $bindvars = [(int)$data["calendarId"],trim($data["newcat"])]; 607 $this->query($query, $bindvars, -1, -1, false); 608 $query = "insert into `tiki_calendar_categories` (`calendarId`,`name`) values (?,?)"; 609 $this->query($query, $bindvars); 610 $data["categoryId"] = $this->getOne("select `calcatId` from `tiki_calendar_categories` where `calendarId`=? and `name`=?", $bindvars); 611 } 612 } else { 613 $data['categoryId'] = 0; 614 } 615 616 if ($caldata['customparticipants'] == 'y') { 617 $roles = []; 618 if ($data["organizers"]) { 619 if (is_string($data['organizers'])) { 620 $data['organizers'] = preg_split('/\s*,\s*/', $data['organizers']); 621 } 622 foreach ($data['organizers'] as $o) { 623 if (trim($o)) { 624 $roles[] = [ 625 'username' => trim($o), 626 'role' => ROLE_ORGANIZER 627 ]; 628 } 629 } 630 } 631 if ($data["participants"]) { 632 foreach ($data['participants'] as $pa) { 633 if (trim($pa['username'])) { 634 $roles[] = $pa; 635 } 636 } 637 } 638 } 639 640 if ($caldata['customlanguages'] == 'y') { 641 if (! isset($data['lang'])) { 642 $data['lang'] = ''; 643 } 644 } else { 645 $data['lang'] = ''; 646 } 647 648 if ($caldata['custompriorities'] == 'y') { 649 if (! isset($data['priority'])) { 650 $data['priority'] = 0; 651 } 652 } else { 653 $data['priority'] = 0; 654 } 655 656 if ($caldata['customsubscription'] == 'y') { 657 if (! isset($data['nlId'])) { 658 $data['nlId'] = 0; 659 } 660 } else { 661 $data['nlId'] = 0; 662 } 663 664 $data['user'] = $user; 665 666 $realcolumns = ['calitemId', 'calendarId', 'start', 'end', 'locationId', 'categoryId', 'nlId', 'priority', 'uri', 'uid', 667 'status', 'url', 'lang', 'name', 'description', 'user', 'created', 'lastmodif', 'allday', 'recurrenceId', 'changed', 'recurrenceStart']; 668 foreach ($customs as $custom) { 669 $realcolumns[] = $custom; 670 } 671 672 if ($calitemId) { 673 $finalEvent = 'tiki.calendaritem.update'; 674 675 $oldData = $this->get_item($calitemId); 676 if (empty($oldData)) { 677 return false; 678 } 679 $data = array_merge($oldData, $data); 680 $data['lastmodif'] = $this->now; 681 682 $l = []; 683 $r = []; 684 685 foreach ($data as $k => $v) { 686 if (! in_array($k, $realcolumns)) { 687 continue; 688 } 689 $l[] = "`$k`=?"; 690 $r[] = $v; 691 } 692 693 if (! empty($data['changed']) && empty($data['recurrenceStart'])) { 694 $l[] = "`recurrenceStart` = ?"; 695 $r[] = $oldData['start']; 696 } 697 698 if (! empty($data['recurrenceStart']) && empty($data['changed'])) { 699 $l[] = "`changed` = 1"; 700 } 701 702 $query = 'UPDATE `tiki_calendar_items` SET ' . implode(',', $l) . ' WHERE `calitemId`=?'; 703 $r[] = (int)$calitemId; 704 705 $result = $this->query($query, $r); 706 $this->add_change($data['calendarId'], $calitemId, 2); 707 708 $trackerItemsIds = $this->getAttachedTrackerItems($calitemId); 709 710 require_once 'lib/search/refresh-functions.php'; 711 foreach ($trackerItemsIds as $trackerItemId) { 712 refresh_index('trackeritem', $trackerItemId); 713 } 714 715 } else { 716 $finalEvent = 'tiki.calendaritem.create'; 717 $new = true; 718 $oldData = null; 719 $data['lastmodif'] = $this->now; 720 $data['created'] = $this->now; 721 722 $l = []; 723 $r = []; 724 $z = []; 725 726 foreach ($data as $k => $v) { 727 if (! in_array($k, $realcolumns)) { 728 continue; 729 } 730 $l[] = "`$k`"; 731 $z[] = '?'; 732 $r[] = ($k == 'priority') ? (string)$v : $v; 733 } 734 735 $query = 'INSERT INTO `tiki_calendar_items` (' . implode(',', $l) . ') VALUES (' . implode(',', $z) . ')'; 736 $result = $this->query($query, $r); 737 $calitemId = $this->GetOne("SELECT MAX(`calitemId`) FROM `tiki_calendar_items` where `calendarId`=?", [$data["calendarId"]]); 738 $this->add_change($data['calendarId'], $calitemId, 1); 739 } 740 741 if ($calitemId) { 742 $wikilib = TikiLib::lib('wiki'); 743 $wikilib->update_wikicontent_relations($data['description'], 'calendar event', $calitemId); 744 $wikilib->update_wikicontent_links($data['description'], 'calendar event', $calitemId); 745 $existing_roles = $this->fetchAll('select * from `tiki_calendar_roles` where `calitemId`=?', [$calitemId]); 746 $query = "delete from `tiki_calendar_roles` where `calitemId`=?"; 747 $this->query($query, [(int)$calitemId]); 748 } else { 749 $existing_roles = []; 750 } 751 752 foreach ($roles as $role) { 753 if (empty($role['partstat'])) { 754 foreach ($existing_roles as $erole) { 755 if ($role['username'] == $erole['username']) { 756 $role['partstat'] = $erole['partstat']; 757 } 758 } 759 } 760 $query = "insert into `tiki_calendar_roles` (`calitemId`,`username`,`role`,`partstat`) values (?,?,?,?)"; 761 $this->query($query, [(int)$calitemId, $role['username'], $role['role'] ?? 0, $role['partstat'] ?? null]); 762 } 763 764 if ($prefs['feature_user_watches'] == 'y') { 765 $this->watch($calitemId, $data); 766 } 767 768 TikiLib::events()->trigger($finalEvent, [ 769 'type' => 'calendaritem', 770 'object' => $calitemId, 771 'user' => $GLOBALS['user'], 772 'bulk_import' => $isBulk, 773 'old_data' => $oldData, 774 'process_itip' => !empty($data['process_itip']) 775 ]); 776 777 return $calitemId; 778 } 779 780 /** 781 * Get all tracker items attached to a calender item 782 * 783 * @param $calitemId 784 * 785 * @return array 786 * @throws Exception 787 */ 788 public function getAttachedTrackerItems($calitemId) 789 { 790 $trackerItems = []; 791 $attributes = TikiLib::lib('attribute')->find_objects_with('tiki.calendar.item', $calitemId); 792 793 foreach ($attributes as $attribute) { 794 $trackerItems[] = (int)$attribute['itemId']; 795 } 796 797 return $trackerItems; 798 } 799 800 /** 801 * @param $calitemId 802 * @param $data 803 */ 804 function watch($calitemId, $data) 805 { 806 global $prefs, $user; 807 $smarty = TikiLib::lib('smarty'); 808 $tikilib = TikiLib::lib('tiki'); 809 $nots = $tikilib->get_event_watches('calendar_changed', $data['calendarId']); 810 811 if ($prefs['calendar_watch_editor'] != "y" || $prefs['user_calendar_watch_editor'] != "y") { 812 for ($i = count($nots) - 1; $i >= 0; --$i) { 813 if ($nots[$i]['user'] == $data["user"]) { 814 unset($nots[$i]); 815 break; 816 } 817 } 818 } 819 820 if ($prefs['feature_daily_report_watches'] == 'y') { 821 $reportsManager = Reports_Factory::build('Reports_Manager'); 822 $reportsManager->addToCache($nots, ['event' => 'calendar_changed', 'calitemId' => $calitemId, 'user' => $user]); 823 } 824 825 if ($nots) { 826 include_once('lib/webmail/tikimaillib.php'); 827 $mail = new TikiMail(); 828 $smarty->assign('mail_new', $new); 829 $smarty->assign('mail_data', $data); 830 $smarty->assign('mail_calitemId', $calitemId); 831 $foo = parse_url($_SERVER["REQUEST_URI"]); 832 $machine = $tikilib->httpPrefix(true) . dirname($foo["path"]); 833 $machine = preg_replace("!/$!", "", $machine); // just incase 834 $smarty->assign('mail_machine', $machine); 835 $defaultLanguage = $prefs['site_language']; 836 foreach ($nots as $not) { 837 $mail->setUser($not['user']); 838 $mail_data = $smarty->fetchLang($defaultLanguage, "mail/user_watch_calendar_subject.tpl"); 839 $mail->setSubject($mail_data); 840 $mail_data = $smarty->fetchLang($defaultLanguage, "mail/user_watch_calendar.tpl"); 841 $mail->setText($mail_data); 842 $mail->send([$not['email']]); 843 } 844 } 845 } 846 847 /** 848 * @param $user 849 * @param $calitemId 850 */ 851 function drop_item($user, $calitemId, $isBulk = false, $process_itip = true) 852 { 853 if ($calitemId) { 854 $item = $this->get_item($calitemId); 855 $query = "delete from `tiki_calendar_items` where `calitemId`=?"; 856 $this->query($query, [$calitemId]); 857 $query = "delete from `tiki_calendar_roles` where `calitemId`=?"; 858 $this->query($query, [$calitemId]); 859 $this->remove_object('calendar event', $calitemId); 860 TikiLib::lib('calendar')->add_change($item['calendarId'], $calitemId, 3); 861 862 TikiLib::events()->trigger('tiki.calendaritem.delete', [ 863 'type' => 'calendaritem', 864 'object' => $calitemId, 865 'user' => $user, 866 'bulk_import' => $isBulk, 867 'old_data' => $item, 868 'process_itip' => $process_itip 869 ]); 870 } 871 } 872 873 /** 874 * @param $calitemId 875 * @param int $delay 876 */ 877 function move_item($calitemId, $delay = 0) 878 { 879 if ($delay != 0) { 880 $query = 'UPDATE `tiki_calendar_items` set start = start + ?, end = end + ? WHERE `calitemId`=?'; 881 $this->query($query, [$delay,$delay,$calitemId]); 882 } 883 } 884 885 /** 886 * @param $calitemId 887 * @param int $delay 888 */ 889 function resize_item($calitemId, $delay = 0) 890 { 891 if ($delay != 0) { 892 $query = 'UPDATE `tiki_calendar_items` set end = end + ? WHERE `calitemId`=?'; 893 $this->query($query, [$delay,$calitemId]); 894 } 895 } 896 897 /** 898 * @param $calendarId 899 * @return array 900 */ 901 function list_locations($calendarId) 902 { 903 $res = []; 904 if ($calendarId > 0) { 905 $query = "select `callocId` as `locationId`, `name` from `tiki_calendar_locations` where `calendarId`=? order by `name`"; 906 return $this->fetchAll($query, [$calendarId]); 907 } 908 return $res; 909 } 910 911 /** 912 * @param $calendarId 913 * @return array 914 */ 915 function list_categories($calendarId) 916 { 917 $res = []; 918 if ($calendarId > 0) { 919 $query = "select `calcatId` as `categoryId`, `name` from `tiki_calendar_categories` where `calendarId`=? order by `name`"; 920 return $this->fetchAll($query, [$calendarId]); 921 } 922 return $res; 923 } 924 925 // Returns the last $maxrows of modified events for an 926 // optional $calendarId 927 /** 928 * @param $maxrows 929 * @param int $calendarId 930 * @return mixed 931 */ 932 function last_modif_events($maxrows = -1, $calendarId = 0) 933 { 934 935 if ($calendarId > 0) { 936 $cond = "where `calendarId` = ? "; 937 $bindvars = [$calendarId]; 938 } else { 939 $cond = ''; 940 $bindvars = []; 941 } 942 943 $query = "select `start`, `name`, `calitemId`, `calendarId`, `user`, `lastModif` from `tiki_calendar_items` " . $cond . "order by " . $this->convertSortMode('lastModif_desc'); 944 945 return $this->fetchAll($query, $bindvars, $maxrows, 0); 946 } 947 948 /** 949 * @param $fname 950 * @param $calendarId 951 * @return int 952 */ 953 function importCSV($fname, $calendarId) 954 { 955 global $user; 956 $smarty = TikiLib::lib('smarty'); 957 $fields = false; 958 if ($fhandle = fopen($fname, 'r')) { 959 $fields = fgetcsv($fhandle, 1000); 960 } 961 if ($fields === false || ! array_search('name', $fields)) { 962 $smarty->assign('msg', tra("The file has incorrect syntax or is not a CSV file")); 963 $smarty->display("error.tpl"); 964 die; 965 } 966 $nb = 0; 967 while (($data = fgetcsv($fhandle, 1000)) !== false) { 968 $d = [ 969 'calendarId' => $calendarId, 970 'calitemId' => '0', 971 'name' => '', 972 'description' => '', 973 'locationId' => '', 974 'organizers' => '', 975 'participants' => '', 976 'status' => '1', 977 'priority' => '5', 978 'categoryId' => '0', 979 'newloc' => '0', 980 'newcat' => '', 981 'nlId' => '', 982 'lang' => '', 983 'start' => '', 984 'end' => '' 985 ]; 986 987 foreach ($fields as $field) { 988 $d[$field] = $data[array_search($field, $fields)]; 989 } 990 991 if (isset($d["subject"]) && empty($d["name"])) { 992 $d["name"] = $d["subject"]; 993 } 994 if (isset($d['start date'])) { 995 if (isset($d['start time'])) { 996 $d['start'] = strtotime($d['start time'], strtotime($d['start date'])); 997 } else { 998 $d['start'] = strtotime($d['start date']); 999 } 1000 } 1001 if (isset($d['end date'])) { 1002 if (isset($d['end time'])) { 1003 $d['end'] = strtotime($d['end time'], strtotime($d['end date'])); 1004 } else { 1005 $d['end'] = strtotime($d['end date']); 1006 } 1007 } 1008 1009 if ($d['organizers']) { 1010 $d['organizers'] = explode(',', $d['organizers']); 1011 } 1012 1013 if ($d['participants']) { 1014 $d['participants'] = array_map(function($part){ 1015 $part = explode(':', $part); 1016 if (count($part) > 1) { 1017 $part = [ 1018 'username' => $part[1], 1019 'role' => $part[0] 1020 ]; 1021 } else { 1022 $part = [ 1023 'username' => $part[0] 1024 ]; 1025 } 1026 return $part; 1027 }, explode(',', $d['participants'])); 1028 } 1029 1030 // TODO do a replace if name, calendarId, start, end exists 1031 if (! empty($d['start']) && ! empty($d['end'])) { 1032 $this->set_item($user, 0, $d); 1033 ++$nb; 1034 } 1035 } 1036 fclose($fhandle); 1037 return $nb; 1038 } 1039 1040 /** 1041 * Returns an array of a maximum of $maxrows upcoming (but possibly past) events in the given $order. 1042 * If $calendarId is set, events not in the specified calendars are filtered. $calendarId 1043 * can be a calendar identifier or an array of calendar identifiers. If $maxDaysEnd is 1044 * a natural, events ending after $maxDaysEnd days are filtered. If $maxDaysStart is a 1045 * natural, events starting after $maxDaysStart days are filtered. 1046 * Events ending more than $priorDays in the past are filtered. 1047 * 1048 * Each event is represented by a string-indexed array with indices start, end, 1049 * name, description, calitemId, calendarId, user, lastModif, url, allday 1050 * in the same format as tiki_calendar_items fields, as well as location 1051 * for the event's locations, parsed for the parsed description and category 1052 * for the event's calendar category. 1053 * 1054 */ 1055 1056 //Pagination 1057 function upcoming_events($maxrows = -1, $calendarId = null, $maxDaysEnd = -1, $order = 'start_asc', $priorDays = 0, $maxDaysStart = -1, $start = 0) 1058 { 1059 1060 global $prefs; 1061 $cond = ''; 1062 $bindvars = []; 1063 if (isset($calendarId)) { 1064 if (is_array($calendarId)) { 1065 $cond = $cond . "and (0=1"; 1066 foreach ($calendarId as $id) { 1067 $cond = $cond . " or i.`calendarId` = ? "; 1068 } 1069 $cond = $cond . ")"; 1070 $bindvars = array_merge($bindvars, $calendarId); 1071 } else { 1072 $cond = $cond . " and i.`calendarId` = ? "; 1073 $bindvars[] = $calendarId; 1074 } 1075 } 1076 $cond .= " and `end` >= (unix_timestamp(now()) - ?*3600*24)"; 1077 $bindvars[] = $priorDays; 1078 1079 1080 if ($maxDaysEnd > 0) { 1081 $maxSeconds = ($maxDaysEnd * 24 * 60 * 60); 1082 $cond .= " and `end` <= (unix_timestamp(now())) +" . $maxSeconds; 1083 } 1084 if ($maxDaysStart > 0) { 1085 $maxSeconds = ($maxDaysStart * 24 * 60 * 60); 1086 $cond .= " and `start` <= (unix_timestamp(now())) +" . $maxSeconds; 1087 } 1088 $ljoin = "left join `tiki_calendar_locations` as l on i.`locationId`=l.`callocId` left join `tiki_calendar_categories` as c on i.`categoryId`=c.`calcatId`"; 1089 1090 $query = "select i.`start`, i.`end`, i.`name`, i.`description`, i.`status`," . 1091 " i.`calitemId`, i.`calendarId`, i.`user`, i.`lastModif`, i.`url`," . 1092 " l.`name` as location, i.`allday`, c.`name` as category" . 1093 " from `tiki_calendar_items` i $ljoin" . 1094 " where 1=1 " . $cond . 1095 " order by " . $this->convertSortMode($order); 1096 1097 $ret = $this->fetchAll($query, $bindvars, $maxrows, $start); 1098 1099 $query_cant = "select count(*) from `tiki_calendar_items` i $ljoin where 1=1 " . $cond . " GROUP BY i.calitemId order by " . $this->convertSortMode($order); 1100 $cant = $this->getOne($query_cant, $bindvars); 1101 1102 foreach ($ret as &$res) { 1103 $res['parsed'] = TikiLib::lib('parser')->parse_data($res['description'], ['is_html' => $prefs['calendar_description_is_html'] === 'y']); 1104 } 1105 1106 $retval = []; 1107 $retval['data'] = $ret; 1108 $retval['cant'] = $cant; 1109 return $retval; 1110 } 1111 1112 /** 1113 * @param $maxrows 1114 * @param null $calendarId 1115 * @param $maxDaysEnd 1116 * @param string $order 1117 * @param int $priorDays 1118 * @param $maxDaysStart 1119 * @param int $start 1120 * @return array 1121 */ 1122 function all_events($maxrows = -1, $calendarId = null, $maxDaysEnd = -1, $order = 'start_asc', $priorDays = 0, $maxDaysStart = -1, $start = 0, $itemIds = []) 1123 { 1124 global $prefs; 1125 $cond = ''; 1126 $bindvars = []; 1127 if (isset($calendarId)) { 1128 if (is_array($calendarId)) { 1129 $cond = $cond . "and (0=1"; 1130 foreach ($calendarId as $id) { 1131 $cond = $cond . " or i.`calendarId` = ? "; 1132 } 1133 $cond = $cond . ")"; 1134 $bindvars = array_merge($bindvars, $calendarId); 1135 } else { 1136 $cond = $cond . " and i.`calendarId` = ? "; 1137 $bindvars[] = $calendarId; 1138 } 1139 } 1140 if (count($itemIds) > 0) { 1141 $cond .= " and i.calitemId in (".implode(',', array_fill(0, count($itemIds), '?')).")"; 1142 $bindvars = array_merge($bindvars, $itemIds); 1143 } 1144 $condition = ''; 1145 $cond .= " and $condition (unix_timestamp(now()) - ?*3600*34)"; 1146 $bindvars[] = $priorDays; 1147 1148 if ($maxDaysEnd > 0) { 1149 $maxSeconds = ($maxDaysEnd * 24 * 60 * 60); 1150 $cond .= " and `end` <= (unix_timestamp(now())) +" . $maxSeconds; 1151 } 1152 if ($maxDaysStart > 0) { 1153 $maxSeconds = ($maxDaysStart * 24 * 60 * 60); 1154 $cond .= " and `start` <= (unix_timestamp(now())) +" . $maxSeconds; 1155 } 1156 $ljoin = "left join `tiki_calendar_locations` as l on i.`locationId`=l.`callocId` left join `tiki_calendar_categories` as c on i.`categoryId`=c.`calcatId`"; 1157 1158 $query = "select i.`start`, i.`end`, i.`name`, i.`description`, i.`status`," . 1159 " i.`calitemId`, i.`calendarId`, i.`user`, i.`lastModif`, i.`url`," . 1160 " l.`name` as location, i.`allday`, c.`name` as category, i.`created`, i.`priority`, i.`uid`" . 1161 " from `tiki_calendar_items` i" . 1162 " $ljoin" . 1163 " where 1=1 " . $cond . 1164 " order by " . $this->convertSortMode($order); 1165 1166 $ret = $this->fetchAll($query, $bindvars, $maxrows, $start); 1167 1168 $query_cant = "select count(*) from `tiki_calendar_items` i $ljoin where 1=1 " . $cond . " order by " . $this->convertSortMode($order); 1169 $cant = $this->getOne($query_cant, $bindvars); 1170 1171 foreach ($ret as &$res) { 1172 $res['parsed'] = TikiLib::lib('parser')->parse_data($res['description'], ['is_html' => $prefs['calendar_description_is_html'] === 'y']); 1173 } 1174 1175 $retval = []; 1176 $retval['data'] = $ret; 1177 $retval['cant'] = $cant; 1178 return $retval; 1179 } 1180 1181 public function get_events($calendarId, $itemIdsOrUris = [], $componenttype = null, $start = null, $end = null, $recurrenceId = null, $changed = null) 1182 { 1183 global $prefs; 1184 1185 $cond = ' and i.calendarId = ?'; 1186 $bindvars = [$calendarId]; 1187 1188 if (count($itemIdsOrUris) > 0) { 1189 $recurrences = array_filter($itemIdsOrUris, function($uri) { 1190 return substr($uri, 0, 1) == 'r'; 1191 }); 1192 $itemIdsOrUris = array_diff($itemIdsOrUris, $recurrences); 1193 if (! $itemIdsOrUris) { 1194 $itemIdsOrUris[] = ''; 1195 } 1196 $recurrences = array_map(function($uri){ 1197 return substr($uri, 1); 1198 }, $recurrences); 1199 if (! $recurrences) { 1200 $recurrences[] = ''; 1201 } 1202 $cond .= " and (i.calitemId in (".implode(',', array_fill(0, count($itemIdsOrUris), '?')).") or i.uri in (".implode(',', array_fill(0, count($itemIdsOrUris), '?')).") or i.recurrenceId in (".implode(',', array_fill(0, count($recurrences), '?')).") or r.uri in (".implode(',', array_fill(0, count($itemIdsOrUris), '?'))."))"; 1203 $bindvars = array_merge($bindvars, $itemIdsOrUris, $itemIdsOrUris, $recurrences, $itemIdsOrUris); 1204 } 1205 1206 // TODO: we support only events for now. This is meant for CalDAV access to support TODO items, for example. 1207 // if ($componenttype) { 1208 // $cond .= " and i.componenttype = ?"; 1209 // $bindvars[] = $componenttype; 1210 // } 1211 1212 if ($start) { 1213 $cond .= " and i.end > ?"; 1214 $bindvars[] = $start; 1215 } 1216 1217 if ($end) { 1218 $cond .= " and i.start < ?"; 1219 $bindvars[] = $end; 1220 } 1221 1222 if ($recurrenceId) { 1223 $cond .= " and i.recurrenceId = ?"; 1224 $bindvars[] = $recurrenceId; 1225 } 1226 1227 if (! is_null($changed)) { 1228 $cond .= " and i.changed = ?"; 1229 $bindvars[] = $changed; 1230 } 1231 1232 $join = "left join `tiki_calendar_locations` as l on i.`locationId`=l.`callocId` left join `tiki_calendar_categories` as c on i.`categoryId`=c.`calcatId`"; 1233 1234 $query = "select i.`start`, i.`end`, i.`name`, i.`description`, i.`status`," . 1235 " i.`calitemId`, i.`calendarId`, i.`user`, i.`lastmodif` as `lastModif`, i.`url`, i.`recurrenceId`, i.`recurrenceStart`, r.`uid` as `recurrenceUid`," . 1236 " l.`name` as location, c.`name` as category, i.`created`, i.`priority`, i.`uid`, i.`uri`" . 1237 " from `tiki_calendar_items` i" . 1238 " left join `tiki_calendar_recurrence` r on i.`recurrenceId` = r.`recurrenceId`" . 1239 " $join" . 1240 " where 1=1 " . $cond . 1241 " order by calitemId"; 1242 1243 return $this->fetchAll($query, $bindvars); 1244 } 1245 1246 public function find_by_uid($user, $uid) { 1247 $query = "select i.`calendarId`, i.`calitemId`, i.`uri`, i.`recurrenceId` from `tiki_calendar_items` i left join `tiki_calendars` c on i.`calendarId` = c.`calendarId` left join `tiki_calendar_recurrence` r on i.`recurrenceId` = r.`recurrenceId` where (i.`uid` = ? or r.uid = ?)"; 1248 $bindvars = [$uid, $uid]; 1249 if ($user) { 1250 $query .= " and c.user = ?"; 1251 $bindvars[] = $user; 1252 } 1253 $result = $this->query($query, $bindvars); 1254 return $result->fetchRow(); 1255 } 1256 1257 /** 1258 * @param $maxrows 1259 * @param null $calendarId 1260 * @param $maxDaysEnd 1261 * @param string $order 1262 * @param int $priorDays 1263 * @param $maxDaysStart 1264 * @param int $start 1265 * @return array 1266 */ 1267 function past_events($maxrows = -1, $calendarId = null, $maxDaysEnd = -1, $order = 'start_asc', $priorDays = 0, $maxDaysStart = -1, $start = 0) 1268 { 1269 global $prefs; 1270 $cond = ''; 1271 $bindvars = []; 1272 if (isset($calendarId)) { 1273 if (is_array($calendarId)) { 1274 $cond = $cond . "and (0=1"; 1275 foreach ($calendarId as $id) { 1276 $cond = $cond . " or i.`calendarId` = ? "; 1277 } 1278 $cond = $cond . ")"; 1279 $bindvars = array_merge($bindvars, $calendarId); 1280 } else { 1281 $cond = $cond . " and i.`calendarId` = ? "; 1282 $bindvars[] = $calendarId; 1283 } 1284 } 1285 $cond .= " and `end` <= (unix_timestamp(now()) - ?*3600*34)"; 1286 $bindvars[] = $priorDays; 1287 1288 if ($maxDaysEnd > 0) { 1289 $maxSeconds = ($maxDaysEnd * 24 * 60 * 60); 1290 $cond .= " and `end` <= (unix_timestamp(now())) +" . $maxSeconds; 1291 } 1292 if ($maxDaysStart > 0) { 1293 $maxSeconds = ($maxDaysStart * 24 * 60 * 60); 1294 $cond .= " and `start` <= (unix_timestamp(now())) +" . $maxSeconds; 1295 } 1296 1297 $ljoin = "left join `tiki_calendar_locations` as l on i.`locationId`=l.`callocId` left join `tiki_calendar_categories` as c on i.`categoryId`=c.`calcatId`"; 1298 $query = "select i.`start`, i.`end`, i.`name`, i.`description`," . 1299 " i.`calitemId`, i.`calendarId`, i.`user`, i.`lastModif`," . 1300 " i.`url`, l.`name` as location, i.`allday`," . 1301 "c.`name` as category" . 1302 " from `tiki_calendar_items` i $ljoin where 1=1 " . $cond . 1303 " order by " . $this->convertSortMode($order); 1304 1305 $ret = $this->fetchAll($query, $bindvars, $maxrows, $start); 1306 1307 $query_cant = "select count(*) from `tiki_calendar_items` i $ljoin where 1=1 " . $cond . " order by " . $this->convertSortMode($order); 1308 $cant = $this->getOne($query_cant, $bindvars); 1309 1310 foreach ($ret as &$res) { 1311 $res['parsed'] = TikiLib::lib('parser')->parse_data($res['description'], ['is_html' => $prefs['calendar_description_is_html'] === 'y']); 1312 } 1313 1314 $retval = []; 1315 $retval['data'] = $ret; 1316 $retval['cant'] = $cant; 1317 return $retval; 1318 } 1319 1320 /** 1321 * @param $calendarId 1322 * @param $days 1323 * @return TikiDb_Pdo_Result|TikiDb_Adodb_Result 1324 */ 1325 function cleanEvents($calendarId, $days) 1326 { 1327 global $tikilib; 1328 $mid[] = " `end` < ? "; 1329 $bindvars[] = $tikilib->now - $days * 24 * 60 * 60; 1330 if ($calendarId > 0) { 1331 $mid[] = " `calendarId` = ? "; 1332 $bindvars[] = $calendarId; 1333 } 1334 $query = "delete from `tiki_calendar_items` where " . implode(' and ', $mid); 1335 $result = $tikilib->query($query, $bindvars); 1336 return $result; 1337 } 1338 1339 /** 1340 * @return int 1341 */ 1342 function firstDayofWeek() 1343 { 1344 global $prefs; 1345 if ($prefs['calendar_firstDayofWeek'] == 'user') { 1346 $firstDayofWeek = (int)tra('First day of week: Sunday (its ID is 0) - Translators, you need to localize this string!'); 1347 if ($firstDayofWeek < 1 || $firstDayofWeek > 6) { 1348 $firstDayofWeek = 0; 1349 } 1350 } else { 1351 $firstDayofWeek = $prefs['calendar_firstDayofWeek']; 1352 } 1353 return $firstDayofWeek; 1354 } 1355 // return detail on a date 1356 /** 1357 * @param $focusDate 1358 * @return array 1359 */ 1360 function infoDate($focusDate) 1361 { 1362 $focus = [ 1363 'day' => (int)TikiLib::date_format('%d', $focusDate), 1364 'month' => (int)TikiLib::date_format('%m', $focusDate), 1365 'year' => TikiLib::date_format('%Y', $focusDate), 1366 'date' => $focusDate, 1367 'weekDay' => TikiLib::date_format('%w', $focusDate) // in (0, 6) 1368 ]; 1369 $focus['daysInMonth'] = Date_Calc::daysInMonth($focus['month'], $focus['year']); 1370 return $focus; 1371 } 1372 // Compute the start date (the 1 first of the month of the focus date or the day) and the next start date from the period around a focus date 1373 /** 1374 * @param $focus 1375 * @param string $view 1376 * @param string $beginMonth 1377 * @param $start 1378 * @param $startNext 1379 */ 1380 function focusStartEnd($focus, $view = 'month', $beginMonth = 'y', &$start, &$startNext) 1381 { 1382 $nbMonths = ['month' => 1, 'bimester' => 2, 'trimester' => 3, 'quarter' => 4, 'semester' => 6, 'year' => 12]; 1383 // start of the period 1384 $start = $focus; 1385 if ($beginMonth == 'y') { 1386 $start['day'] = 1; 1387 } 1388 $start['date'] = TikiLib::make_time(0, 0, 0, $start['month'], $start['day'], $start['year']); 1389 $start['weekDay'] = TikiLib::date_format('%w', $start['date']); // in (0, 6) 1390 // start of the next period - just shift some months 1391 $startNext['date'] = TikiLib::make_time(0, 0, 0, $start['month'] + $nbMonths[$view], $start['day'], $start['year']); 1392 $startNext['day'] = TikiLib::date_format('%d', $startNext['date']); 1393 $startNext['month'] = TikiLib::date_format('%m', $startNext['date']); 1394 $startNext['year'] = TikiLib::date_format('%Y', $startNext['date']); 1395 $startNext['weekDay'] = TikiLib::date_format('%w', $startNext['date']); 1396 } 1397 // Compute the date just $view from the focus 1398 /** 1399 * @param $focus 1400 * @param string $view 1401 * @return array 1402 */ 1403 function focusPrevious($focus, $view = 'month') 1404 { 1405 $nbMonths = ['day' => 0, 'week' => 0, 'month' => 1, 'bimester' => 2, 'trimester' => 3, 'quarter' => 4, 'semester' => 6, 'year' => 12]; 1406 $nbDays = ['day' => 1, 'week' => 7, 'month' => 0, 'bimester' => 0, 'trimester' => 0, 'quarter' => 0, 'semester' => 0, 'year' => 0]; 1407 $previous = $focus; 1408 $previous['day'] -= $nbDays[$view]; 1409 // $tikilib->make_time() used with timezones doesn't support month = 0 1410 if ($previous['month'] - $nbMonths[$view] <= 0) { // need to change year 1411 $previous['month'] = ($previous['month'] + 11 - $nbMonths[$view]) % 12 + 1; 1412 $previous['year'] -= 1; 1413 } else { 1414 $previous['month'] -= $nbMonths[$view]; 1415 } 1416 $previous['daysInMonth'] = Date_Calc::daysInMonth($previous['month'], $previous['year']); 1417 if ($previous['day'] > $previous['daysInMonth']) { 1418 $previous['day'] = $previous['daysInMonth']; 1419 } 1420 $previous['date'] = Tikilib::make_time(0, 0, 0, $previous['month'], $previous['day'], $previous['year']); 1421 $previous = $this->infoDate($previous['date']); // get back real day, month, year 1422 return $previous; 1423 } 1424 // Compute the date just $view after the focus 1425 /** 1426 * @param $focus 1427 * @param string $view 1428 * @return array 1429 */ 1430 function focusNext($focus, $view = 'month') 1431 { 1432 $nbMonths = ['day' => 0, 'week' => 0, 'month' => 1, 'bimester' => 2, 'trimester' => 3, 'quarter' => 4, 'semester' => 6, 'year' => 12]; 1433 $nbDays = ['day' => 1, 'week' => 7, 'month' => 0, 'bimester' => 0, 'trimester' => 0, 'quarter' => 0, 'semester' => 0, 'year' => 0]; 1434 $next = $focus; 1435 $next['day'] += $nbDays[$view]; 1436 if ($next['month'] + $nbMonths[$view] > 12) { 1437 $next['month'] = ($next['month'] - 1 + $nbMonths[$view]) % 12 + 1; 1438 $next['year'] += 1; 1439 } else { 1440 $next['month'] += $nbMonths[$view]; 1441 } 1442 $next['daysInMonth'] = Date_Calc::daysInMonth($next['month'], $next['year']); 1443 if ($next['day'] > $next['daysInMonth']) { 1444 $next['day'] = $next['daysInMonth']; 1445 } 1446 $next['date'] = Tikilib::make_time(0, 0, 0, $next['month'], $next['day'], $next['year']); 1447 $next = $this->infoDate($next['date']); // get back real day, month, year 1448 return $next; 1449 } 1450 // Compute a table view of dates (one line per week) 1451 // $firstWeekDay = 0 (Sunday), 1 (Monday) 1452 /** 1453 * @param $start 1454 * @param $startNext 1455 * @param string $view 1456 * @param int $firstWeekDay 1457 * @return array 1458 */ 1459 function getTableViewCells($start, $startNext, $view = 'month', $firstWeekDay = 0) 1460 { 1461 // start of the view 1462 $viewStart = $start; 1463 $nbBackDays = $start['weekDay'] < $firstWeekDay ? 6 : $start['weekDay'] - $firstWeekDay; 1464 if ($nbBackDays == 0) { 1465 $viewStart['daysInMonth'] = Date_Calc::daysInMonth($viewStart['month'], $viewStart['year']); 1466 } elseif ($start['day'] - $nbBackDays < 0) { 1467 $viewStart['month'] = $start['month'] == 1 ? 12 : $start['month'] - 1; 1468 $viewStart['year'] = $start['month'] == 1 ? $start['year'] - 1 : $start['year']; 1469 $viewStart['daysInMonth'] = Date_Calc::daysInMonth($viewStart['month'], $viewStart['year']); 1470 $viewStart['day'] = $viewStart['daysInMonth'] - $nbBackDays + 1; 1471 $viewStart['date'] = TikiLib::make_time(0, 0, 0, $viewStart['month'], $viewStart['day'], $viewStart['year']); 1472 } else { 1473 $viewStart['daysInMonth'] = Date_Calc::daysInMonth($viewStart['month'], $viewStart['year']); 1474 $viewStart['day'] = $viewStart['day'] - $nbBackDays; 1475 $viewStart['date'] = TikiLib::make_time(0, 0, 0, $viewStart['month'], $viewStart['day'], $viewStart['year']); 1476 } 1477 // echo '<br/>VIEWSTART'; print_r($viewStart); 1478 // end of the period 1479 $cell = []; 1480 1481 for ($ilign = 0, $icol = 0, $loop = $viewStart, $weekDay = $viewStart['weekDay'];;) { 1482 if ($loop['date'] >= $startNext['date'] && $icol == 0) { 1483 break; 1484 } 1485 $cell[$ilign][$icol] = $loop; 1486 $cell[$ilign][$icol]['focus'] = $loop['date'] < $start['date'] || $loop['date'] >= $startNext['date'] ? false : true; 1487 $cell[$ilign][$icol]['weekDay'] = $weekDay; 1488 $weekDay = ($weekDay + 1) % 7; 1489 if ($icol >= 6) { 1490 ++$ilign; 1491 $icol = 0; 1492 } else { 1493 ++$icol; 1494 } 1495 if ($loop['day'] >= $loop['daysInMonth']) { 1496 $loop['day'] = 1; 1497 if ($loop['month'] == 12) { 1498 $loop['month'] = 1; 1499 $loop['year'] += 1; 1500 } else { 1501 $loop['month'] += 1; 1502 } 1503 $loop['daysInMonth'] = Date_Calc::daysInMonth($loop['month'], $loop['year']); 1504 } else { 1505 $loop['day'] = $loop['day'] + 1; 1506 } 1507 $loop['date'] = TikiLib::make_time(0, 0, 0, $loop['month'], $loop['day'], $loop['year']); 1508 } 1509 //echo '<pre>CELL'; print_r($cell); echo '</pre>'; 1510 return $cell; 1511 } 1512 1513 /** 1514 * @param int $firstDayofWeek 1515 * @param $daysnames 1516 * @param $daysnames_abr 1517 */ 1518 function getDayNames($firstDayofWeek = 0, &$daysnames, &$daysnames_abr) 1519 { 1520 $daysnames = []; 1521 $daysnames_abr = []; 1522 if ($firstDayofWeek == 0) { 1523 $daysnames[] = tra('Sunday'); 1524 $daysnames_abr[] = tra('Su'); 1525 } 1526 array_push( 1527 $daysnames, 1528 tra('Monday'), 1529 tra('Tuesday'), 1530 tra('Wednesday'), 1531 tra('Thursday'), 1532 tra('Friday'), 1533 tra('Saturday') 1534 ); 1535 array_push( 1536 $daysnames_abr, 1537 tra('Mo'), 1538 tra('Tu'), 1539 tra('We'), 1540 tra('Th'), 1541 tra('Fr'), 1542 tra('Sa') 1543 ); 1544 if ($firstDayofWeek != 0) { 1545 $daysnames[] = tra('Sunday'); 1546 $daysnames_abr[] = tra('Su'); 1547 } 1548 } 1549 1550 /** 1551 * Get calendar and its events 1552 * 1553 * @param $calIds 1554 * @param $viewstart 1555 * @param $viewend 1556 * @param $group_by 1557 * @param $item_name 1558 * @param bool $listmode if set to true populate listevents key of the returned array 1559 * @return array 1560 */ 1561 function getCalendar($calIds, &$viewstart, &$viewend, $group_by = '', $item_name = 'events', $listmode = false) 1562 { 1563 global $user, $prefs; 1564 1565 // Global vars used by tiki-calendar_setup.php (this has to be changed) 1566 global $calendarViewMode, $request_day, $request_month; 1567 global $request_year, $dayend, $myurl; 1568 global $weekdays, $daysnames, $daysnames_abr; 1569 include('tiki-calendar_setup.php'); 1570 1571 $smarty = TikiLib::lib('smarty'); 1572 $tikilib = TikiLib::lib('tiki'); 1573 1574 //FIXME : maxrecords = 50 1575 $listtikievents = $this->list_items_by_day($calIds, $user, $viewstart, $viewend, 0, 50); 1576 1577 $mloop = TikiLib::date_format('%m', $viewstart); 1578 $dloop = TikiLib::date_format('%d', $viewstart); 1579 $yloop = TikiLib::date_format('%Y', $viewstart); 1580 $curtikidate = new TikiDate(); 1581 $display_tz = $tikilib->get_display_timezone(); 1582 if ($display_tz == '') { 1583 $display_tz = 'UTC'; 1584 } 1585 $curtikidate->setTZbyID($display_tz); 1586 $curtikidate->setLocalTime($dloop, $mloop, $yloop, 0, 0, 0, 0); 1587 $listevents = []; 1588 1589 // note that number of weeks starts at ZERO (i.e., zero = 1 week to display). 1590 for ($i = 0; $i <= $numberofweeks; $i++) { 1591 $weeks[] = $curtikidate->getWeekOfYear(); 1592 1593 foreach ($weekdays as $w) { 1594 $leday = []; 1595 if ($group_by == 'day') { 1596 $key = 0; 1597 } 1598 if ($calendarViewMode['casedefault'] == 'day') { 1599 $dday = $daystart; 1600 } else { 1601 $dday = $curtikidate->getTime(); 1602 $curtikidate->addDays(1); 1603 } 1604 $cell[$i][$w]['day'] = $dday; 1605 1606 if ($calendarViewMode['casedefault'] == 'day' or ( $dday >= $daystart && $dday <= $dayend )) { 1607 $cell[$i][$w]['focus'] = true; 1608 } else { 1609 $cell[$i][$w]['focus'] = false; 1610 } 1611 if (isset($listtikievents["$dday"])) { 1612 $e = -1; 1613 1614 foreach ($listtikievents["$dday"] as $lte) { 1615 $lte['desc_name'] = $lte['name']; 1616 if ($group_by_item != 'n') { 1617 if ($group_by != 'day') { 1618 $key = $lte['id'] . '|' . $lte['type']; 1619 } 1620 if (! isset($leday[$key])) { 1621 $leday[$key] = $lte; 1622 if ($group_by == 'day') { 1623 $leday[$key]['description'] = [$lte['where'] => [$lte['group_description']]]; 1624 $leday[$key]['head'] = TikiLib::date_format($prefs['short_date_format'], $cell[$i][$w]['day']); 1625 } else { 1626 $leday[$key]['description'] = ' - <b>' . $lte['when'] . '</b> : ' . tra($lte['action']) . ' ' . $lte['description']; 1627 $leday[$key]['head'] = $lte['name'] . ', <i>' . tra('in') . ' ' . $lte['where'] . '</i>'; 1628 } 1629 $leday[$key]['desc_name'] = ''; 1630 } else { 1631 $leday_item =& $leday[$key]; 1632 $leday_item['user'] .= ', ' . $lte['user']; 1633 1634 if (! isset($leday_item['action']) || ! is_integer($leday_item['action'])) { 1635 $leday_item['action'] = 1; 1636 } 1637 $leday_item['action']++; 1638 1639 if ($group_by == 'day') { 1640 $leday_item['name'] .= '<br />' . $lte['name']; 1641 $leday_item['desc_name'] = $leday_item['action'] . ' ' . tra($item_name) . ': '; 1642 $leday_item['description'][$lte['where']][] = $lte['group_description']; 1643 } else { 1644 $leday_item['name'] = $lte['name'] . ' (x ' . $leday_item['action'] . ')'; 1645 $leday_item['desc_name'] = $leday_item['action'] . ' ' . tra($item_name); 1646 if ($lte['show_description'] == 'y' && ! empty($lte['description'])) { 1647 $leday_item['description'] .= ",\n<br /> - <b>" . $lte['when'] . '</b> : ' . tra($lte['action']) . ' ' . $lte['description']; 1648 $leday_item['show_description'] = 'y'; 1649 } 1650 } 1651 } 1652 } else { 1653 $e++; 1654 $key = "{$lte['time']}$e"; 1655 $leday[$key] = $lte; 1656 $lte['desc_name'] .= tra($lte['action']); 1657 } 1658 } 1659 foreach ($leday as $key => $lte) { 1660 if ($group_by == 'day') { 1661 $desc = ''; 1662 foreach ($lte['description'] as $desc_where => $desc_items) { 1663 $desc_items = array_unique($desc_items); 1664 foreach ($desc_items as $desc_item) { 1665 if ($desc != '') { 1666 $desc .= '<br />'; 1667 } 1668 $desc .= '- ' . $desc_item; 1669 if (! empty($lte['show_location']) && $lte['show_location'] == 'y' && $desc_where != '') { 1670 $desc .= ' <i>[' . $desc_where . ']</i>'; 1671 } 1672 } 1673 } 1674 $lte['description'] = $desc; 1675 } 1676 1677 $smarty->assign('calendar_type', ( $myurl == 'tiki-action_calendar.php' ? 'tiki_actions' : 'calendar' )); 1678 $smarty->assign_by_ref('item_url', $lte["url"]); 1679 $smarty->assign_by_ref('cellhead', $lte["head"]); 1680 $smarty->assign_by_ref('cellprio', $lte["prio"]); 1681 $smarty->assign_by_ref('cellcalname', $lte["calname"]); 1682 $smarty->assign('celllocation', ""); 1683 $smarty->assign('cellcategory', ""); 1684 $smarty->assign_by_ref('cellname', $lte["desc_name"]); 1685 $smarty->assign('cellid', ""); 1686 $smarty->assign_by_ref('celldescription', $lte["description"]); 1687 $smarty->assign('show_description', $lte["show_description"]); 1688 1689 if (! isset($leday[$key]["over"])) { 1690 $leday[$key]["over"] = ''; 1691 } else { 1692 $leday[$key]["over"] .= "<br />\n"; 1693 } 1694 $leday[$key]["over"] .= $smarty->fetch("tiki-calendar_box.tpl"); 1695 } 1696 } 1697 1698 if (is_array($leday)) { 1699 ksort($leday); 1700 $cell[$i][$w]['items'] = array_values($leday); 1701 } 1702 } 1703 } 1704 1705 if ((isset($_SESSION['CalendarViewList']) && $_SESSION['CalendarViewList'] == 'list') || $listmode) { 1706 if (is_array($listtikievents)) { 1707 foreach ($listtikievents as $le) { 1708 if (is_array($le)) { 1709 foreach ($le as $e) { 1710 $listevents[] = $e; 1711 } 1712 } 1713 } 1714 } 1715 } 1716 1717 return [ 1718 'cell' => $cell, 1719 'listevents' => $listevents, 1720 'weeks' => $weeks, 1721 'weekdays' => $weekdays, 1722 'daysnames' => $daysnames, 1723 'daysnames_abr' => $daysnames_abr, 1724 'trunc' => $trunc 1725 ]; 1726 } 1727 1728 /** 1729 * @param $calitemId 1730 * @param null $adds 1731 * @param null $dels 1732 */ 1733 function update_participants($calitemId, $adds = null, $dels = null) 1734 { 1735 if (! empty($dels)) { 1736 foreach ($dels as $del) { 1737 $this->query('delete from `tiki_calendar_roles` where `calitemId`=? and `username`=? and `role`!=?', [$calitemId, $del, ROLE_ORGANIZER]); 1738 } 1739 } 1740 if (! empty($adds)) { 1741 $all = $this->fetchAll('select * from `tiki_calendar_roles` where `calitemId`=?', [$calitemId]); 1742 foreach ($adds as $add) { 1743 if (! isset($add['role']) || $add['role'] == ROLE_ORGANIZER) { 1744 $add['role'] = 0; 1745 } 1746 $found = false; 1747 foreach ($all as $u) { 1748 if ($u['username'] == $add['name'] && $u['role'] != ROLE_ORGANIZER) { 1749 if ($u['role'] != $add['role']) { 1750 $this->query('update `tiki_calendar_roles` set `role`=? where `calitemId`=? and `username`=?', [$add['role'], $calitemId, $add['name']]); 1751 } 1752 $found = true; 1753 break; 1754 } 1755 } 1756 if (! $found) { 1757 $this->query('insert into `tiki_calendar_roles`(`calitemId`, `username`, `role`) values(?, ? ,?)', [$calitemId, $add['name'], $add['role']]); 1758 } 1759 } 1760 } 1761 } 1762 1763 /** 1764 * Update participant status (partstat) for an attendee 1765 * @param $calitemId 1766 * @param $username 1767 * @param $partstat - ACCEPTED, TENTATIVE, DECLINED 1768 */ 1769 public function update_partstat($calitemId, $username, $partstat) { 1770 return $this->query("update `tiki_calendar_roles` SET `partstat` = ? where calitemId = ? and username = ?", [$partstat, $calitemId, $username]); 1771 } 1772 1773 /** 1774 * Adds a change record to the calendarchanges table. 1775 * 1776 * @param int $calendarId 1777 * @param int $calitemId 1778 * @param int $operation 1 = add, 2 = modify, 3 = delete. 1779 * @return void 1780 */ 1781 public function add_change($calendarId, $calitemId, $operation) 1782 { 1783 $options = $this->get_calendar_options($calendarId); 1784 1785 $this->query('insert into `tiki_calendar_changes`(`calitemId`, `synctoken`, `calendarId`, `operation`) values(?, ?, ?, ?)', [ 1786 $calitemId, 1787 $options['synctoken'] ?? 1, 1788 $calendarId, 1789 $operation, 1790 ]); 1791 1792 $this->query('replace into tiki_calendar_options(calendarId, optionName, value) values(?, ?, ?)', [ 1793 $calendarId, 1794 'synctoken', 1795 $options['synctoken']+1, 1796 ]); 1797 } 1798 1799 /** 1800 * Gets latest change for each item in the calendar. 1801 * 1802 * @param int $calendarId 1803 * @param int $synctoken 1804 * @param int $maxrecords 1805 * @return array 1806 */ 1807 public function get_changes($calendarId, $synctoken, $maxRecords = -1) 1808 { 1809 $query = 'select c1.calitemId, c1.operation, ci.uri 1810 from `tiki_calendar_changes` c1 1811 left join `tiki_calendar_changes` c2 on c1.calitemId = c2.calitemId and c1.synctoken < c2.synctoken 1812 left join `tiki_calendar_items` ci on c1.calitemId = ci.calitemId 1813 where c1.calendarId = ? and c1.synctoken > ? and c2.calitemId is null'; 1814 $bindvars = [$calendarId, $synctoken]; 1815 return $this->fetchAll($query, $bindvars, $maxRecords); 1816 } 1817 1818 public function fill_uid($calitemId, $uid) { 1819 $this->query("update `tiki_calendar_items` set `uid` = ? where `calitemId` = ?", [$uid, $calitemId]); 1820 } 1821 1822 /** 1823 * Calendar instance methods - deal with invites and shares 1824 */ 1825 public function get_calendar_instances($calendarId) 1826 { 1827 $query = "select user, access, share_href, share_name, share_invite_status from `tiki_calendar_instances` where calendarId = ?"; 1828 $bindvars = [$calendarId]; 1829 return $this->fetchAll($query, $bindvars); 1830 } 1831 1832 public function get_calendar_instance($instanceId) 1833 { 1834 $query = "select user, access, share_href, share_name, share_invite_status from `tiki_calendar_instances` where calendarInstanceId = ?"; 1835 $bindvars = [$instanceId]; 1836 $result = $this->query($query, $bindvars); 1837 return $result->fetchRow(); 1838 } 1839 1840 public function create_calendar_instance($data) 1841 { 1842 $query = 'insert into `tiki_calendar_instances` (`'.implode('`, `', array_keys($data)).'`) values ('.implode(",", array_fill(0, count($data), "?")).')'; 1843 $bindvars = array_values($data); 1844 $this->query($query, $bindvars); 1845 return $this->lastInsertId(); 1846 } 1847 1848 public function update_calendar_instance($calendarId, $share_href, $data) 1849 { 1850 $query = 'update `tiki_calendar_instances` set '.implode(' = ?, ', array_keys($data)).' = ? where calendarId = ? and share_href = ?'; 1851 $bindvars = array_values($data) + [$calendarId, $share_href]; 1852 return $this->query($query, $bindvars); 1853 } 1854 1855 public function remove_calendar_instance($calendarId, $share_href = null, $instanceId = null) 1856 { 1857 if ($shared_href) { 1858 return $this->query('delete from `tiki_calendar_instances` where calendarId = ? and share_href = ?', [$calendarId, $share_href]); 1859 } 1860 if ($instanceId) { 1861 return $this->query('delete from `tiki_calendar_instances` where calendarId = ? and calendarInstanceId = ?', [$calendarId, $instanceId]); 1862 } 1863 } 1864 1865 /** 1866 * Subscription methods 1867 */ 1868 public function get_subscriptions($user) 1869 { 1870 $query = "select subscriptionId, calendarId, user, source, name, refresh_rate, `order`, color, strip_todos, strip_alarms, strip_attachments, lastmodif from tiki_calendar_subscriptions where user = ?"; 1871 $bindvars = [$user]; 1872 return $this->fetchAll($query, $bindvars); 1873 } 1874 1875 public function create_subscription($data) 1876 { 1877 $data['lastmodif'] = time(); 1878 $query = 'insert into `tiki_calendar_subscriptions` (`'.implode('`, `', array_keys($data)).'`) values ('.implode(",", array_fill(0, count($data), "?")).')'; 1879 $bindvars = array_values($data); 1880 $this->query($query, $bindvars); 1881 return $this->lastInsertId(); 1882 } 1883 1884 public function update_subscription($subscriptionId, $data) 1885 { 1886 $data['lastmodif'] = time(); 1887 $query = 'update `tiki_calendar_subscriptions` set '.implode(' = ?, ', array_keys($data)).' = ? where subscriptionId = ?'; 1888 $bindvars = array_values($data) + [$subscriptionId]; 1889 return $this->query($query, $bindvars); 1890 } 1891 1892 public function delete_subscription($subscriptionId) 1893 { 1894 return $this->query('delete from `tiki_calendar_subscriptions` where subscriptionId = ?', [$subscriptionId]); 1895 } 1896 1897 /** 1898 * Scheduling methods 1899 */ 1900 public function get_scheduling_object($user, $uri) 1901 { 1902 $query = "SELECT uri, calendardata, lastmodif, etag, size FROM `tiki_calendar_scheduling_objects` WHERE user = ? AND uri = ?"; 1903 $bindvars = [$user, $uri]; 1904 $result = $this->query($query, $bindvars); 1905 return $result->fetchRow(); 1906 } 1907 1908 public function get_scheduling_objects($user) 1909 { 1910 $query = "SELECT schedulingObjectId, calendardata, uri, lastmodif, etag, size FROM `tiki_calendar_scheduling_objects` WHERE user = ?"; 1911 $bindvars = [$user]; 1912 return $this->fetchAll($query, $bindvars); 1913 } 1914 1915 public function delete_scheduling_object($user, $uri) 1916 { 1917 return $this->query('delete from `tiki_calendar_scheduling_objects` where user = ? and uri = ?', [$user, $uri]); 1918 } 1919 1920 public function create_scheduling_object($user, $uri, $data) 1921 { 1922 $query = "insert into `tiki_calendar_scheduling_objects` (user, calendardata, uri, lastmodif, etag, size) values (?, ?, ?, ?, ?, ?)"; 1923 $bindvars = [$user, $data, $uri, time(), md5($data), strlen($data)]; 1924 $this->query($query, $bindvars); 1925 return $this->lastInsertId(); 1926 } 1927} 1928