/** * Toggles completion status of this task. Moves a recurring task * to the next occurence on completion. */ public function toggleComplete() { if ($this->completed) { $this->completed_date = null; $this->completed = false; if ($this->recurs()) { /* What do we want do delete here? All completions? * The latest completion? Any completion in the * future?. */ foreach ($this->recurrence->getCompletions() as $completion) { $this->recurrence->deleteCompletion(substr($completion, 0, 4), substr($completion, 4, 2), substr($completion, 6, 2)); } } return; } if ($this->recurs()) { /* Get current occurrence (task due date) */ $current = $this->recurrence->nextActiveRecurrence(new Horde_Date($this->due)); if ($current) { $this->recurrence->addCompletion($current->year, $current->month, $current->mday); /* Advance this occurence by a day to indicate that we * want the following occurence (Recurrence uses days * as minimal time duration between occurrences). */ $current->mday++; /* Only mark this due date completed if there is another * occurence. */ if ($next = $this->recurrence->nextActiveRecurrence($current)) { $this->completed = false; return; } } } $this->completed_date = time(); $this->completed = true; }
/** * Creates a task from a Horde_Icalendar_Vtodo object. * * @param Horde_Icalendar_Vtodo $vTodo The iCalendar data to update from. */ public function fromiCalendar(Horde_Icalendar_Vtodo $vTodo) { /* Owner is always current user. */ $this->owner = $GLOBALS['registry']->getAuth(); try { $name = $vTodo->getAttribute('SUMMARY'); if (!is_array($name)) { $this->name = $name; } } catch (Horde_Icalendar_Exception $e) { } // Not sure why we were mapping the ORGANIZER to the person the // task is assigned to? If anything, this needs to be mapped to // any ATTENDEE fields from the vTodo. // try { // $assignee = $vTodo->getAttribute('ORGANIZER'); // if (!is_array($assignee)) { $this->assignee = $assignee; } // } catch (Horde_Icalendar_Exception $e) {} try { $organizer = $vTodo->getAttribute('ORGANIZER'); if (!is_array($organizer)) { $this->organizer = $organizer; } } catch (Horde_Icalendar_Exception $e) { } // If an attendee matches our from_addr, add current user as assignee. try { $atnames = $vTodo->getAttribute('ATTENDEE'); if (!is_array($atnames)) { $atnames = array($atnames); } $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create(); $all_addrs = $identity->getAll('from_addr'); foreach ($atnames as $index => $attendee) { if ($vTodo->getAttribute('VERSION') < 2) { $addr_ob = new Horde_Mail_Rfc822_Address($attendee); if (!$addr_ob->valid) { continue; } $attendee = $addr_ob->bare_address; $name = $addr_ob->personal; } else { $attendee = str_ireplace('mailto:', '', $attendee); $addr_ob = new Horde_Mail_Rfc822_Address($attendee); if (!$addr_ob->valid) { continue; } $attendee = $addr_ob->bare_address; $name = isset($atparms[$index]['CN']) ? $atparms[$index]['CN'] : null; } if (in_array($attendee, $all_addrs) !== false) { $this->assignee = $GLOBALS['conf']['assignees']['allow_external'] ? $attendee : $GLOBALS['registry']->getAuth(); $this->status = Nag::RESPONSE_ACCEPTED; break; } elseif ($GLOBALS['conf']['assignees']['allow_external']) { $this->assignee = $attendee; } } } catch (Horde_Icalendar_Exception $e) { } // Default to current user as organizer if (empty($this->organizer) && !empty($this->assignee)) { $this->organizer = $identity->getValue('from_addr'); } try { $uid = $vTodo->getAttribute('UID'); if (!is_array($uid)) { $this->uid = $uid; } } catch (Horde_Icalendar_Exception $e) { } try { $relations = $vTodo->getAttribute('RELATED-TO'); if (!is_array($relations)) { $relations = array($relations); } $params = $vTodo->getAttribute('RELATED-TO', true); foreach ($relations as $id => $relation) { if (empty($params[$id]['RELTYPE']) || Horde_String::upper($params[$id]['RELTYPE']) == 'PARENT') { try { $parent = $this->_storage->getByUID($relation, $this->tasklist); $this->parent_id = $parent->id; } catch (Horde_Exception_NotFound $e) { } break; } } } catch (Horde_Icalendar_Exception $e) { } try { $start = $vTodo->getAttribute('DTSTART'); if (!is_array($start)) { // Date-Time field $this->start = $start; } else { // Date field $this->start = mktime(0, 0, 0, (int) $start['month'], (int) $start['mday'], (int) $start['year']); } } catch (Horde_Icalendar_Exception $e) { } try { $due = $vTodo->getAttribute('DUE'); if (is_array($due)) { $this->due = mktime(0, 0, 0, (int) $due['month'], (int) $due['mday'], (int) $due['year']); } elseif (!empty($due)) { $this->due = $due; } } catch (Horde_Icalendar_Exception $e) { } // Recurrence. try { $rrule = $vTodo->getAttribute('RRULE'); if (!is_array($rrule)) { $this->recurrence = new Horde_Date_Recurrence($this->due); if (strpos($rrule, '=') !== false) { $this->recurrence->fromRRule20($rrule); } else { $this->recurrence->fromRRule10($rrule); } // Completions. EXDATE represents completed tasks, just add the // exception. $exdates = $vTodo->getAttributeValues('EXDATE'); if (is_array($exdates)) { foreach ($exdates as $exdate) { if (is_array($exdate)) { $this->recurrence->addCompletion((int) $exdate['year'], (int) $exdate['month'], (int) $exdate['mday']); } } } } } catch (Horde_Icalendar_Exception $e) { } // vCalendar 1.0 alarms try { $alarm = $vTodo->getAttribute('AALARM'); if (!is_array($alarm) && !empty($alarm) && !empty($this->due)) { $this->alarm = intval(($this->due - $alarm) / 60); if ($this->alarm === 0) { // We don't support alarms exactly at due date. $this->alarm = 1; } } } catch (Horde_Icalendar_Exception $e) { } // vCalendar 2.0 alarms foreach ($vTodo->getComponents() as $alarm) { if (!$alarm instanceof Horde_Icalendar_Valarm) { continue; } try { if ($alarm->getAttribute('ACTION') == 'NONE') { continue; } } catch (Horde_Icalendar_Exception $e) { } try { // @todo consider implementing different ACTION types. // $action = $alarm->getAttribute('ACTION'); $trigger = $alarm->getAttribute('TRIGGER'); $triggerParams = $alarm->getAttribute('TRIGGER', true); } catch (Horde_Icalendar_Exception $e) { continue; } if (!is_array($triggerParams)) { $triggerParams = array($triggerParams); } $haveTrigger = false; foreach ($triggerParams as $tp) { if (isset($tp['VALUE']) && $tp['VALUE'] == 'DATE-TIME') { if (isset($tp['RELATED']) && $tp['RELATED'] == 'END') { if ($this->due) { $this->alarm = intval(($this->due - $trigger) / 60); $haveTrigger = true; break; } } else { if ($this->start) { $this->alarm = intval(($this->start - $trigger) / 60); $haveTrigger = true; break; } } } elseif (isset($tp['RELATED']) && $tp['RELATED'] == 'END' && $this->due && $this->start) { $this->alarm = -intval($trigger / 60); $this->alarm -= $this->due - $this->start; $haveTrigger = true; break; } } if (!$haveTrigger) { $this->alarm = -intval($trigger / 60); } break; } // Alarm snoozing/dismissal if ($this->alarm) { try { // If X-MOZ-LASTACK is set, this task is either dismissed or // snoozed. $vTodo->getAttribute('X-MOZ-LASTACK'); try { // If X-MOZ-SNOOZE-TIME is set, this task is snoozed. $snooze = $vTodo->getAttribute('X-MOZ-SNOOZE-TIME'); $this->snooze = intval(($snooze - time()) / 60); } catch (Horde_Icalendar_Exception $e) { // If X-MOZ-SNOOZE-TIME is not set, this event is dismissed. $this->snooze = -1; } } catch (Horde_Icalendar_Exception $e) { } } try { $desc = $vTodo->getAttribute('DESCRIPTION'); if (!is_array($desc)) { $this->desc = $desc; } } catch (Horde_Icalendar_Exception $e) { } try { $priority = $vTodo->getAttribute('PRIORITY'); if (!is_array($priority)) { $this->priority = $priority; } } catch (Horde_Icalendar_Exception $e) { } try { $cat = $vTodo->getAttribute('CATEGORIES'); if (!is_array($cat)) { $this->tags = $cat; } } catch (Horde_Icalendar_Exception $e) { } try { $status = $vTodo->getAttribute('STATUS'); if (!is_array($status)) { $this->completed = !strcasecmp($status, 'COMPLETED'); } } catch (Horde_Icalendar_Exception $e) { } try { $class = $vTodo->getAttribute('CLASS'); if (!is_array($class)) { $class = Horde_String::upper($class); $this->private = $class == 'PRIVATE' || $class == 'CONFIDENTIAL'; } } catch (Horde_Icalendar_Exception $e) { } }
public static function readRecurrenceForm($start, $timezone, $recurrence = null) { $recur = Horde_Util::getFormData('recur'); if (!strlen($recur)) { return $recurrence; } if (!isset($recurrence)) { $recurrence = new Horde_Date_Recurrence($start); } else { $recurrence->setRecurStart($start); } if (Horde_Util::getFormData('recur_end_type') == 'date') { if ($end_date = Horde_Util::getFormData('recur_end_date')) { // From ajax interface. $date_ob = Kronolith::parseDate($end_date, false); $recur_enddate = array('year' => $date_ob->year, 'month' => $date_ob->month, 'day' => $date_ob->mday); } else { // From traditional interface. $recur_enddate = Horde_Util::getFormData('recur_end'); } if ($recurrence->hasRecurEnd()) { $recurEnd = $recurrence->recurEnd; $recurEnd->month = $recur_enddate['month']; $recurEnd->mday = $recur_enddate['day']; $recurEnd->year = $recur_enddate['year']; } else { $recurEnd = new Horde_Date(array('hour' => 23, 'min' => 59, 'sec' => 59, 'month' => $recur_enddate['month'], 'mday' => $recur_enddate['day'], 'year' => $recur_enddate['year']), $timezone); } $recurrence->setRecurEnd($recurEnd); } elseif (Horde_Util::getFormData('recur_end_type') == 'count') { $recurrence->setRecurCount(Horde_Util::getFormData('recur_count')); } elseif (Horde_Util::getFormData('recur_end_type') == 'none') { $recurrence->setRecurCount(0); $recurrence->setRecurEnd(null); } $recurrence->setRecurType($recur); switch ($recur) { case Horde_Date_Recurrence::RECUR_DAILY: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_daily_interval', 1)); break; case Horde_Date_Recurrence::RECUR_WEEKLY: $weekly = Horde_Util::getFormData('weekly'); $weekdays = 0; if (is_array($weekly)) { foreach ($weekly as $day) { $weekdays |= $day; } } if ($weekdays == 0) { // Sunday starts at 0. switch ($start->dayOfWeek()) { case 0: $weekdays |= Horde_Date::MASK_SUNDAY; break; case 1: $weekdays |= Horde_Date::MASK_MONDAY; break; case 2: $weekdays |= Horde_Date::MASK_TUESDAY; break; case 3: $weekdays |= Horde_Date::MASK_WEDNESDAY; break; case 4: $weekdays |= Horde_Date::MASK_THURSDAY; break; case 5: $weekdays |= Horde_Date::MASK_FRIDAY; break; case 6: $weekdays |= Horde_Date::MASK_SATURDAY; break; } } $recurrence->setRecurInterval(Horde_Util::getFormData('recur_weekly_interval', 1)); $recurrence->setRecurOnDay($weekdays); break; case Horde_Date_Recurrence::RECUR_MONTHLY_DATE: switch (Horde_Util::getFormData('recur_monthly_scheme')) { case Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY: case Horde_Date_Recurrence::RECUR_MONTHLY_LAST_WEEKDAY: $recurrence->setRecurType(Horde_Util::getFormData('recur_monthly_scheme')); case Horde_Date_Recurrence::RECUR_MONTHLY_DATE: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_monthly') ? 1 : Horde_Util::getFormData('recur_monthly_interval', 1)); break; default: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_day_of_month_interval', 1)); break; } break; case Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_week_of_month_interval', 1)); break; case Horde_Date_Recurrence::RECUR_MONTHLY_LAST_WEEKDAY: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_last_week_of_month_interval', 1)); break; case Horde_Date_Recurrence::RECUR_YEARLY_DATE: switch (Horde_Util::getFormData('recur_yearly_scheme')) { case Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY: case Horde_Date_Recurrence::RECUR_YEARLY_DAY: $recurrence->setRecurType(Horde_Util::getFormData('recur_yearly_scheme')); case Horde_Date_Recurrence::RECUR_YEARLY_DATE: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_yearly') ? 1 : Horde_Util::getFormData('recur_yearly_interval', 1)); break; default: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_yearly_interval', 1)); break; } break; case Horde_Date_Recurrence::RECUR_YEARLY_DAY: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_yearly_day_interval', $yearly_interval)); break; case Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY: $recurrence->setRecurInterval(Horde_Util::getFormData('recur_yearly_weekday_interval', $yearly_interval)); break; } foreach (array('exceptions', 'completions') as $what) { if ($data = Horde_Util::getFormData($what)) { if (!is_array($data)) { $data = explode(',', $data); } foreach ($data as $date) { list($year, $month, $mday) = sscanf($date, '%04d%02d%02d'); if ($what == 'exceptions') { $recurrence->addException($year, $month, $mday); } else { $recurrence->addCompletion($year, $month, $mday); } } } } return $recurrence; }
/** * Imports a backend specific event object. * * @param mixed $event Backend specific event object that this object * will represent. */ public function fromDriver($event) { $this->id = '_' . $this->_api . $event['id']; $this->icon = !empty($event['icon']) ? $event['icon'] : null; $this->title = $event['title']; $this->description = isset($event['description']) ? $event['description'] : ''; if (isset($event['location'])) { $this->location = $event['location']; } try { $this->start = new Horde_Date($event['start']); $this->end = new Horde_Date($event['end']); } catch (Horde_Date_Exception $e) { throw new Kronolith_Exception($e); } if (isset($event['status'])) { switch ($event['status']) { case 'confirmed': $this->status = Kronolith::STATUS_CONFIRMED; break; case 'tentative': $this->status = Kronolith::STATUS_TENTATIVE; break; default: $this->status = Kronolith::STATUS_FREE; } } else { $this->status = Kronolith::STATUS_FREE; } if (isset($event['private'])) { $this->private = $event['private']; } $this->_params = $event['params']; $this->_link = !empty($event['link']) ? $event['link'] : null; $this->url = !empty($event['url']) ? (string) $event['url'] : null; $this->_editLink = !empty($event['edit_link']) ? $event['edit_link'] : null; $this->_deleteLink = !empty($event['delete_link']) ? $event['delete_link'] : null; $this->_ajaxLink = !empty($event['ajax_link']) ? $event['ajax_link'] : null; $this->_backgroundColor = Kronolith::backgroundColor($event); $this->_foregroundColor = Kronolith::foregroundColor($event); if (isset($event['recurrence'])) { $recurrence = new Horde_Date_Recurrence($this->start); $recurrence->setRecurType($event['recurrence']['type']); if (isset($event['recurrence']['end'])) { $recurrence->setRecurEnd(new Horde_Date($event['recurrence']['end'])); } if (isset($event['recurrence']['interval'])) { $recurrence->setRecurInterval($event['recurrence']['interval']); } if (isset($event['recurrence']['count'])) { $recurrence->setRecurCount($event['recurrence']['count']); } if (isset($event['recurrence']['days'])) { $recurrence->setRecurOnDay($event['recurrence']['days']); } if (isset($event['recurrence']['exceptions'])) { foreach ($event['recurrence']['exceptions'] as $exception) { $recurrence->addException(substr($exception, 0, 4), substr($exception, 4, 2), substr($exception, 6, 2)); } } if (isset($event['recurrence']['completions'])) { foreach ($event['recurrence']['completions'] as $completion) { $recurrence->addCompletion(substr($completion, 0, 4), substr($completion, 4, 2), substr($completion, 6, 2)); } } $this->recurrence = $recurrence; } if (isset($event['owner'])) { $this->_owner = $event['owner']; } if (isset($event['permissions'])) { $this->_permissions = $event['permissions']; } if (isset($event['variable_length'])) { $this->_variableLength = $event['variable_length']; } $this->initialized = true; $this->stored = true; }
public function getInfo(&$vars, &$var, &$info) { $recur = $vars->recurrence; if (!$recur) { return; } $recurrence = new Horde_Date_Recurrence($this->_getDue($var, $vars)); if ($vars->recur_end_type == 'date') { $recurEnd = Nag::parseDate($vars->recur_end, false); $recurEnd->hour = 23; $recurEnd->min = $recurEnd->sec = 59; $recurrence->setRecurEnd($recurEnd); } elseif ($vars->recur_end_type == 'count') { $recurrence->setRecurCount($vars->recur_count); } elseif ($vars->recur_end_type == 'none') { $recurrence->setRecurCount(0); $recurrence->setRecurEnd(null); } $recurrence->setRecurType($recur); switch ($recur) { case Horde_Date_Recurrence::RECUR_DAILY: $recurrence->setRecurInterval($vars->get('recur_daily_interval', 1)); break; case Horde_Date_Recurrence::RECUR_WEEKLY: $weekly = $vars->weekly; $weekdays = 0; if (is_array($weekly)) { foreach ($weekly as $day) { $weekdays |= $day; } } if ($weekdays == 0) { // Sunday starts at 0. switch ($recurrence->start->dayOfWeek()) { case 0: $weekdays |= Horde_Date::MASK_SUNDAY; break; case 1: $weekdays |= Horde_Date::MASK_MONDAY; break; case 2: $weekdays |= Horde_Date::MASK_TUESDAY; break; case 3: $weekdays |= Horde_Date::MASK_WEDNESDAY; break; case 4: $weekdays |= Horde_Date::MASK_THURSDAY; break; case 5: $weekdays |= Horde_Date::MASK_FRIDAY; break; case 6: $weekdays |= Horde_Date::MASK_SATURDAY; break; } } $recurrence->setRecurInterval($vars->get('recur_weekly_interval', 1)); $recurrence->setRecurOnDay($weekdays); break; case Horde_Date_Recurrence::RECUR_MONTHLY_DATE: switch ($vars->recur_monthly_scheme) { case Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY: case Horde_Date_Recurrence::RECUR_MONTHLY_LAST_WEEKDAY: $recurrence->setRecurType($vars->recur_monthly_scheme); case Horde_Date_Recurrence::RECUR_MONTHLY_DATE: $recurrence->setRecurInterval($vars->recur_monthly ? 1 : $vars->get('recur_monthly_interval', 1)); break; default: $recurrence->setRecurInterval($vars->get('recur_day_of_month_interval', 1)); break; } break; case Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY: $recurrence->setRecurInterval($vars->get('recur_week_of_month_interval', 1)); break; case Horde_Date_Recurrence::RECUR_MONTHLY_LAST_WEEKDAY: $recurrence->setRecurInterval($vars->get('recur_last_week_of_month_interval', 1)); break; case Horde_Date_Recurrence::RECUR_YEARLY_DATE: switch ($vars->recur_yearly_scheme) { case Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY: case Horde_Date_Recurrence::RECUR_YEARLY_DAY: $recurrence->setRecurType($vars->recur_yearly_scheme); case Horde_Date_Recurrence::RECUR_YEARLY_DATE: $recurrence->setRecurInterval($vars->recur_yearly ? 1 : $vars->get('recur_yearly_interval', 1)); break; default: $recurrence->setRecurInterval($vars->get('recur_yearly_interval', 1)); break; } break; case Horde_Date_Recurrence::RECUR_YEARLY_DAY: $recurrence->setRecurInterval($vars->get('recur_yearly_day_interval', $yearly_interval)); break; case Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY: $recurrence->setRecurInterval($vars->get('recur_yearly_weekday_interval', $yearly_interval)); break; } foreach (array('exceptions', 'completions') as $what) { if ($vars->{$what}) { foreach ($vars->{$what} as $date) { list($year, $month, $mday) = sscanf($date, '%04d%02d%02d'); if ($what == 'exceptions') { $recurrence->addException($year, $month, $mday); } else { $recurrence->addCompletion($year, $month, $mday); } } } } $info = $recurrence; }
/** */ public function testCompletions() { $r = new Horde_Date_Recurrence(new Horde_Date(1970, 1, 1)); $r->setRecurType(Horde_Date_Recurrence::RECUR_DAILY); $r->addCompletion(1970, 1, 2); $this->assertTrue($r->hasCompletion(1970, 1, 2)); $this->assertEquals(1, count($r->getCompletions())); $r->addCompletion(1970, 1, 4); $this->assertEquals(2, count($r->getCompletions())); $r->deleteCompletion(1970, 1, 2); $this->assertEquals(1, count($r->getCompletions())); $this->assertFalse($r->hasCompletion(1970, 1, 2)); $r->addCompletion(1970, 1, 2); $r->addException(1970, 1, 1); $r->addException(1970, 1, 3); $next = $r->nextRecurrence(new Horde_Date($r->start)); $this->assertEquals(1, $next->mday); $this->assertTrue($r->hasException($next->year, $next->month, $next->mday)); $next->mday++; $next = $r->nextRecurrence($next); $this->assertTrue($r->hasCompletion($next->year, $next->month, $next->mday)); $next->mday++; $next = $r->nextRecurrence($next); $this->assertTrue($r->hasException($next->year, $next->month, $next->mday)); $next->mday++; $next = $r->nextRecurrence($next); $this->assertTrue($r->hasCompletion($next->year, $next->month, $next->mday)); $r->setRecurEnd(new Horde_Date(1970, 1, 4)); $this->assertTrue($r->hasRecurEnd()); $this->assertFalse($r->hasActiveRecurrence()); $s = new Horde_Date_Recurrence(new Horde_Date(1970, 1, 1)); $s->fromKolab($r->toKolab()); $this->assertTrue($s->hasRecurEnd()); $next = $s->nextRecurrence(new Horde_Date($s->start)); $this->assertEquals(1, $next->mday); $this->assertTrue($s->hasException($next->year, $next->month, $next->mday)); $next->mday++; $next = $s->nextRecurrence($next); $this->assertTrue($s->hasCompletion($next->year, $next->month, $next->mday)); $next->mday++; $next = $s->nextRecurrence($next); $this->assertTrue($s->hasException($next->year, $next->month, $next->mday)); $next->mday++; $next = $s->nextRecurrence($next); $this->assertTrue($s->hasCompletion($next->year, $next->month, $next->mday)); $this->assertEquals(2, count($s->getCompletions())); $this->assertEquals(2, count($s->getExceptions())); $this->assertFalse($s->hasActiveRecurrence()); $this->assertEquals(2, count($s->getCompletions())); $s->deleteCompletion(1970, 1, 2); $this->assertEquals(1, count($s->getCompletions())); $s->deleteCompletion(1970, 1, 4); $this->assertEquals(0, count($s->getCompletions())); }