From 0492dfb98baa33c58936ebcb087439ac58128e5b Mon Sep 17 00:00:00 2001 From: "Michael J. Rubinsky" Date: Thu, 3 Sep 2009 13:23:22 -0400 Subject: [PATCH] Large bit of work on Kronolith Resources. - K_Event_Resource and k_Driver_Resource resources. - Implement viewing/editing a resource's events. - Show resource calendar title in panel - Get rid of lib/Resource.php (functionality moved to Kronolith::) --- kronolith/lib/Driver/Resource.php | 467 ++++++++++++++++++++++++++++++++ kronolith/lib/Driver/Sql.php | 107 +------- kronolith/lib/Event.php | 2 +- kronolith/lib/Event/Kolab.php | 20 ++ kronolith/lib/Event/Resource.php | 219 +++++++++++++++ kronolith/lib/Event/Sql.php | 2 +- kronolith/lib/FreeBusy.php | 2 +- kronolith/lib/Kronolith.php | 75 ++++- kronolith/lib/Resource.php | 88 ------ kronolith/lib/Resource/Single.php | 9 +- kronolith/lib/View/Month.php | 2 +- kronolith/resources.php | 18 +- kronolith/templates/calendar_titles.inc | 6 + 13 files changed, 805 insertions(+), 212 deletions(-) create mode 100644 kronolith/lib/Driver/Resource.php create mode 100644 kronolith/lib/Event/Resource.php delete mode 100644 kronolith/lib/Resource.php diff --git a/kronolith/lib/Driver/Resource.php b/kronolith/lib/Driver/Resource.php new file mode 100644 index 000000000..977e9d489 --- /dev/null +++ b/kronolith/lib/Driver/Resource.php @@ -0,0 +1,467 @@ + + * @author Chuck Hagenbuch + * @author Jan Schneider + * @package Kronolith + */ +class Kronolith_Driver_Resource extends Kronolith_Driver_Sql +{ + + /** + * Lists all events that satisfy the given conditions. + * + * @param Horde_Date $startInterval Start of range date object. + * @param Horde_Date $endInterval End of range data object. + * @param string $conditions Conditions, given as SQL clauses. + * @param array $vals SQL bind variables for use with + * $conditions clauses. + * + * @return array Events in the given time range satisfying the given + * conditions. + */ + protected function _listEventsConditional($startInterval, $endInterval, + $conditions = '', $vals = array()) + { + $q = 'SELECT event_id, event_uid, event_description, event_location,' . + ' event_private, event_status, event_attendees,' . + ' event_title, event_recurcount,' . + ' event_recurtype, event_recurenddate, event_recurinterval,' . + ' event_recurdays, event_start, event_end, event_allday,' . + ' event_alarm, event_alarm_methods, event_modified,' . + ' event_exceptions, event_creator_id, event_resources' . + ' FROM ' . $this->_params['table'] . + ' WHERE calendar_id = ? AND (('; + $values = array($this->_calendar); + if ($conditions) { + $q .= $conditions . ')) AND (('; + $values = array_merge($values, $vals); + } + + $etime = $endInterval->format('Y-m-d H:i:s'); + $stime = null; + if (isset($startInterval)) { + $stime = $startInterval->format('Y-m-d H:i:s'); + $q .= 'event_end >= ? AND '; + $values[] = $stime; + } + $q .= 'event_start <= ?) OR ('; + $values[] = $etime; + if (isset($stime)) { + $q .= 'event_recurenddate >= ? AND '; + $values[] = $stime; + } + $q .= 'event_start <= ?' . + ' AND event_recurtype <> ?))'; + array_push($values, $etime, Horde_Date_Recurrence::RECUR_NONE); + + /* Log the query at a DEBUG log level. */ + Horde::logMessage(sprintf('Kronolith_Driver_Sql::_listEventsConditional(): user = "%s"; query = "%s"; values = "%s"', + Horde_Auth::getAuth(), $q, implode(',', $values)), + __FILE__, __LINE__, PEAR_LOG_DEBUG); + + /* Run the query. */ + $qr = $this->_db->query($q, $values); + if (is_a($qr, 'PEAR_Error')) { + Horde::logMessage($qr, __FILE__, __LINE__, PEAR_LOG_ERR); + return $qr; + } + + $events = array(); + $row = $qr->fetchRow(DB_FETCHMODE_ASSOC); + while ($row && !is_a($row, 'PEAR_Error')) { + /* If the event did not have a UID before, we need to give + * it one. */ + if (empty($row['event_uid'])) { + $row['event_uid'] = $this->generateUID(); + + /* Save the new UID for data integrity. */ + $query = 'UPDATE ' . $this->_params['table'] . ' SET event_uid = ? WHERE event_id = ?'; + $values = array($row['event_uid'], $row['event_id']); + + /* Log the query at a DEBUG log level. */ + Horde::logMessage(sprintf('Kronolith_Driver_Sql::_listEventsConditional(): user = %s; query = "%s"; values = "%s"', + Horde_Auth::getAuth(), $query, implode(',', $values)), + __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $result = $this->_write_db->query($query, $values); + if (is_a($result, 'PEAR_Error')) { + Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR); + } + } + + /* We have all the information we need to create an event object + * for this event, so go ahead and cache it. */ + $this->_cache[$this->_calendar][$row['event_id']] = new Kronolith_Event_Resource($this, $row); + if ($row['event_recurtype'] == Horde_Date_Recurrence::RECUR_NONE) { + $events[$row['event_uid']] = $row['event_id']; + } else { + $next = $this->nextRecurrence($row['event_id'], $startInterval); + if ($next && $next->compareDateTime($endInterval) < 0) { + $events[$row['event_uid']] = $row['event_id']; + } + } + + $row = $qr->fetchRow(DB_FETCHMODE_ASSOC); + } + + return $events; + } + + public function getEvent($eventId = null) + { + if (!strlen($eventId)) { + return new Kronolith_Event_Resource($this); + } + + if (isset($this->_cache[$this->_calendar][$eventId])) { + return $this->_cache[$this->_calendar][$eventId]; + } + + $query = 'SELECT event_id, event_uid, event_description,' . + ' event_location, event_private, event_status, event_attendees,' . + ' event_title, event_recurcount,' . + ' event_recurtype, event_recurenddate, event_recurinterval,' . + ' event_recurdays, event_start, event_end, event_allday,' . + ' event_alarm, event_alarm_methods, event_modified,' . + ' event_exceptions, event_creator_id, event_resources' . + ' FROM ' . $this->_params['table'] . ' WHERE event_id = ? AND calendar_id = ?'; + $values = array($eventId, $this->_calendar); + + /* Log the query at a DEBUG log level. */ + Horde::logMessage(sprintf('Kronolith_Driver_Sql::getEvent(): user = "%s"; query = "%s"; values = "%s"', + Horde_Auth::getAuth(), $query, implode(',', $values)), + __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $event = $this->_db->getRow($query, $values, DB_FETCHMODE_ASSOC); + if (is_a($event, 'PEAR_Error')) { + Horde::logMessage($event, __FILE__, __LINE__, PEAR_LOG_ERR); + return $event; + } + + if ($event) { + $this->_cache[$this->_calendar][$eventId] = new Kronolith_Event_Resource($this, $event); + return $this->_cache[$this->_calendar][$eventId]; + } else { + return PEAR::raiseError(_("Event not found")); + } + } + + /** + * Get an event or events with the given UID value. + * + * @param string $uid The UID to match + * @param array $calendars A restricted array of calendar ids to search + * @param boolean $getAll Return all matching events? If this is false, + * an error will be returned if more than one event is found. + * + * @return Kronolith_Event + */ + public function getByUID($uid, $calendars = null, $getAll = false) + { + $query = 'SELECT event_id, event_uid, calendar_id, event_description,' . + ' event_location, event_private, event_status, event_attendees,' . + ' event_title, event_recurcount,' . + ' event_recurtype, event_recurenddate, event_recurinterval,' . + ' event_recurdays, event_start, event_end, event_allday,' . + ' event_alarm, event_alarm_methods, event_modified,' . + ' event_exceptions, event_creator_id, event_resources' . + ' FROM ' . $this->_params['table'] . ' WHERE event_uid = ?'; + $values = array($uid); + + /* Optionally filter by calendar */ + if (!is_null($calendars)) { + if (!count($calendars)) { + return PEAR::raiseError(_("No calendars to search")); + } + $query .= ' AND calendar_id IN (?' . str_repeat(', ?', count($calendars) - 1) . ')'; + $values = array_merge($values, $calendars); + } + + /* Log the query at a DEBUG log level. */ + Horde::logMessage(sprintf('Kronolith_Driver_Sql::getByUID(): user = "%s"; query = "%s"; values = "%s"', + Horde_Auth::getAuth(), $query, implode(',', $values)), + __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $events = $this->_db->getAll($query, $values, DB_FETCHMODE_ASSOC); + if (is_a($events, 'PEAR_Error')) { + Horde::logMessage($events, __FILE__, __LINE__, PEAR_LOG_ERR); + return $events; + } + if (!count($events)) { + return PEAR::raiseError($uid . ' not found'); + } + + $eventArray = array(); + foreach ($events as $event) { + $this->open($event['calendar_id']); + $this->_cache[$this->_calendar][$event['event_id']] = new Kronolith_Event_Resource($this, $event); + $eventArray[] = $this->_cache[$this->_calendar][$event['event_id']]; + } + + if ($getAll) { + return $eventArray; + } + + /* First try the user's own calendars. */ + $ownerCalendars = Kronolith::listCalendars(true, PERMS_READ); + $event = null; + foreach ($eventArray as $ev) { + if (isset($ownerCalendars[$ev->getCalendar()])) { + $event = $ev; + break; + } + } + + /* If not successful, try all calendars the user has access too. */ + if (empty($event)) { + $readableCalendars = Kronolith::listCalendars(false, PERMS_READ); + foreach ($eventArray as $ev) { + if (isset($readableCalendars[$ev->getCalendar()])) { + $event = $ev; + break; + } + } + } + + if (empty($event)) { + $event = $eventArray[0]; + } + + return $event; + } + + /** + * Saves an event in the backend. + * If it is a new event, it is added, otherwise the event is updated. + * + * @param Kronolith_Event $event The event to save. + */ + public function saveEvent($event) + { + if ($event->isStored() || $event->exists()) { + $values = array(); + + $query = 'UPDATE ' . $this->_params['table'] . ' SET '; + + foreach ($event->getProperties() as $key => $val) { + $query .= " $key = ?,"; + $values[] = $val; + } + $query = substr($query, 0, -1); + $query .= ' WHERE event_id = ?'; + $values[] = $event->getId(); + + /* Log the query at a DEBUG log level. */ + Horde::logMessage(sprintf('Kronolith_Driver_Sql::saveEvent(): user = "%s"; query = "%s"; values = "%s"', + Horde_Auth::getAuth(), $query, implode(',', $values)), + __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $result = $this->_write_db->query($query, $values); + if (is_a($result, 'PEAR_Error')) { + Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR); + return $result; + } + + /* Log the modification of this item in the history log. */ + if ($event->getUID()) { + $history = Horde_History::singleton(); + $history->log('kronolith:' . $this->_calendar . ':' . $event->getUID(), array('action' => 'modify'), true); + } + + /* Update tags */ + $tagger = Kronolith::getTagger(); + $tagger->replaceTags($event->getUID(), $event->tags, 'event'); + + /* Notify users about the changed event. */ + $result = Kronolith::sendNotification($event, 'edit'); + if (is_a($result, 'PEAR_Error')) { + Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR); + } + + return $event->getId(); + } else { + if ($event->getId()) { + $id = $event->getId(); + } else { + $id = hash('md5', uniqid(mt_rand(), true)); + $event->setId($id); + } + + if ($event->getUID()) { + $uid = $event->getUID(); + } else { + $uid = $this->generateUID(); + $event->setUID($uid); + } + + $query = 'INSERT INTO ' . $this->_params['table']; + $cols_name = ' (event_id, event_uid,'; + $cols_values = ' VALUES (?, ?,'; + $values = array($id, $uid); + + foreach ($event->getProperties() as $key => $val) { + $cols_name .= " $key,"; + $cols_values .= ' ?,'; + $values[] = $val; + } + + $cols_name .= ' calendar_id)'; + $cols_values .= ' ?)'; + $values[] = $this->_calendar; + + $query .= $cols_name . $cols_values; + + /* Log the query at a DEBUG log level. */ + Horde::logMessage(sprintf('Kronolith_Driver_Sql::saveEvent(): user = "%s"; query = "%s"; values = "%s"', + Horde_Auth::getAuth(), $query, implode(',', $values)), + __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $result = $this->_write_db->query($query, $values); + if (is_a($result, 'PEAR_Error')) { + Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR); + return $result; + } + + /* Log the creation of this item in the history log. */ + $history = Horde_History::singleton(); + $history->log('kronolith:' . $this->_calendar . ':' . $uid, array('action' => 'add'), true); + + /* Deal with any tags */ + $tagger = Kronolith::getTagger(); + $tagger->tag($event->getUID(), $event->tags, 'event'); + + /* Notify users about the new event. */ + $result = Kronolith::sendNotification($event, 'add'); + if (is_a($result, 'PEAR_Error')) { + Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR); + } + + return $id; + } + } + + /** + * Save or update a Kronolith_Resource + * + * @param $resource + * + * @return Kronolith_Resource object + * @throws Horde_Exception + */ + public function save($resource) + { + if (!empty($resource->id)) { + $query = 'UPDATE kronolith_resources SET resource_name = ?, resource_calendar = ?, resource_category = ? WHERE resource_id = ?'; + $values = array($resource->name, $resource->calendar, $resource->category, $resource->id); + $result = $this->_write_db->query($query, $values); + if (!($result instanceof PEAR_Error)) { + throw new Horde_Exception($result->getMessage()); + } + } else { + $query = 'INSERT INTO kronolith_resources (resource_id, resource_name, resource_calendar, resource_category)'; + $cols_values = ' VALUES (?, ?, ?, ?)'; + $id = $this->_db->nextId('kronolity_resources'); + $values = array($id, $resource->name, $resource->calendar, $resource->category); + $result = $this->_write_db->query($query . $cols_values, $values); + if (!($result instanceof PEAR_Error)) { + return true; + } else { + throw new Horde_Exception($result->getMessage()); + } + $resource->setUid($id); + } + + return $resource; + } + + /** + * Obtain a Kronolith_Resource by the resource's id + * + * @param int $id The key for the Kronolith_Resource + * + * @return array A hash of resource object properties + * @throws Horde_Exception + */ + public function getResource($id) + { + $query = 'SELECT resource_id, resource_name, resource_calendar, resource_category FROM kronolith_resources WHERE resource_id = ?'; + + $results = $this->_db->getRow($query, array($id), DB_FETCHMODE_ASSOC); + if ($results instanceof PEAR_Error) { + throw new Horde_Exception($results->getMessage()); + } + if (empty($results)) { + throw new Horde_Exception('Resource not found'); + } + $return = array(); + foreach ($results as $field => $value) { + $return[str_replace('resource_', '', $field)] = $this->convertFromDriver($value); + } + + return $return; + } + + /** + * Obtain the resource id associated with the given calendar uid. + * + * @param string $calendar The calendar's uid + * + * @return int The Kronolith_Resource id + * @throws Horde_Exception + */ + public function getResourceIdByCalendar($calendar) + { + $query = 'SELECT resource_id FROM kronolith_resources WHERE resource_calendar = ?'; + $results = $this->_db->getOne($query, array($calendar)); + if ($results instanceof PEAR_Error) { + throw new Horde_Exception($results->getMessage()); + } + if (empty($results)) { + throw new Horde_Exception('Resource not found'); + } + + return $results; + } + + /** + * Return a list of Kronolith_Resources + * + * This method will likely be a moving target as group resources are + * fleshed out. + * + */ + function listResources($params = array()) + { + $query = 'SELECT resource_id, resource_name, resource_calendar, resource_category FROM kronolith_resources'; + $results = $this->_db->getAll($query, null, DB_FETCHMODE_ASSOC); + if ($results instanceof PEAR_Error) { + throw new Horde_Exception($results->getMessage()); + } + + return $results; + } + + /** + * Remove all events owned by the specified user in all calendars. + * + * @todo Refactor: move to Kronolith:: + * + * @param string $user The user name to delete events for. + * + * @param mixed True | PEAR_Error + */ + public function removeUserData($user) + { + return PEAR::raiseError(_("Removing user data is not supported with the current calendar storage backend.")); + } + +} diff --git a/kronolith/lib/Driver/Sql.php b/kronolith/lib/Driver/Sql.php index 26754337a..f356a8dd1 100644 --- a/kronolith/lib/Driver/Sql.php +++ b/kronolith/lib/Driver/Sql.php @@ -20,7 +20,7 @@ class Kronolith_Driver_Sql extends Kronolith_Driver * * @var DB */ - private $_db; + protected $_db; /** * Handle for the current database connection, used for writing. Defaults @@ -28,7 +28,7 @@ class Kronolith_Driver_Sql extends Kronolith_Driver * * @var DB */ - private $_write_db; + protected $_write_db; /** * Cache events as we fetch them to avoid fetching the same event from the @@ -36,7 +36,7 @@ class Kronolith_Driver_Sql extends Kronolith_Driver * * @var array */ - private $_cache = array(); + protected $_cache = array(); public function listAlarms($date, $fullevent = false) { @@ -756,107 +756,6 @@ class Kronolith_Driver_Sql extends Kronolith_Driver } /** - * Save or update a Kronolith_Resource - * - * @param $resource - * - * @return Kronolith_Resource object - * @throws Horde_Exception - */ - public function saveResource($resource) - { - if (!empty($resource->id)) { - $query = 'UPDATE kronolith_resources SET resource_name = ?, resource_calendar = ?, resource_category = ? WHERE resource_id = ?'; - $values = array($resource->name, $resource->calendar, $resource->category, $resource->id); - $result = $this->_write_db->query($query, $values); - if (!($result instanceof PEAR_Error)) { - throw new Horde_Exception($result->getMessage()); - } - } else { - $query = 'INSERT INTO kronolith_resources (resource_id, resource_name, resource_calendar, resource_category)'; - $cols_values = ' VALUES (?, ?, ?, ?)'; - $id = $this->_db->nextId('kronolity_resources'); - $values = array($id, $resource->name, $resource->calendar, $resource->category); - $result = $this->_write_db->query($query . $cols_values, $values); - if (!($result instanceof PEAR_Error)) { - return true; - } else { - throw new Horde_Exception($result->getMessage()); - } - $resource->setUid($id); - } - - return $resource; - } - - /** - * Obtain a Kronolith_Resource by the resource's id - * - * @param int $id The key for the Kronolith_Resource - * - * @return array A hash of resource object properties - * @throws Horde_Exception - */ - public function getResource($id) - { - $query = 'SELECT resource_id, resource_name, resource_calendar, resource_category FROM kronolith_resources WHERE resource_id = ?'; - - $results = $this->_db->getRow($query, array($id), DB_FETCHMODE_ASSOC); - if ($results instanceof PEAR_Error) { - throw new Horde_Exception($results->getMessage()); - } - if (empty($results)) { - throw new Horde_Exception('Resource not found'); - } - $return = array(); - foreach ($results as $field => $value) { - $return[str_replace('resource_', '', $field)] = $this->convertFromDriver($value); - } - - return $return; - } - - /** - * Obtain the resource id associated with the given calendar uid. - * - * @param string $calendar The calendar's uid - * - * @return int The Kronolith_Resource id - * @throws Horde_Exception - */ - public function getResourceIdByCalendar($calendar) - { - $query = 'SELECT resource_id FROM kronolith_resources WHERE resource_calendar = ?'; - $results = $this->_db->getOne($query, array($calendar)); - if ($results instanceof PEAR_Error) { - throw new Horde_Exception($results->getMessage()); - } - if (empty($results)) { - throw new Horde_Exception('Resource not found'); - } - - return $results; - } - - /** - * Return a list of Kronolith_Resources - * - * This method will likely be a moving target as group resources are - * fleshed out. - * - */ - function listResources($params = array()) - { - $query = 'SELECT resource_id, resource_name, resource_calendar, resource_category FROM kronolith_resources'; - $results = $this->_db->getAll($query, null, DB_FETCHMODE_ASSOC); - if ($results instanceof PEAR_Error) { - throw new Horde_Exception($results->getMessage()); - } - - return $results; - } - - /** * Attempts to open a connection to the SQL server. * * @return boolean True. diff --git a/kronolith/lib/Event.php b/kronolith/lib/Event.php index 06d6c219b..e17bdebd9 100644 --- a/kronolith/lib/Event.php +++ b/kronolith/lib/Event.php @@ -1544,7 +1544,7 @@ abstract class Kronolith_Event /** * Adds a Kronolith_Resource to this event. * No validation or acceptence/denial is done here...it should be done - * when saving the Event so we can capture any errors? + * when saving the Event. * * @param Kronolith_Resource $resource The resource to add * diff --git a/kronolith/lib/Event/Kolab.php b/kronolith/lib/Event/Kolab.php index 6e5a35f2a..0994122ad 100644 --- a/kronolith/lib/Event/Kolab.php +++ b/kronolith/lib/Event/Kolab.php @@ -269,4 +269,24 @@ class Kronolith_Event_Kolab extends Kronolith_Event return $event; } + /** + * Function to check availability and auto accept/decline for each resource + * attached to this event. Needed here instead of in Kronolith_Driver::saveEvent + * since the _properties array is already built at that point. + * + * @return unknown_type + */ + public function checkResources() + { + foreach ($this->_resources as $id => $resource) { + $r = Kronolith::getResource($id); + if ($r->isFree($this)) { + $r->addEvent($this); + $this->addResource($r, Kronolith::RESPONSE_ACCEPTED); + } else { + $this->addResource($r, Kronolith::RESPONSE_DECLINED); + } + } + } + } diff --git a/kronolith/lib/Event/Resource.php b/kronolith/lib/Event/Resource.php new file mode 100644 index 000000000..0f7148d47 --- /dev/null +++ b/kronolith/lib/Event/Resource.php @@ -0,0 +1,219 @@ + + * @author Chuck Hagenbuch + * @author Jan Schneider + * @author Michael J. Rubinsky + * + * @package Kronolith + */ +class Kronolith_Event_Resource extends Kronolith_Event +{ + /** + * The type of the calender this event exists on. + * + * @var string + */ + protected $_calendarType = 'resource'; + + /** + * @var array + */ + private $_properties = array(); + + public function fromDriver($SQLEvent) + { + $driver = $this->getDriver(); + + $this->allday = (bool)$SQLEvent['event_allday']; + if (!$this->allday && $driver->getParam('utc')) { + $tz_local = date_default_timezone_get(); + $this->start = new Horde_Date($SQLEvent['event_start'], 'UTC'); + $this->start->setTimezone($tz_local); + $this->end = new Horde_Date($SQLEvent['event_end'], 'UTC'); + $this->end->setTimezone($tz_local); + } else { + $this->start = new Horde_Date($SQLEvent['event_start']); + $this->end = new Horde_Date($SQLEvent['event_end']); + } + + $this->durMin = ($this->end->timestamp() - $this->start->timestamp()) / 60; + + $this->title = $driver->convertFromDriver($SQLEvent['event_title']); + $this->eventID = $SQLEvent['event_id']; + $this->setUID($SQLEvent['event_uid']); + $this->creatorID = $SQLEvent['event_creator_id']; + + if (!empty($SQLEvent['event_recurtype'])) { + $this->recurrence = new Horde_Date_Recurrence($this->start); + $this->recurrence->setRecurType((int)$SQLEvent['event_recurtype']); + $this->recurrence->setRecurInterval((int)$SQLEvent['event_recurinterval']); + if (isset($SQLEvent['event_recurenddate'])) { + if ($driver->getParam('utc')) { + $recur_end = new Horde_Date($SQLEvent['event_recurenddate'], 'UTC'); + if ($recur_end->min == 0) { + /* Old recurrence end date format. */ + $recur_end = new Horde_Date($SQLEvent['event_recurenddate']); + $recur_end->hour = 23; + $recur_end->min = 59; + $recur_end->sec = 59; + } else { + $recur_end->setTimezone(date_default_timezone_get()); + } + } else { + $recur_end = new Horde_Date($SQLEvent['event_recurenddate']); + $recur_end->hour = 23; + $recur_end->min = 59; + $recur_end->sec = 59; + } + $this->recurrence->setRecurEnd($recur_end); + } + if (isset($SQLEvent['event_recurcount'])) { + $this->recurrence->setRecurCount((int)$SQLEvent['event_recurcount']); + } + if (isset($SQLEvent['event_recurdays'])) { + $this->recurrence->recurData = (int)$SQLEvent['event_recurdays']; + } + if (!empty($SQLEvent['event_exceptions'])) { + $this->recurrence->exceptions = explode(',', $SQLEvent['event_exceptions']); + } + } + + if (isset($SQLEvent['event_location'])) { + $this->location = $driver->convertFromDriver($SQLEvent['event_location']); + } + if (isset($SQLEvent['event_private'])) { + $this->private = (bool)($SQLEvent['event_private']); + } + if (isset($SQLEvent['event_status'])) { + $this->status = (int)$SQLEvent['event_status']; + } + if (isset($SQLEvent['event_attendees'])) { + $this->attendees = array_change_key_case($driver->convertFromDriver(unserialize($SQLEvent['event_attendees']))); + } + if (isset($SQLEvent['event_resources'])) { + $this->_resources = array_change_key_case($driver->convertFromDriver(unserialize($SQLEvent['event_resources']))); + } + if (isset($SQLEvent['event_description'])) { + $this->description = $driver->convertFromDriver($SQLEvent['event_description']); + } + if (isset($SQLEvent['event_alarm'])) { + $this->alarm = (int)$SQLEvent['event_alarm']; + } + if (isset($SQLEvent['event_alarm_methods'])) { + $this->methods = $driver->convertFromDriver(unserialize($SQLEvent['event_alarm_methods'])); + } + $this->initialized = true; + $this->stored = true; + } + + public function toDriver() + { + $driver = $this->getDriver(); + + /* Basic fields. */ + $this->_properties['event_creator_id'] = $driver->convertToDriver($this->getCreatorId()); + $this->_properties['event_title'] = $driver->convertToDriver($this->title); + $this->_properties['event_description'] = $driver->convertToDriver($this->getDescription()); + $this->_properties['event_location'] = $driver->convertToDriver($this->getLocation()); + $this->_properties['event_private'] = (int)$this->isPrivate(); + $this->_properties['event_status'] = $this->getStatus(); + $this->_properties['event_attendees'] = serialize($driver->convertToDriver($this->getAttendees())); + $this->_properties['event_resources'] = serialize($driver->convertToDriver($this->getResources())); + $this->_properties['event_modified'] = $_SERVER['REQUEST_TIME']; + + if ($this->isAllDay()) { + $this->_properties['event_start'] = $this->start->strftime('%Y-%m-%d %H:%M:%S'); + $this->_properties['event_end'] = $this->end->strftime('%Y-%m-%d %H:%M:%S'); + $this->_properties['event_allday'] = 1; + } else { + if ($driver->getParam('utc')) { + $start = clone $this->start; + $end = clone $this->end; + $start->setTimezone('UTC'); + $end->setTimezone('UTC'); + } else { + $start = $this->start; + $end = $this->end; + } + $this->_properties['event_start'] = $start->strftime('%Y-%m-%d %H:%M:%S'); + $this->_properties['event_end'] = $end->strftime('%Y-%m-%d %H:%M:%S'); + $this->_properties['event_allday'] = 0; + } + + /* Alarm. */ + $this->_properties['event_alarm'] = (int)$this->getAlarm(); + + /* Alarm Notification Methods. */ + $this->_properties['event_alarm_methods'] = serialize($driver->convertToDriver($this->methods)); + + /* Recurrence. */ + if (!$this->recurs()) { + $this->_properties['event_recurtype'] = 0; + } else { + $recur = $this->recurrence->getRecurType(); + if ($this->recurrence->hasRecurEnd()) { + if ($driver->getParam('utc')) { + $recur_end = clone $this->recurrence->recurEnd; + $recur_end->setTimezone('UTC'); + } else { + $recur_end = $this->recurrence->recurEnd; + } + } else { + $recur_end = new Horde_Date(array('year' => 9999, 'month' => 12, 'mday' => 31, 'hour' => 23, 'min' => 59, 'sec' => 59)); + } + + $this->_properties['event_recurtype'] = $recur; + $this->_properties['event_recurinterval'] = $this->recurrence->getRecurInterval(); + $this->_properties['event_recurenddate'] = $recur_end->format('Y-m-d H:i:s'); + $this->_properties['event_recurcount'] = $this->recurrence->getRecurCount(); + + switch ($recur) { + case Horde_Date_Recurrence::RECUR_WEEKLY: + $this->_properties['event_recurdays'] = $this->recurrence->getRecurOnDays(); + break; + } + $this->_properties['event_exceptions'] = implode(',', $this->recurrence->getExceptions()); + } + } + + public function getProperties() + { + return $this->_properties; + } + + /** + * Returns a reference to a driver that's valid for this event. + * + * @return Kronolith_Driver A driver that this event can use to save + * itself, etc. + */ + public function getDriver() + { + return Kronolith::getDriver('Resource', $this->_calendar); + } + + /** + * Encapsulates permissions checking. For now, admins, and ONLY admins have + * any permissions to a resource's events. + * + * @param integer $permission The permission to check for. + * @param string $user The user to check permissions for. + * + * @return boolean + */ + public function hasPermission($permission, $user = null) + { + if (Horde_Auth::isAdmin()) { + return true; + } + + return false; + } + +} diff --git a/kronolith/lib/Event/Sql.php b/kronolith/lib/Event/Sql.php index 915241b7c..7937e048b 100644 --- a/kronolith/lib/Event/Sql.php +++ b/kronolith/lib/Event/Sql.php @@ -217,7 +217,7 @@ class Kronolith_Event_Sql extends Kronolith_Event public function checkResources() { foreach ($this->_resources as $id => $resource) { - $r = Kronolith_Resource::getResource($id); + $r = Kronolith::getResource($id); if ($r->isFree($this)) { $r->addEvent($this); $this->addResource($r, Kronolith::RESPONSE_ACCEPTED); diff --git a/kronolith/lib/FreeBusy.php b/kronolith/lib/FreeBusy.php index a5d1a676a..a931e4c54 100644 --- a/kronolith/lib/FreeBusy.php +++ b/kronolith/lib/FreeBusy.php @@ -35,7 +35,7 @@ class Kronolith_FreeBusy { if (is_a($share, 'PEAR_Error')) { // Might be a Kronolith_Resource try { - $resource = Kronolith_Resource::isResourceCalendar($calendar[0]); + $resource = Kronolith::isResourceCalendar($calendar[0]); $owner = $calendar[0]; } catch (Horde_Exception $e) { return $returnObj ? $share : ''; diff --git a/kronolith/lib/Kronolith.php b/kronolith/lib/Kronolith.php index d87e2754f..727ea9a0a 100644 --- a/kronolith/lib/Kronolith.php +++ b/kronolith/lib/Kronolith.php @@ -315,6 +315,21 @@ class Kronolith } } + /* Resource calendars (this would only be populated if explicitly + * requested in the request, so include them if this is set regardless + * of $calendars value). + */ + if (!empty($GLOBALS['display_resource_calendars'])) { + $driver = self::getDriver('Resource'); + foreach ($GLOBALS['display_resource_calendars'] as $calendar) { + $driver->open($calendar); + $events = $driver->listEvents($startDate, $endDate, true); + if (!is_a($events, 'PEAR_Error')) { + self::mergeEvents($results, $events); + } + } + } + if ($showRemote) { /* Horde applications providing listTimeObjects. */ $driver = self::getDriver('Horde'); @@ -738,7 +753,7 @@ class Kronolith $GLOBALS['display_external_calendars'][] = $calendarId; } } elseif (strncmp($calendarId, 'resource_', 9) === 0) { - $resource_cal = $calendarId; + $GLOBALS['display_resource_calendars'] = array($calendarId); } else { if (!in_array($calendarId, $GLOBALS['display_calendars'])) { $GLOBALS['display_calendars'][] = $calendarId; @@ -787,10 +802,6 @@ class Kronolith } } -// if (!empty($resource_cal)) { -// $GLOBALS['display_calendars'][] = $resource_cal; -// } - /* Make sure all the remote calendars still exist. */ $_temp = $GLOBALS['display_remote_calendars']; $GLOBALS['display_remote_calendars'] = array(); @@ -1707,6 +1718,7 @@ class Kronolith $params = array(); switch ($driver) { case 'Sql': + case 'Resource': $params = Horde::getDriverConfig('calendar', 'sql'); break; @@ -1793,6 +1805,8 @@ class Kronolith if (Horde_Util::getFormData('calendar') == '**remote') { $event = self::getDriver('Ical', Horde_Util::getFormData('remoteCal')) ->getEvent(Horde_Util::getFormData('eventID')); + } elseif (strncmp(Horde_Util::getFormData('calendar'), 'resource_', 9) === 0) { + $event = self::getDriver('Resource', Horde_Util::getFormData('calendar'))->getEvent(Horde_Util::getFormData('eventID')); } elseif ($uid = Horde_Util::getFormData('uid')) { $event = self::getDriver()->getByUID($uid); } else { @@ -1801,6 +1815,7 @@ class Kronolith } if (!is_a($event, 'PEAR_Error') && !$event->hasPermission(PERMS_READ)) { + var_dump($event); $event = PEAR::raiseError(_("Permission Denied")); } @@ -1974,4 +1989,54 @@ class Kronolith return self::$_tagger; } + /** + * Adds a new resource to storage + * + * @param Kronolith_Resource $resource + * + * @return unknown_type + */ + static public function addResource($resource) + { + // Create a new calendar id. + $calendar = 'resource_' . hash('md5', microtime()); + $resource->calendar = $calendar; + $driver = Kronolith::getDriver('Resource'); + + return $driver->save($resource); + } + + /** + * + * @return array of Kronolith_Resource objects + */ + static public function listResources($params = array()) + { + // Query kronolith_resource table for all(?) available resources? + // maybe by 'type' or 'name'? type would be arbitrary? + $driver = Kronolith::getDriver('Resource'); + $resources = $driver->listResources($params); + $return = array(); + foreach ($resources as $resource) { + $return[] = new Kronolith_Resource_Single($resource); + } + + return $return; + } + + static public function getResource($id) + { + $driver = Kronolith::getDriver('Resource'); + return new Kronolith_Resource_Single($driver->getResource($id)); + } + + static public function isResourceCalendar($calendar) + { + if (strncmp($calendar, 'resource_', 9) === 0) { + return true; + } + + return false; + } + } diff --git a/kronolith/lib/Resource.php b/kronolith/lib/Resource.php deleted file mode 100644 index 5257f7771..000000000 --- a/kronolith/lib/Resource.php +++ /dev/null @@ -1,88 +0,0 @@ - - * @package Kronolith - */ -class Kronolith_Resource -{ - static protected $_driver; - - /** - * - * @return array of Kronolith_Resource objects - */ - static public function listResources($params = array()) - { - // Query kronolith_resource table for all(?) available resources? - // maybe by 'type' or 'name'? type would be arbitrary? - if (empty(self::$_driver)) { - self::$_driver = Kronolith::getDriver('Sql'); - } - - $resources = self::$_driver->listResources($params); - $return = array(); - foreach ($resources as $resource) { - $return[] = new Kronolith_Resource_Single($resource); - } - - return $return; - } - - /** - * Adds a new resource to storage - * - * @param Kronolith_Resource $resource - * @return unknown_type - */ - static public function addResource($resource) - { - // Create a new calendar id. - $calendar = 'resource_' . hash('md5', microtime()); - $resource->calendar = $calendar; - - if (empty(self::$_driver)) { - self::$_driver = Kronolith::getDriver('Sql'); - } - - return self::$_driver->saveResource($resource); - } - - /** - * Removes a resource from storage - * - * @param Kronolith_Resource $resource - * @return boolean - * @throws Horde_Exception - */ - static public function removeResource($resource) - { - - } - - static public function getResource($id) - { - $driver = Kronolith::getDriver('Sql'); - return new Kronolith_Resource_Single($driver->getResource($id)); - } - - static public function isResourceCalendar($calendar) - { - if (strncmp($calendar, 'resource_', 9) === 0) { - return true; - } - } - -} \ No newline at end of file diff --git a/kronolith/lib/Resource/Single.php b/kronolith/lib/Resource/Single.php index cfbe3b0b7..f03e5b9d0 100644 --- a/kronolith/lib/Resource/Single.php +++ b/kronolith/lib/Resource/Single.php @@ -13,11 +13,12 @@ class Kronolith_Resource_Single extends Kronolith_Resource_Base { /** - * Should this take an event, or a time range? + * Determine if the resource is free during the time period for the + * supplied event. * - * @param $startTime - * @param $endTime - * @return unknown_type + * @param Kronolith_Event $event + * + * @return boolean */ public function isFree($event) { diff --git a/kronolith/lib/View/Month.php b/kronolith/lib/View/Month.php index 6628300b8..795306f0b 100644 --- a/kronolith/lib/View/Month.php +++ b/kronolith/lib/View/Month.php @@ -101,7 +101,7 @@ class Kronolith_View_Month { $this->_currentCalendars = array(true); } - $this->_events = Kronolith::listEvents($startDate, $endDate, $GLOBALS['display_calendars']); + $this->_events = Kronolith::listEvents($startDate, $endDate); if (is_a($this->_events, 'PEAR_Error')) { $GLOBALS['notification']->push($this->_events, 'horde.error'); $this->_events = array(); diff --git a/kronolith/resources.php b/kronolith/resources.php index e8b45bd82..6a6e8283a 100644 --- a/kronolith/resources.php +++ b/kronolith/resources.php @@ -7,23 +7,27 @@ require_once dirname(__FILE__) . '/lib/base.php'; $title = _("Edit resources"); require KRONOLITH_TEMPLATES . '/common-header.inc'; - +require KRONOLITH_TEMPLATES . '/menu.inc'; /* Test creating a new resource */ -//$new = array('name' => _("Big Meeting Room"), +//$new = array('name' => _("Another Big Meeting Room"), // 'category' => 'conference rooms'); // //$resource = new Kronolith_Resource_Single($new); -//$results = Kronolith_Resource::addResource($resource); +//$results = Kronolith::addResource($resource); //var_dump($results); /* Test adding resource to event */ -$resource = Kronolith_Resource::getResource(9); +$resource = Kronolith::getResource(9); + +/* Any driver/event */ $driver = Kronolith::getDriver('Sql'); -$event = $driver->getByUID('20090820100656.66097kphc3ecwf8k@localhost'); +$event = $driver->getByUID('20090831145736.98833ff01g9m338k@localhost'); $event->addResource($resource, Kronolith::RESPONSE_NONE); $event->save(); -//var_dump($resource->getFreeBusy(null, null, true)); +// +////var_dump($resource->getFreeBusy(null, null, true)); +// /* Test listing resources */ -var_dump(Kronolith_Resource::listResources()); \ No newline at end of file +//var_dump(Kronolith::listResources()); \ No newline at end of file diff --git a/kronolith/templates/calendar_titles.inc b/kronolith/templates/calendar_titles.inc index 587bc99ee..afefc0f23 100644 --- a/kronolith/templates/calendar_titles.inc +++ b/kronolith/templates/calendar_titles.inc @@ -3,6 +3,12 @@ $calendar_names = array(); foreach ($GLOBALS['display_calendars'] as $calendarId) { $calendar_names[] = htmlspecialchars($GLOBALS['all_calendars'][$calendarId]->get('name')); } +if (!empty($GLOBALS['display_resource_calendars'])) { + foreach ($GLOBALS['display_resource_calendars'] as $c) { + $rc = Kronolith::getResource(Kronolith::getDriver('Resource')->getResourceIdByCalendar($c)); + $calendar_names[] = htmlspecialchars($rc->name); + } +} ?>

-- 2.11.0