More additions based on some discussion with Gunnar in IRC:
authorMichael J. Rubinsky <mrubinsk@horde.org>
Sat, 12 Sep 2009 15:06:36 +0000 (11:06 -0400)
committerMichael J. Rubinsky <mrubinsk@horde.org>
Tue, 29 Sep 2009 20:53:54 +0000 (16:53 -0400)
 - Allow specifying if a resource is required or optional
 - Add a response_type property to resources. Specifies if REQUESTS are
   either always accepted, always denied, automatically accepted/denied
   based on actual availability, handled manually (still todo), or simply
   ignored (set response to NONE).

Also, try to clean up the implementation - trying to make it more likely
to be able to be extened for kolab. No idea if this helps of not though ;)

13 files changed:
kronolith/attendees.php
kronolith/lib/Driver/Resource.php
kronolith/lib/Driver/Sql.php
kronolith/lib/Forms/CreateResource.php
kronolith/lib/Forms/EditResource.php
kronolith/lib/FreeBusy/View.php
kronolith/lib/Kronolith.php
kronolith/lib/Resource.php [new file with mode: 0644]
kronolith/lib/Resource/Base.php
kronolith/lib/Resource/Single.php
kronolith/resources/edit.php
kronolith/scripts/upgrades/2009-08-17_add_resources.sql
kronolith/templates/attendees/attendees.inc

index d0fce0d..5f01e53 100644 (file)
@@ -29,7 +29,6 @@ if (Horde_Util::getFormData('clearAll')) {
     $actionID =  'clear';
 }
 $actionValue = Horde_Util::getFormData('actionValue');
-
 // Perform the specified action, if there is one.
 switch ($actionID) {
 case 'add':
@@ -105,9 +104,20 @@ case 'add':
     if (!empty($newResource)) {
         $resource = Kronolith::getDriver('Resource')->getResource($newResource);
 
+        /* If we know we always accept/deny mark it that way now. */
+        /* @TODO: Should we attempt to get the proposed event time from the event form and pass it here? */
+        $type = $resource->getResponseType();
+        if ($type == Kronolith_Resource::RESPONSETYPE_ALWAYS_ACCEPT) {
+            $response = Kronolith::RESPONSE_ACCEPTED;
+        } elseif ($type == Kronolith_Resource::RESPONSETYPE_ALWAYS_DECLINE) {
+            $response = Kronolith::RESPONSE_DECLINED;
+        } else {
+            $response = Kronolith::RESPONSE_NONE;
+        }
+
         $resources[$newResource] = array(
-            'attendance' => Kronolith::PART_IGNORE,
-            'response'   => Kronolith::RESPONSE_NONE,
+            'attendance' => Kronolith::PART_REQUIRED,
+            'response'   => $response,
             'name'       => $resource->get('name'),
         );
 
@@ -153,6 +163,15 @@ case 'removeResource':
     }
     break;
 
+case 'changeResourceResp':
+    //@TODO: What else to do here? Dissallow if responsetype is auto?
+    list($partval, $partname) = explode(' ', $actionValue, 2);
+    if (isset($resources[$partname])) {
+        $resources[$partname]['response'] = $partval;
+        $_SESSION['kronolith']['resources'] = $resources;
+    }
+    break;
+
 case 'changeatt':
     // Change the attendance status of an attendee
     list($partval, $partname) = explode(' ', $actionValue, 2);
@@ -162,6 +181,15 @@ case 'changeatt':
     }
     break;
 
+case 'changeResourceAtt':
+    // Change attendance status of a resource
+    list($partval, $partname) = explode(' ', $actionValue, 2);
+    if (isset($resources[$partname])) {
+        $resources[$partname]['attendance'] = $partval;
+        $_SESSION['kronolith']['resources'] = $resources;
+    }
+    break;
+
 case 'changeresp':
     // Change the response status of an attendee
     list($partval, $partname) = explode(' ', $actionValue, 2);
@@ -272,9 +300,19 @@ foreach ($attendees as $email => $status) {
 if (count($resources)) {
     $driver = Kronolith::getDriver('Resource');
     foreach ($resources as $r_id => $resource) {
-        $r = $driver->getResource($r_id);
-        $vfb = $r->getFreeBusy(null, null, true);
-        $attendee_view->addResourceMember($vfb);
+        try {
+            $r = $driver->getResource($r_id);
+            $vfb = $r->getFreeBusy(null, null, true);
+            if ($resource['attendance'] == Kronolith::PART_REQUIRED) {
+                $attendee_view->addRequiredResourceMember($vfb);
+            } else {
+                $attendee_view->addOptionalResourceMember($vfb);
+            }
+        } catch (Horde_Exception $e) {
+            $notification->push(
+                sprintf(_("Error retrieving free/busy information for %s: %s"),
+                    $r_id, $e->getMessage()));
+        }
     }
 }
 $date = sprintf("%02d%02d%02d000000", Horde_Util::getFormData('year'), Horde_Util::getFormData('month'), Horde_Util::getFormData('mday'));
index 6a8f50d..5aa02a3 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /**
- * The Kronolith_Driver_Sql class implements the Kronolith_Driver API for a
- * SQL backend.
+ * The Kronolith_Driver_Resource class implements the Kronolith_Driver API for
+ * storing resource calendars in a SQL backend.
  *
  * Copyright 1999-2009 The Horde Project (http://www.horde.org/)
  *
@@ -18,6 +18,7 @@ class Kronolith_Driver_Resource extends Kronolith_Driver_Sql
 
     /**
      * Lists all events that satisfy the given conditions.
+     * (Need to override this here since we create a concrete event object).
      *
      * @param Horde_Date $startInterval  Start of range date object.
      * @param Horde_Date $endInterval    End of range data object.
@@ -360,17 +361,17 @@ class Kronolith_Driver_Resource extends Kronolith_Driver_Sql
     public function save($resource)
     {
         if ($resource->getId()) {
-            $query = 'UPDATE kronolith_resources SET resource_name = ?, resource_calendar = ?, resource_category = ? WHERE resource_id = ?';
-            $values = array($resource->get('name'), $resource->get('calendar'), $resource->get('category'), $resource->getId());
+            $query = 'UPDATE kronolith_resources SET resource_name = ?, resource_calendar = ?, resource_category = ? , resource_description = ?, resource_response_type = ?, resource_max_reservations = ? WHERE resource_id = ?';
+            $values = array($resource->get('name'), $resource->get('calendar'), $resource->get('category'), $resource->get('description'), $resource->get('response_type'), $resource->get('max_reservations'), $resource->getId());
             $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 (?, ?, ?, ?)';
+            $query = 'INSERT INTO kronolith_resources (resource_id, resource_name, resource_calendar, resource_category, resource_description, resource_response_type, resource_max_reservations)';
+            $cols_values = ' VALUES (?, ?, ?, ?, ?, ?, ?)';
             $id = $this->_db->nextId('kronolity_resources');
-            $values = array($id, $resource->get('name'), $resource->get('calendar'), $resource->get('category'));
+            $values = array($id, $resource->get('name'), $resource->get('calendar'), $resource->get('category'), $resource->get('description'), $resource->get('response_type'), $resource->get('max_reservations'));
             $result = $this->_write_db->query($query . $cols_values, $values);
             if (!($result instanceof PEAR_Error)) {
                 return true;
@@ -392,7 +393,6 @@ class Kronolith_Driver_Resource extends Kronolith_Driver_Sql
     public function delete($resource)
     {
         if (!$resource->get('calendar') || !$resource->getId()) {
-            var_dump($resource);
             throw new Horde_Exception(_("Resource not valid."));
         }
 
@@ -452,7 +452,7 @@ class Kronolith_Driver_Resource extends Kronolith_Driver_Sql
      */
     public function getResource($id)
     {
-        $query = 'SELECT resource_id, resource_name, resource_calendar, resource_category FROM kronolith_resources WHERE resource_id = ?';
+        $query = 'SELECT resource_id, resource_name, resource_calendar, resource_category, resource_description, resource_response_type, resource_max_reservations FROM kronolith_resources WHERE resource_id = ?';
 
         $results = $this->_db->getRow($query, array($id), DB_FETCHMODE_ASSOC);
         if ($results instanceof PEAR_Error) {
@@ -496,7 +496,7 @@ class Kronolith_Driver_Resource extends Kronolith_Driver_Sql
      */
     public function listResources($params = array())
     {
-        $query = 'SELECT resource_id, resource_name, resource_calendar, resource_category FROM kronolith_resources';
+        $query = 'SELECT resource_id, resource_name, resource_calendar, resource_category, resource_description, resource_response_type, resource_max_reservations FROM kronolith_resources';
         $results = $this->_db->getAll($query, null, DB_FETCHMODE_ASSOC);
         if ($results instanceof PEAR_Error) {
             throw new Horde_Exception($results->getMessage());
index 060bb65..8fc97a2 100644 (file)
@@ -735,6 +735,8 @@ class Kronolith_Driver_Sql extends Kronolith_Driver
         }
 
         /* Remove the event from any resources that are attached to it */
+        //@TODO: Not sure this belongs _here_, but not sure about having to
+        //       call this _everywhere_ we delete an event?
         $resources = $event->getResources();
         if (count($resources)) {
             $rd = Kronolith::getDriver('Resource');
index 0e15600..d0c89fa 100644 (file)
@@ -27,9 +27,16 @@ class Kronolith_CreateResourceForm extends Horde_Form {
     function Kronolith_CreateResourceForm(&$vars)
     {
         parent::Horde_Form($vars, _("Create Resource"));
+        $responses =  array(Kronolith_Resource::RESPONSETYPE_ALWAYS_ACCEPT => _("Always Accept"),
+                            Kronolith_Resource::RESPONSETYPE_ALWAYS_DECLINE => _("Always Decline"),
+                            Kronolith_Resource::RESPONSETYPE_AUTO => _("Automatically"),
+                            Kronolith_Resource::RESPONSETYPE_MANUAL => _("Manual"),
+                            Kronolith_Resource::RESPONSETYPE_NONE => _("None"));
 
         $this->addVariable(_("Name"), 'name', 'text', true);
         $this->addVariable(_("Description"), 'description', 'longtext', false, false, null, array(4, 60));
+        $this->addVariable(_("Response type"), 'responsetype', 'enum', true, false, null, array('enum' => $responses));
+        $this->addVariable(_("Maximum number of overlapping reservations"), 'maxreservations', 'number', true);
         $this->addVariable(_("Category"), 'category', 'text', false);
         $this->setButtons(array(_("Create")));
     }
@@ -37,7 +44,10 @@ class Kronolith_CreateResourceForm extends Horde_Form {
     function execute()
     {
         $new = array('name' => $this->_vars->get('name'),
-                     'category' =>$this->_vars->get('category'));
+                     'category' => $this->_vars->get('category'),
+                     'description' => $this->_vars->get('description'),
+                     'response_type' => $this->_vars->get('response_type'),
+                     'max_reservations' => $this->_vars->get('max_reservations'));
 
         $resource = new Kronolith_Resource_Single($new);
         return $results = Kronolith::addResource($resource);
index 4ca875f..5e0c4a5 100644 (file)
@@ -32,10 +32,16 @@ class Kronolith_EditResourceForm extends Horde_Form {
     {
         $this->_resource = &$resource;
         parent::Horde_Form($vars, sprintf(_("Edit %s"), $resource->get('name')));
-
+        $responses =  array(Kronolith_Resource::RESPONSETYPE_ALWAYS_ACCEPT => _("Always Accept"),
+                            Kronolith_Resource::RESPONSETYPE_ALWAYS_DECLINE => _("Always Decline"),
+                            Kronolith_Resource::RESPONSETYPE_AUTO => _("Automatically"),
+                            Kronolith_Resource::RESPONSETYPE_MANUAL => _("Manual"),
+                            Kronolith_Resource::RESPONSETYPE_NONE => _("None"));
         $this->addHidden('', 'c', 'text', true);
         $this->addVariable(_("Name"), 'name', 'text', true);
         $this->addVariable(_("Description"), 'description', 'longtext', false, false, null, array(4, 60));
+        $this->addVariable(_("Response type"), 'responsetype', 'enum', true, false, null, array('enum' => $responses));
+        $this->addVariable(_("Maximum number of overlapping reservations"), 'maxreservations', 'number', true);
         $this->addVariable(_("Category"), 'category', 'text', false);
         $this->setButtons(array(_("Save")));
     }
@@ -47,6 +53,8 @@ class Kronolith_EditResourceForm extends Horde_Form {
         $this->_resource->set('name', $new_name);
         $this->_resource->set('description', $this->_vars->get('description'));
         $this->_resource->set('category', $this->_vars->get('category'));
+        $this->_resource->set('response_type', $this->_vars->get('responsetype'));
+        $this->_resource->set('max_reservations', $this->_vars->get('maxreservations'));
         if ($original_name != $new_name) {
             $result = Kronolith::getDriver()->rename($original_name, $new_name);
             if (is_a($result, 'PEAR_Error')) {
index 8788c55..015ca4f 100644 (file)
@@ -14,7 +14,8 @@ class Kronolith_FreeBusy_View {
 
     var $_requiredMembers = array();
     var $_optionalMembers = array();
-    var $_resourceMembers = array();
+    var $_requiredResourceMembers = array();
+    var $_optionalResourceMembers = array();
     var $_timeBlocks = array();
 
     var $_startHour;
@@ -33,9 +34,14 @@ class Kronolith_FreeBusy_View {
         $this->_optionalMembers[] = clone $vFreebusy;
     }
 
-    function addResourceMember($vFreebusy)
+    function addOptionalResourceMember($vFreebusy)
     {
-        $this->_resourceMembers[] = clone $vFreebusy;
+        $this->_optionalResourceMembers[] = clone $vFreebusy;
+    }
+
+    function addRequiredResourceMember($vFreebusy)
+    {
+        $this->_requiredResourceMembers[] = clone $vFreebusy;
     }
 
     function render($day = null)
@@ -48,18 +54,28 @@ class Kronolith_FreeBusy_View {
         $this->_render($day);
 
         $vCal = new Horde_iCalendar();
+
+        /* Required members */
         $required = &Horde_iCalendar::newComponent('vfreebusy', $vCal);
         foreach ($this->_requiredMembers as $member) {
             $required->merge($member, false);
         }
+        foreach ($this->_requiredResourceMembers as $member) {
+            $required->merge($member, false);
+        }
         $required->simplify();
 
+        /* Optional members */
         $optional = &Horde_iCalendar::newComponent('vfreebusy', $vCal);
         foreach ($this->_optionalMembers as $member) {
             $optional->merge($member, false);
         }
+        foreach ($this->_optionalResourceMembers as $member) {
+            $optional->merge($member, false);
+        }
         $optional->simplify();
 
+        /* Optimal time calculation */
         $optimal = &Horde_iCalendar::newComponent('vfreebusy', $vCal);
         $optimal->merge($required, false);
         $optimal->merge($optional);
@@ -124,11 +140,20 @@ class Kronolith_FreeBusy_View {
             $html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html');
         }
 
-        // Resources
-        if (count($this->_resourceMembers) > 0) {
+        // Required Resources
+        //if (count($this->_requiredResourceMembers) > 0) {
+        if (count($this->_requiredResourceMembers) > 0 || count($this->_optionalResourceMembers) > 0) {
             $template = new Horde_Template();
             $rows = '';
-            foreach ($this->_resourceMembers as $member) {
+            foreach ($this->_requiredResourceMembers as $member) {
+                $member->simplify();
+                $blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
+                $template = new Horde_Template();
+                $template->set('blocks', $blocks);
+                $template->set('name', $member->getName());
+                $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
+            }
+            foreach ($this->_optionalResourceMembers as $member) {
                 $member->simplify();
                 $blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
                 $template = new Horde_Template();
@@ -137,7 +162,7 @@ class Kronolith_FreeBusy_View {
                 $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
             }
             $template = new Horde_Template();
-            $template->set('title', _("Resources"));
+            $template->set('title', _("Required Resources"));
             $template->set('rows', $rows);
             $template->set('span', count($this->_timeBlocks));
             $template->set('hours', $hours_html);
@@ -145,6 +170,28 @@ class Kronolith_FreeBusy_View {
             $html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html');
         }
 
+//        // Optional Resources
+//        if (count($this->_optionalResourceMembers) > 0) {
+//            $template = new Horde_Template();
+//            $rows = '';
+//            foreach ($this->_optionalResourceMembers as $member) {
+//                $member->simplify();
+//                $blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
+//                $template = new Horde_Template();
+//                $template->set('blocks', $blocks);
+//                $template->set('name', $member->getName());
+//                $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
+//            }
+//            $template = new Horde_Template();
+//            $template->set('title', _("Optional Resources"));
+//            $template->set('rows', $rows);
+//            $template->set('span', count($this->_timeBlocks));
+//            $template->set('hours', $hours_html);
+//            $template->set('legend', '');
+//            $html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html');
+//        }
+
+
         // Possible meeting times.
         $optimal->setAttribute('ORGANIZER', _("All Attendees"));
         $blocks = $this->_getBlocks($optimal,
@@ -167,6 +214,17 @@ class Kronolith_FreeBusy_View {
         $template->set('blocks', $blocks);
         $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
 
+        // Possible meeting times.
+//        $resource->setAttribute('ORGANIZER', _("Required Attendees"));
+//        $blocks = $this->_getBlocks($required,
+//                                    $required->getFreePeriods($this->_start->timestamp(), $this->_end->timestamp()),
+//                                    'meetingblock.html', _("Required Attendees"));
+//
+//        $template = new Horde_Template();
+//        $template->set('name', _("Required Attendees"));
+//        $template->set('blocks', $blocks);
+//        $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
+
         // Reset locale.
         setlocale(LC_NUMERIC, $lc);
 
index b0b2903..1697844 100644 (file)
@@ -2087,13 +2087,39 @@ class Kronolith
     static public function checkResources($event)
     {
         foreach ($event->getResources() as $id => $resource) {
+
+            /* Get the resource */
             $r = Kronolith::getDriver('Resource')->getResource($id);
-            if ($r->isFree($event)) {
+
+            /* Determine if we have to calculate, or just auto-reply */
+            $type = $r->getResponseType();
+            switch($type) {
+            case Kronolith_Resource::RESPONSETYPE_ALWAYS_ACCEPT:
                 $r->addEvent($event);
                 $event->addResource($r, Kronolith::RESPONSE_ACCEPTED);
-            } else {
+                break;
+            case Kronolith_Resource::RESPONSETYPE_AUTO:
+                if ($r->isFree($event)) {
+                    $r->addEvent($event);
+                    $event->addResource($r, Kronolith::RESPONSE_ACCEPTED);
+                } else {
+                   $event->addResource($r, Kronolith::RESPONSE_DECLINED);
+                }
+                break;
+
+            case Kronolith_Resource::RESPONSETYPE_ALWAYS_DECLINE:
                 $event->addResource($r, Kronolith::RESPONSE_DECLINED);
+                break;
+
+            case Kronolith_Resource::RESPONSETYPE_NONE:
+                $event->addResource($r, Kronolith::RESPONSE_NONE);
+                break;
+
+            case Kronolith_Resource::RESPONSETYPE_MANUAL:
+                //???
+                break;
             }
+
         }
     }
 
diff --git a/kronolith/lib/Resource.php b/kronolith/lib/Resource.php
new file mode 100644 (file)
index 0000000..356964e
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ */
+class Kronolith_Resource
+{
+    /* ResponseType constants */
+    const RESPONSETYPE_NONE = 0;
+    const RESPONSETYPE_AUTO = 1;
+    const RESPONSETYPE_ALWAYS_ACCEPT = 2;
+    const RESPONSETYPE_ALWAYS_DECLINE = 3;
+    const RESPONSETYPE_MANUAL = 4; // Send iTip - not sure how that would work without a user account for the resource.
+
+    /**
+     *
+     */
+    public function factory($driver, $params)
+    {
+
+    }
+
+}
\ No newline at end of file
index 0e6661c..d805d43 100644 (file)
@@ -15,6 +15,9 @@ abstract class Kronolith_Resource_Base
      *   category    - The category of this resource...an arbitrary label used
      *                 to group multiple resources for the resource_group implementation
      *   description -
+     *   email       -
+     *   response_type - a RESPONSETYE_* constant
+     *   max_reservations
      *
      * @var array
      */
@@ -47,9 +50,9 @@ abstract class Kronolith_Resource_Base
     }
 
     /**
-     * Obtain the resource's internal id.
+     * Obtain the resource's internal identifier.
      *
-     * @return integer  The id.
+     * @return mixed The id.
      */
     public function getId()
     {
@@ -57,7 +60,7 @@ abstract class Kronolith_Resource_Base
     }
 
     /**
-     * Allow setting of the name and category properties.
+     * Allow setting of properties
      *
      * @param string $property  The property to set
      * @param mixed $value      The value to set to
@@ -66,9 +69,9 @@ abstract class Kronolith_Resource_Base
      */
     public function set($property, $value)
     {
-        if (in_array($property, array('name', 'category', 'calendar'))) {
+        //if (in_array($property, array('name', 'category', 'calendar', 'description'))) {
             $this->_params[$property] = $value;
-        }
+        //}
     }
 
     /**
@@ -167,4 +170,10 @@ abstract class Kronolith_Resource_Base
      */
     abstract public function setId($id);
 
+    /**
+     * Get ResponseType for this resource.
+     * @return unknown_type
+     */
+    abstract public function getResponseType();
+
 }
\ No newline at end of file
index c8e1818..f686b4a 100644 (file)
@@ -36,6 +36,7 @@ class Kronolith_Resource_Single extends Kronolith_Resource_Base
         /* Check for conflicts, ignoring the conflict if it's for the
          * same event that is passed. */
         $uid = $event->getUID();
+        $conflicts = 0;
         foreach ($busy as $events) {
             foreach ($events as $e) {
                 if (!($e->hasStatus(Kronolith::STATUS_CANCELLED) ||
@@ -44,7 +45,12 @@ class Kronolith_Resource_Single extends Kronolith_Resource_Base
 
                      if (!($e->start->compareDateTime($event->end) >= 1 ||
                          $e->end->compareDateTime($event->start) <= -1)) {
-                         return false;
+
+                         /* Conflict, but check to see if we are allowed mulitiple */
+                         if (++$conflicts >= $this->get('max_reservations')) {
+                            return false;
+                         }
+
                      }
                 }
             }
@@ -64,7 +70,7 @@ class Kronolith_Resource_Single extends Kronolith_Resource_Base
     public function addEvent($event)
     {
         /* Get a driver for this resource's calendar */
-        $driver = Kronolith::getDriver('Resource', $this->get('calendar'));
+        $driver = $this->getDriver();
 
         /* Make sure it's not already attached. */
         $uid = $event->getUID();
@@ -123,4 +129,9 @@ class Kronolith_Resource_Single extends Kronolith_Resource_Base
         }
     }
 
+    public function getResponseType()
+    {
+        return $this->get('response_type');
+    }
+
 }
\ No newline at end of file
index 37306c8..8db003b 100644 (file)
@@ -53,6 +53,8 @@ if ($form->validate($vars)) {
 $vars->set('name', $resource->get('name'));
 $vars->set('description', $resource->get('description'));
 $vars->set('category', $resource->get('category'));
+$vars->set('maxreservations', $resource->get('max_reservations'));
+$vars->set('responsetype', $resource->get('response_type'));
 
 $title = $form->getTitle();
 require KRONOLITH_TEMPLATES . '/common-header.inc';
index bc22852..a66d24a 100644 (file)
@@ -6,6 +6,8 @@ CREATE TABLE kronolith_resources (
     resource_calendar VARCHAR(255),
     resource_description TEXT,
     resource_category VARCHAR(255),
+    resource_response_type INT DEFAULT 0,
+    resource_max_reservations INT DEFAULT 1,
     
     PRIMARY KEY (resource_id)
 );
index 29a2490..1ccc2ac 100644 (file)
@@ -81,7 +81,8 @@ function switchDateView(view, date)
 <tr class="item nowrap leftAlign">
  <th width="2%">&nbsp;</th>
  <th width="48%"><?php echo htmlspecialchars(_("Resource")) ?></th>
- <th colspan="2" width="50%"><?php echo htmlspecialchars(_("Status")) ?></th>
+ <th wiidth="25%"><?php echo _("Attendance") ?></th>
+ <th width="25%"><?php echo _("Status") ?></th>
 </tr>
 
 <!--  resources -->
@@ -91,17 +92,21 @@ function switchDateView(view, date)
  <tr>
   <td class="nowrap"><?php echo Horde::link('#', sprintf(_("Remove %s"), $resource['name']), '', '', "performAction('removeResource', " . $id . "); return false;") . Horde::img('delete.png', '', null, $registry->getImageDir('horde')) ?></a></td>
   <td><?php echo htmlspecialchars($resource['name']) ?></td>
+  <td>
+  <label for="<?php echo "resourceattendance_$i" ?>" class="hidden"><?php echo _("Attendance") ?></label>
+   <select id="<?php echo "resourceattendance_$i" ?>" name="<?php echo "resourceattendance_$i" ?>" onchange="performAction('changeResourceAtt', document.attendeesForm.<?php echo "resourceattendance_$i" ?>.value + ' ' + decodeURIComponent('<?php echo rawurlencode($id) ?>'));">
+    <option value="<?php echo Kronolith::PART_REQUIRED ?>"<?php if ($resource['attendance'] == Kronolith::PART_REQUIRED)  echo ' selected="selected"' ?>><?php echo Kronolith::partToString(Kronolith::PART_REQUIRED) ?></option>
+    <option value="<?php echo Kronolith::PART_OPTIONAL ?>"<?php if ($resource['attendance'] == Kronolith::PART_OPTIONAL)  echo ' selected="selected"' ?>><?php echo Kronolith::partToString(Kronolith::PART_OPTIONAL) ?></option>
+    <option value="<?php echo Kronolith::PART_NONE ?>"<?php if ($resource['attendance'] == Kronolith::PART_NONE)  echo ' selected="selected"' ?>><?php echo Kronolith::partToString(Kronolith::PART_NONE) ?></option>
+   </select>
+ </td>
   <td colspan="2">
-    <?php switch ($resource['response']) {
-        case Kronolith::RESPONSE_ACCEPTED:
-            echo _("Accepted");
-            break;
-        case Kronolith::RESPONSE_DECLINED:
-            echo _("Declined");
-            break;
-        default:
-            echo _("Pending");
-    } ?>
+    <select name="<?php echo "resourceresponse_$i" ?>" onchange="performAction('changeResourceResp', document.attendeesForm.<?php echo "resourceresponse_$i" ?>.value + ' ' + decodeURIComponent('<?php echo rawurlencode($id) ?>'));">
+    <option value="<?php echo Kronolith::RESPONSE_ACCEPTED ?>"<?php if ($resource['response'] == Kronolith::RESPONSE_ACCEPTED)  echo ' selected="selected"' ?>><?php echo Kronolith::responseToString(Kronolith::RESPONSE_ACCEPTED) ?></option>
+    <option value="<?php echo Kronolith::RESPONSE_DECLINED ?>"<?php if ($resource['response'] == Kronolith::RESPONSE_DECLINED)  echo ' selected="selected"' ?>><?php echo Kronolith::responseToString(Kronolith::RESPONSE_DECLINED) ?></option>
+    <option value="<?php echo Kronolith::RESPONSE_TENTATIVE ?>"<?php if ($resource['response'] == Kronolith::RESPONSE_TENTATIVE)  echo ' selected="selected"' ?>><?php echo Kronolith::responseToString(Kronolith::RESPONSE_TENTATIVE) ?></option>
+    <option value="<?php echo Kronolith::RESPONSE_NONE ?>"<?php if ($resource['response'] == Kronolith::RESPONSE_NONE)  echo ' selected="selected"' ?>><?php echo Kronolith::responsetoString(Kronolith::RESPONSE_NONE) ?></option>
+   </select>
   </td>
  </tr>