$actionID = 'clear';
}
$actionValue = Horde_Util::getFormData('actionValue');
-
// Perform the specified action, if there is one.
switch ($actionID) {
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'),
);
}
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);
}
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);
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'));
<?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/)
*
/**
* 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.
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;
public function delete($resource)
{
if (!$resource->get('calendar') || !$resource->getId()) {
- var_dump($resource);
throw new Horde_Exception(_("Resource not valid."));
}
*/
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) {
*/
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());
}
/* 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');
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")));
}
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);
{
$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")));
}
$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')) {
var $_requiredMembers = array();
var $_optionalMembers = array();
- var $_resourceMembers = array();
+ var $_requiredResourceMembers = array();
+ var $_optionalResourceMembers = array();
var $_timeBlocks = array();
var $_startHour;
$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)
$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);
$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();
$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);
$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,
$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);
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;
}
+
}
}
--- /dev/null
+<?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
* 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
*/
}
/**
- * Obtain the resource's internal id.
+ * Obtain the resource's internal identifier.
*
- * @return integer The id.
+ * @return mixed The id.
*/
public function getId()
{
}
/**
- * 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
*/
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;
- }
+ //}
}
/**
*/
abstract public function setId($id);
+ /**
+ * Get ResponseType for this resource.
+ * @return unknown_type
+ */
+ abstract public function getResponseType();
+
}
\ No newline at end of file
/* 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) ||
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;
+ }
+
}
}
}
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();
}
}
+ public function getResponseType()
+ {
+ return $this->get('response_type');
+ }
+
}
\ No newline at end of file
$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';
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)
);
<tr class="item nowrap leftAlign">
<th width="2%"> </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 -->
<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>