Large bit of work on Kronolith Resources.
authorMichael J. Rubinsky <mrubinsk@horde.org>
Thu, 3 Sep 2009 17:23:22 +0000 (13:23 -0400)
committerMichael J. Rubinsky <mrubinsk@horde.org>
Tue, 29 Sep 2009 20:53:50 +0000 (16:53 -0400)
 - 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::)

13 files changed:
kronolith/lib/Driver/Resource.php [new file with mode: 0644]
kronolith/lib/Driver/Sql.php
kronolith/lib/Event.php
kronolith/lib/Event/Kolab.php
kronolith/lib/Event/Resource.php [new file with mode: 0644]
kronolith/lib/Event/Sql.php
kronolith/lib/FreeBusy.php
kronolith/lib/Kronolith.php
kronolith/lib/Resource.php [deleted file]
kronolith/lib/Resource/Single.php
kronolith/lib/View/Month.php
kronolith/resources.php
kronolith/templates/calendar_titles.inc

diff --git a/kronolith/lib/Driver/Resource.php b/kronolith/lib/Driver/Resource.php
new file mode 100644 (file)
index 0000000..977e9d4
--- /dev/null
@@ -0,0 +1,467 @@
+<?php
+/**
+ * The Kronolith_Driver_Sql class implements the Kronolith_Driver API for a
+ * SQL backend.
+ *
+ * Copyright 1999-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author  Luc Saillard <luc.saillard@fr.alcove.com>
+ * @author  Chuck Hagenbuch <chuck@horde.org>
+ * @author  Jan Schneider <jan@horde.org>
+ * @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."));
+    }
+
+}
index 2675433..f356a8d 100644 (file)
@@ -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.
index 06d6c21..e17bdeb 100644 (file)
@@ -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
      *
index 6e5a35f..0994122 100644 (file)
@@ -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 (file)
index 0000000..0f7148d
--- /dev/null
@@ -0,0 +1,219 @@
+<?php
+/**
+ * Copyright 1999-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author  Luc Saillard <luc.saillard@fr.alcove.com>
+ * @author  Chuck Hagenbuch <chuck@horde.org>
+ * @author  Jan Schneider <jan@horde.org>
+ * @author  Michael J. Rubinsky <mrubinsk@horde.org>
+ *
+ * @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;
+    }
+
+}
index 915241b..7937e04 100644 (file)
@@ -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);
index a5d1a67..a931e4c 100644 (file)
@@ -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 : '';
index d87e275..727ea9a 100644 (file)
@@ -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 (file)
index 5257f77..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-/**
- * Base class for dealing with Kronolith_Resource objects. Handles basic
- * creation/deletion/listing by delegating to the underlying Kronolith_Driver
- * object.
- *
- * For now, assume SQL driver only. Could probably easily extend this to use
- * different backend drivers if/when support is added to those drivers for
- * resources.
- *
- * Copyright 2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael J. Rubinsky <mrubinsk@horde.org>
- * @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
index cfbe3b0..f03e5b9 100644 (file)
 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)
     {
index 6628300..795306f 100644 (file)
@@ -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();
index e8b45bd..6a6e828 100644 (file)
@@ -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
index 587bc99..afefc0f 100644 (file)
@@ -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);
+    }
+}
 ?>
 <div id="calendarPrint">
  <br />