1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-22 14:52:41 +01:00

DRAFT Add db columns for recurring events

Summary: Ref T2896, DRAFT Add db columns for recurring events

Test Plan: Open event, confirm it still works.

Reviewers: chad, #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: btrahan, Korvin, epriestley

Maniphest Tasks: T2896

Differential Revision: https://secure.phabricator.com/D13039
This commit is contained in:
lkassianik 2015-05-28 17:27:25 -07:00
parent 1aa8bc319b
commit 59f0e8f950
13 changed files with 354 additions and 30 deletions

View file

@ -7,7 +7,7 @@
*/
return array(
'names' => array(
'core.pkg.css' => '68d4f4fb',
'core.pkg.css' => 'e2460e8f',
'core.pkg.js' => '3bbe23c6',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '30602b8c',
@ -135,7 +135,7 @@ return array(
'rsrc/css/phui/phui-feed-story.css' => 'c9f3a0b5',
'rsrc/css/phui/phui-fontkit.css' => 'dd8ddf27',
'rsrc/css/phui/phui-form-view.css' => '808329f2',
'rsrc/css/phui/phui-form.css' => 'f535f938',
'rsrc/css/phui/phui-form.css' => '25876baf',
'rsrc/css/phui/phui-header-view.css' => '75aaf372',
'rsrc/css/phui/phui-icon.css' => 'bc766998',
'rsrc/css/phui/phui-image-mask.css' => '5a8b09c8',
@ -333,6 +333,7 @@ return array(
'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18',
'rsrc/js/application/calendar/behavior-day-view.js' => '5c46cff2',
'rsrc/js/application/calendar/behavior-event-all-day.js' => '38dcf3c8',
'rsrc/js/application/calendar/behavior-recurring-edit.js' => '85c73ceb',
'rsrc/js/application/config/behavior-reorder-fields.js' => 'b6993408',
'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '01774ab2',
'rsrc/js/application/conpherence/behavior-drag-and-drop-photo.js' => 'cf86d16a',
@ -629,6 +630,7 @@ return array(
'javelin-behavior-project-boards' => 'ba4fa35c',
'javelin-behavior-project-create' => '065227cc',
'javelin-behavior-quicksand-blacklist' => '7927a7d3',
'javelin-behavior-recurring-edit' => '85c73ceb',
'javelin-behavior-refresh-csrf' => '7814b593',
'javelin-behavior-releeph-preview-branch' => 'b2b4fbaf',
'javelin-behavior-releeph-request-state-change' => 'a0b57eb8',
@ -775,7 +777,7 @@ return array(
'phui-feed-story-css' => 'c9f3a0b5',
'phui-font-icon-base-css' => '3dad2ae3',
'phui-fontkit-css' => 'dd8ddf27',
'phui-form-css' => 'f535f938',
'phui-form-css' => '25876baf',
'phui-form-view-css' => '808329f2',
'phui-header-view-css' => '75aaf372',
'phui-icon-view-css' => 'bc766998',

View file

@ -0,0 +1,17 @@
ALTER TABLE {$NAMESPACE}_calendar.calendar_event
ADD isRecurring BOOL NOT NULL;
ALTER TABLE {$NAMESPACE}_calendar.calendar_event
ADD recurrenceFrequency LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL;
ALTER TABLE {$NAMESPACE}_calendar.calendar_event
ADD recurrenceEndDate INT UNSIGNED;
ALTER TABLE {$NAMESPACE}_calendar.calendar_event
ADD instanceOfEventPHID varbinary(64);
ALTER TABLE {$NAMESPACE}_calendar.calendar_event
ADD sequenceIndex INT UNSIGNED;
UPDATE {$NAMESPACE}_calendar.calendar_event
SET recurrenceFrequency = '[]' WHERE recurrenceFrequency = '';

View file

@ -40,7 +40,8 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication {
public function getRoutes() {
return array(
'/E(?P<id>[1-9]\d*)' => 'PhabricatorCalendarEventViewController',
'/E(?P<id>[1-9]\d*)(?:/(?P<sequence>\d+))?'
=> 'PhabricatorCalendarEventViewController',
'/calendar/' => array(
'(?:query/(?P<queryKey>[^/]+)/(?:(?P<year>\d+)/'.
'(?P<month>\d+)/)?(?:(?P<day>\d+)/)?)?'

View file

@ -21,9 +21,11 @@ final class PhabricatorCalendarEventEditController
$error_end_date = true;
$validation_exception = null;
$is_recurring_id = celerity_generate_unique_node_id();
$frequency_id = celerity_generate_unique_node_id();
$all_day_id = celerity_generate_unique_node_id();
$start_date_id = celerity_generate_unique_node_id();
$end_date_id = null;
$end_date_id = celerity_generate_unique_node_id();
$next_workflow = $request->getStr('next');
$uri_query = $request->getStr('query');
@ -70,7 +72,6 @@ final class PhabricatorCalendarEventEditController
$subscribers = array();
$invitees = array($user_phid);
$cancel_uri = $this->getApplicationURI();
$end_date_id = celerity_generate_unique_node_id();
} else {
$event = id(new PhabricatorCalendarEventQuery())
->setViewer($viewer)
@ -113,6 +114,8 @@ final class PhabricatorCalendarEventEditController
$name = $event->getName();
$description = $event->getDescription();
$is_all_day = $event->getIsAllDay();
$is_recurring = $event->getIsRecurring();
$frequency = idx($event->getRecurrenceFrequency(), 'rule');
$icon = $event->getIcon();
$current_policies = id(new PhabricatorPolicyQuery())
@ -134,6 +137,8 @@ final class PhabricatorCalendarEventEditController
$subscribers = $request->getArr('subscribers');
$edit_policy = $request->getStr('editPolicy');
$view_policy = $request->getStr('viewPolicy');
$is_recurring = $request->getStr('isRecurring') ? 1 : 0;
$frequency = $request->getStr('frequency');
$is_all_day = $request->getStr('isAllDay');
$icon = $request->getStr('icon');
@ -152,6 +157,16 @@ final class PhabricatorCalendarEventEditController
PhabricatorCalendarEventTransaction::TYPE_NAME)
->setNewValue($name);
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_RECURRING)
->setNewValue($is_recurring);
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_FREQUENCY)
->setNewValue(array('rule' => $frequency));
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_ALL_DAY)
@ -233,18 +248,44 @@ final class PhabricatorCalendarEventEditController
}
}
Javelin::initBehavior('event-all-day', array(
'allDayID' => $all_day_id,
'startDateID' => $start_date_id,
'endDateID' => $end_date_id,
));
$name = id(new AphrontFormTextControl())
->setLabel(pht('Name'))
->setName('name')
->setValue($name)
->setError($error_name);
Javelin::initBehavior('recurring-edit', array(
'isRecurring' => $is_recurring_id,
'frequency' => $frequency_id,
));
$is_recurring_checkbox = id(new AphrontFormCheckboxControl())
->addCheckbox(
'isRecurring',
1,
pht('Recurring Event'),
$is_recurring,
$is_recurring_id);
$recurrence_frequency_select = id(new AphrontFormSelectControl())
->setName('frequency')
->setOptions(array(
'daily' => pht('Daily'),
'weekly' => pht('Weekly'),
'monthly' => pht('Monthly'),
'yearly' => pht('Yearly'),
))
->setValue($frequency)
->setLabel(pht('Recurring Event Frequency'))
->setID($frequency_id)
->setDisabled(!$is_recurring);
Javelin::initBehavior('event-all-day', array(
'allDayID' => $all_day_id,
'startDateID' => $start_date_id,
'endDateID' => $end_date_id,
));
$all_day_checkbox = id(new AphrontFormCheckboxControl())
->addCheckbox(
'isAllDay',
@ -323,6 +364,8 @@ final class PhabricatorCalendarEventEditController
->addHiddenInput('query', $uri_query)
->setUser($viewer)
->appendChild($name)
->appendChild($is_recurring_checkbox)
->appendChild($recurrence_frequency_select)
->appendChild($all_day_checkbox)
->appendChild($start_control)
->appendChild($end_control)

View file

@ -17,6 +17,8 @@ final class PhabricatorCalendarEventViewController
$request = $this->getRequest();
$viewer = $request->getUser();
$sequence = $request->getURIData('sequence');
$event = id(new PhabricatorCalendarEventQuery())
->setViewer($viewer)
->withIDs(array($this->id))
@ -25,6 +27,12 @@ final class PhabricatorCalendarEventViewController
return new Aphront404Response();
}
if ($sequence && $event->getIsRecurring()) {
$event = $event->generateNthGhost($sequence, $viewer);
} else if ($sequence) {
return new Aphront404Response();
}
$title = 'E'.$event->getID();
$page_title = $title.' '.$event->getName();
$crumbs = $this->buildApplicationCrumbs();
@ -127,13 +135,15 @@ final class PhabricatorCalendarEventViewController
$event,
PhabricatorPolicyCapability::CAN_EDIT);
$actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Event'))
->setIcon('fa-pencil')
->setHref($this->getApplicationURI("event/edit/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
if (!$event->getIsGhostEvent()) {
$actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Event'))
->setIcon('fa-pencil')
->setHref($this->getApplicationURI("event/edit/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
}
if ($is_attending) {
$actions->addAction(
@ -205,6 +215,12 @@ final class PhabricatorCalendarEventViewController
phabricator_datetime($event->getDateTo(), $viewer));
}
if ($event->getIsRecurring()) {
$properties->addProperty(
pht('Recurs'),
idx($event->getRecurrenceFrequency(), 'rule'));
}
$properties->addProperty(
pht('Host'),
$viewer->renderHandle($event->getUserPHID()));

View file

@ -23,6 +23,12 @@ final class PhabricatorCalendarEventEditor
$types[] = PhabricatorCalendarEventTransaction::TYPE_ALL_DAY;
$types[] = PhabricatorCalendarEventTransaction::TYPE_ICON;
$types[] = PhabricatorCalendarEventTransaction::TYPE_RECURRING;
$types[] = PhabricatorCalendarEventTransaction::TYPE_FREQUENCY;
$types[] = PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE;
$types[] = PhabricatorCalendarEventTransaction::TYPE_INSTANCE_OF_EVENT;
$types[] = PhabricatorCalendarEventTransaction::TYPE_SEQUENCE_INDEX;
$types[] = PhabricatorTransactions::TYPE_COMMENT;
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
@ -34,6 +40,16 @@ final class PhabricatorCalendarEventEditor
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorCalendarEventTransaction::TYPE_RECURRING:
return $object->getIsRecurring();
case PhabricatorCalendarEventTransaction::TYPE_FREQUENCY:
return $object->getRecurrenceFrequency();
case PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE:
return $object->getRecurrenceEndDate();
case PhabricatorCalendarEventTransaction::TYPE_INSTANCE_OF_EVENT:
return $object->getInstanceOfEventPHID();
case PhabricatorCalendarEventTransaction::TYPE_SEQUENCE_INDEX:
return $object->getSequenceIndex();
case PhabricatorCalendarEventTransaction::TYPE_NAME:
return $object->getName();
case PhabricatorCalendarEventTransaction::TYPE_START_DATE:
@ -72,6 +88,11 @@ final class PhabricatorCalendarEventEditor
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorCalendarEventTransaction::TYPE_RECURRING:
case PhabricatorCalendarEventTransaction::TYPE_FREQUENCY:
case PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE:
case PhabricatorCalendarEventTransaction::TYPE_INSTANCE_OF_EVENT:
case PhabricatorCalendarEventTransaction::TYPE_SEQUENCE_INDEX:
case PhabricatorCalendarEventTransaction::TYPE_NAME:
case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION:
case PhabricatorCalendarEventTransaction::TYPE_CANCEL:
@ -93,6 +114,16 @@ final class PhabricatorCalendarEventEditor
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorCalendarEventTransaction::TYPE_RECURRING:
return $object->setIsRecurring($xaction->getNewValue());
case PhabricatorCalendarEventTransaction::TYPE_FREQUENCY:
return $object->setRecurrenceFrequency($xaction->getNewValue());
case PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE:
return $object->setRecurrenceEndDate($xaction->getNewValue());
case PhabricatorCalendarEventTransaction::TYPE_INSTANCE_OF_EVENT:
return $object->setInstanceOfEventPHID($xaction->getNewValue());
case PhabricatorCalendarEventTransaction::TYPE_SEQUENCE_INDEX:
return $object->setSequenceIndex($xaction->getNewValue());
case PhabricatorCalendarEventTransaction::TYPE_NAME:
$object->setName($xaction->getNewValue());
return;
@ -126,6 +157,11 @@ final class PhabricatorCalendarEventEditor
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorCalendarEventTransaction::TYPE_RECURRING:
case PhabricatorCalendarEventTransaction::TYPE_FREQUENCY:
case PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE:
case PhabricatorCalendarEventTransaction::TYPE_INSTANCE_OF_EVENT:
case PhabricatorCalendarEventTransaction::TYPE_SEQUENCE_INDEX:
case PhabricatorCalendarEventTransaction::TYPE_NAME:
case PhabricatorCalendarEventTransaction::TYPE_START_DATE:
case PhabricatorCalendarEventTransaction::TYPE_END_DATE:
@ -181,6 +217,11 @@ final class PhabricatorCalendarEventEditor
switch ($xaction->getTransactionType()) {
case PhabricatorCalendarEventTransaction::TYPE_ICON:
break;
case PhabricatorCalendarEventTransaction::TYPE_RECURRING:
case PhabricatorCalendarEventTransaction::TYPE_FREQUENCY:
case PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE:
case PhabricatorCalendarEventTransaction::TYPE_INSTANCE_OF_EVENT:
case PhabricatorCalendarEventTransaction::TYPE_SEQUENCE_INDEX:
case PhabricatorCalendarEventTransaction::TYPE_START_DATE:
case PhabricatorCalendarEventTransaction::TYPE_END_DATE:
case PhabricatorCalendarEventTransaction::TYPE_CANCEL:

View file

@ -11,6 +11,13 @@ final class PhabricatorCalendarEventQuery
private $creatorPHIDs;
private $isCancelled;
private $generateGhosts = false;
public function setGenerateGhosts($generate_ghosts) {
$this->generateGhosts = $generate_ghosts;
return $this;
}
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
@ -69,6 +76,7 @@ final class PhabricatorCalendarEventQuery
protected function loadPage() {
$table = new PhabricatorCalendarEvent();
$conn_r = $table->establishConnection('r');
$viewer = $this->getViewer();
$data = queryfx_all(
$conn_r,
@ -86,6 +94,63 @@ final class PhabricatorCalendarEventQuery
$event->applyViewerTimezone($this->getViewer());
}
if (!$this->generateGhosts) {
return $events;
}
foreach ($events as $event) {
$sequence_start = 0;
$instance_count = null;
if ($event->getIsRecurring()) {
$frequency = $event->getFrequencyUnit();
$modify_key = '+1 '.$frequency;
if ($this->rangeBegin && $this->rangeBegin > $event->getDateFrom()) {
$max_date = $this->rangeBegin;
$date = $event->getDateFrom();
$datetime = PhabricatorTime::getDateTimeFromEpoch($date, $viewer);
while ($date < $max_date) {
// TODO: optimize this to not loop through all off-screen events
$sequence_start++;
$datetime = PhabricatorTime::getDateTimeFromEpoch($date, $viewer);
$date = $datetime->modify($modify_key)->format('U');
}
$start = $this->rangeBegin;
} else {
$start = $event->getDateFrom();
}
$date = $start;
$start_datetime = PhabricatorTime::getDateTimeFromEpoch(
$start,
$viewer);
if ($this->rangeEnd) {
$end = $this->rangeEnd;
$instance_count = $sequence_start;
while ($date < $end) {
$instance_count++;
$datetime = PhabricatorTime::getDateTimeFromEpoch($date, $viewer);
$datetime->modify($modify_key);
$date = $datetime->format('U');
}
} else {
$instance_count = $this->getRawResultLimit();
}
$sequence_start = max(1, $sequence_start);
$max_sequence = $sequence_start + $instance_count;
for ($index = $sequence_start; $index < $max_sequence; $index++) {
$events[] = $event->generateNthGhost($index, $viewer);
}
}
}
return $events;
}
@ -122,7 +187,7 @@ final class PhabricatorCalendarEventQuery
if ($this->rangeBegin) {
$where[] = qsprintf(
$conn_r,
'event.dateTo >= %d',
'event.dateTo >= %d OR event.isRecurring = 1',
$this->rangeBegin);
}

View file

@ -50,7 +50,8 @@ final class PhabricatorCalendarEventSearchEngine
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new PhabricatorCalendarEventQuery());
$query = id(new PhabricatorCalendarEventQuery())
->setGenerateGhosts(true);
$viewer = $this->requireViewer();
$timezone = new DateTimeZone($viewer->getTimezoneIdentifier());
@ -132,7 +133,8 @@ final class PhabricatorCalendarEventSearchEngine
$query->withCreatorPHIDs($creator_phids);
}
$is_cancelled = $saved->getParameter('isCancelled');
$is_cancelled = $saved->getParameter('isCancelled', 'active');
switch ($is_cancelled) {
case 'active':
$query->withIsCancelled(false);
@ -305,14 +307,14 @@ final class PhabricatorCalendarEventSearchEngine
$viewer = $this->requireViewer();
$list = new PHUIObjectItemListView();
foreach ($events as $event) {
$href = '/E'.$event->getID();
// $href = '/E'.$event->getID();
$from = phabricator_datetime($event->getDateFrom(), $viewer);
$to = phabricator_datetime($event->getDateTo(), $viewer);
$creator_handle = $handles[$event->getUserPHID()];
$item = id(new PHUIObjectItemView())
->setHeader($event->getName())
->setHref($href)
->setHref($event->getURI())
->addByline(pht('Creator: %s', $creator_handle->renderLink()))
->addAttribute(pht('From %s to %s', $from, $to))
->addAttribute(id(new PhutilUTF8StringTruncator())
@ -371,7 +373,8 @@ final class PhabricatorCalendarEventSearchEngine
$event->setUserPHID($status->getUserPHID());
$event->setDescription(pht('%s (%s)', $name_text, $status_text));
$event->setName($status_text);
$event->setEventID($status->getID());
$event->setURI($status->getURI());
// $event->setEventID($status->getID());
$event->setViewerIsInvited($viewer_is_invited);
$month_view->addEvent($event);
}
@ -423,7 +426,7 @@ final class PhabricatorCalendarEventSearchEngine
$event->setViewerIsInvited($viewer_is_invited);
$event->setName($status->getName());
$event->setURI('/'.$status->getMonogram());
$event->setURI($status->getURI());
$day_view->addEvent($event);
}

View file

@ -20,6 +20,14 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
protected $icon;
protected $mailKey;
protected $isRecurring = 0;
protected $recurrenceFrequency = array();
protected $recurrenceEndDate;
private $isGhostEvent = false;
protected $instanceOfEventPHID;
protected $sequenceIndex;
protected $viewPolicy;
protected $editPolicy;
@ -36,8 +44,13 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
->withClasses(array('PhabricatorCalendarApplication'))
->executeOne();
$view_policy = null;
$is_recurring = 0;
if ($mode == 'public') {
$view_policy = PhabricatorPolicies::getMostOpenPolicy();
} else if ($mode == 'recurring') {
$is_recurring = true;
} else {
$view_policy = $actor->getPHID();
}
@ -46,6 +59,7 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
->setUserPHID($actor->getPHID())
->setIsCancelled(0)
->setIsAllDay(0)
->setIsRecurring($is_recurring)
->setIcon(self::DEFAULT_ICON)
->setViewPolicy($view_policy)
->setEditPolicy($actor->getPHID())
@ -180,12 +194,19 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
'isAllDay' => 'bool',
'icon' => 'text32',
'mailKey' => 'bytes20',
'isRecurring' => 'bool',
'recurrenceEndDate' => 'epoch?',
'instanceOfEventPHID' => 'phid?',
'sequenceIndex' => 'uint32?',
),
self::CONFIG_KEY_SCHEMA => array(
'userPHID_dateFrom' => array(
'columns' => array('userPHID', 'dateTo'),
),
),
self::CONFIG_SERIALIZATION => array(
'recurrenceFrequency' => self::SERIALIZATION_JSON,
),
) + parent::getConfiguration();
}
@ -238,6 +259,69 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
return true;
}
public function getIsGhostEvent() {
return $this->isGhostEvent;
}
public function setIsGhostEvent($is_ghost_event) {
$this->isGhostEvent = $is_ghost_event;
return $this;
}
public function generateNthGhost(
$sequence_index,
PhabricatorUser $actor) {
$frequency = $this->getFrequencyUnit();
$modify_key = '+'.$sequence_index.' '.$frequency;
$date = $this->dateFrom;
$date_time = PhabricatorTime::getDateTimeFromEpoch($date, $actor);
$date_time->modify($modify_key);
$date = $date_time->format('U');
$duration = $this->dateTo - $this->dateFrom;
$edit_policy = PhabricatorPolicies::POLICY_NOONE;
$ghost_event = id(clone $this)
->setIsGhostEvent(true)
->setDateFrom($date)
->setDateTo($date + $duration)
->setIsRecurring(false)
->setRecurrenceFrequency(null)
->setInstanceOfEventPHID($this->getPHID())
->setSequenceIndex($sequence_index)
->setEditPolicy($edit_policy);
return $ghost_event;
}
public function getFrequencyUnit() {
$frequency = idx($this->recurrenceFrequency, 'rule');
switch ($frequency) {
case 'daily':
return 'day';
case 'weekly':
return 'week';
case 'monthly':
return 'month';
case 'yearly':
return 'yearly';
default:
return 'day';
}
}
public function getURI() {
$uri = '/'.$this->getMonogram();
if ($this->isGhostEvent) {
$uri = $uri.'/'.$this->sequenceIndex;
}
return $uri;
}
/* -( Markup Interface )--------------------------------------------------- */
@ -307,6 +391,9 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
// The owner of a task can always view and edit it.
$user_phid = $this->getUserPHID();
if ($this->isGhostEvent) {
return false;
}
if ($user_phid) {
$viewer_phid = $viewer->getPHID();
if ($viewer_phid == $user_phid) {
@ -328,7 +415,8 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
public function describeAutomaticCapability($capability) {
return pht('The owner of an event can always view and edit it,
and invitees can always view it.');
and invitees can always view it, except if the event is an
instance of a recurring event.');
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */

View file

@ -12,6 +12,13 @@ final class PhabricatorCalendarEventTransaction
const TYPE_ICON = 'calendar.icon';
const TYPE_INVITE = 'calendar.invite';
const TYPE_RECURRING = 'calendar.recurring';
const TYPE_FREQUENCY = 'calendar.frequency';
const TYPE_RECURRENCE_END_DATE = 'calendar.recurrenceenddate';
const TYPE_INSTANCE_OF_EVENT = 'calendar.instanceofevent';
const TYPE_SEQUENCE_INDEX = 'calendar.sequenceindex';
const MAILTAG_RESCHEDULE = 'calendar-reschedule';
const MAILTAG_CONTENT = 'calendar-content';
const MAILTAG_OTHER = 'calendar-other';
@ -38,6 +45,11 @@ final class PhabricatorCalendarEventTransaction
case self::TYPE_DESCRIPTION:
case self::TYPE_CANCEL:
case self::TYPE_ALL_DAY:
case self::TYPE_RECURRING:
case self::TYPE_FREQUENCY:
case self::TYPE_RECURRENCE_END_DATE:
case self::TYPE_INSTANCE_OF_EVENT:
case self::TYPE_SEQUENCE_INDEX:
$phids[] = $this->getObjectPHID();
break;
case self::TYPE_INVITE:
@ -60,6 +72,11 @@ final class PhabricatorCalendarEventTransaction
case self::TYPE_CANCEL:
case self::TYPE_ALL_DAY:
case self::TYPE_INVITE:
case self::TYPE_RECURRING:
case self::TYPE_FREQUENCY:
case self::TYPE_RECURRENCE_END_DATE:
case self::TYPE_INSTANCE_OF_EVENT:
case self::TYPE_SEQUENCE_INDEX:
return ($old === null);
}
return parent::shouldHide();
@ -75,6 +92,11 @@ final class PhabricatorCalendarEventTransaction
case self::TYPE_DESCRIPTION:
case self::TYPE_ALL_DAY:
case self::TYPE_CANCEL:
case self::TYPE_RECURRING:
case self::TYPE_FREQUENCY:
case self::TYPE_RECURRENCE_END_DATE:
case self::TYPE_INSTANCE_OF_EVENT:
case self::TYPE_SEQUENCE_INDEX:
return 'fa-pencil';
break;
case self::TYPE_INVITE:
@ -231,6 +253,12 @@ final class PhabricatorCalendarEventTransaction
}
}
return $text;
case self::TYPE_RECURRING:
case self::TYPE_FREQUENCY:
case self::TYPE_RECURRENCE_END_DATE:
case self::TYPE_INSTANCE_OF_EVENT:
case self::TYPE_SEQUENCE_INDEX:
return pht('Recurring event has been updated');
}
return parent::getTitle();
}
@ -411,6 +439,12 @@ final class PhabricatorCalendarEventTransaction
}
}
return $text;
case self::TYPE_RECURRING:
case self::TYPE_FREQUENCY:
case self::TYPE_RECURRENCE_END_DATE:
case self::TYPE_INSTANCE_OF_EVENT:
case self::TYPE_SEQUENCE_INDEX:
return pht('Recurring event has been updated');
}
return parent::getTitleForFeed();

View file

@ -89,7 +89,7 @@ final class PHUICalendarListView extends AphrontTagView {
$content = javelin_tag(
'a',
array(
'href' => '/E'.$event->getEventID(),
'href' => $event->getURI(),
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => $tip,

View file

@ -140,7 +140,7 @@ textarea::-webkit-input-placeholder {
color: {$lightgreytext};
}
select[disabled="disabled"],
input[disabled="disabled"] {
select[disabled],
input[disabled] {
opacity: 0.5;
}

View file

@ -0,0 +1,14 @@
/**
* @provides javelin-behavior-recurring-edit
*/
JX.behavior('recurring-edit', function(config) {
var checkbox = JX.$(config.isRecurring);
JX.DOM.listen(checkbox, 'change', null, function() {
var frequency = JX.$(config.frequency);
frequency.disabled = checkbox.checked ? false : true;
});
});