Page MenuHomePhabricator

D13039.id31486.diff
No OneTemporary

D13039.id31486.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -7,7 +7,7 @@
*/
return array(
'names' => array(
- 'core.pkg.css' => '97a49e3e',
+ 'core.pkg.css' => 'f02a5857',
'core.pkg.js' => '0e261ea7',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '30602b8c',
@@ -135,7 +135,7 @@
'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 @@
'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 @@
'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 @@
'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',
diff --git a/resources/sql/autopatches/20150527.calendar.recurringevents.sql b/resources/sql/autopatches/20150527.calendar.recurringevents.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20150527.calendar.recurringevents.sql
@@ -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 = '';
diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
--- a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
@@ -21,9 +21,11 @@
$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 @@
$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 @@
$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 @@
$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');
@@ -154,6 +159,16 @@
$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)
->setNewValue($is_all_day);
@@ -233,18 +248,44 @@
}
}
- 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 @@
->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)
diff --git a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php
--- a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php
+++ b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php
@@ -23,6 +23,12 @@
$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 @@
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 @@
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,8 +114,18 @@
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());
+ $object->setName($xaction->getNewValue($xaction->getNewValue()));
return;
case PhabricatorCalendarEventTransaction::TYPE_START_DATE:
$object->setDateFrom($xaction->getNewValue());
@@ -126,6 +157,11 @@
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 @@
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:
diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
--- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php
+++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
@@ -20,6 +20,13 @@
protected $icon;
protected $mailKey;
+ protected $isRecurring = 0;
+ protected $recurrenceFrequency = array();
+ protected $recurrenceEndDate;
+
+ protected $instanceOfEventPHID;
+ protected $sequenceIndex;
+
protected $viewPolicy;
protected $editPolicy;
@@ -36,8 +43,13 @@
->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 +58,7 @@
->setUserPHID($actor->getPHID())
->setIsCancelled(0)
->setIsAllDay(0)
+ ->setIsRecurring($is_recurring)
->setIcon(self::DEFAULT_ICON)
->setViewPolicy($view_policy)
->setEditPolicy($actor->getPHID())
@@ -180,12 +193,19 @@
'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();
}
diff --git a/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php b/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php
--- a/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php
+++ b/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php
@@ -12,6 +12,13 @@
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 @@
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 @@
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 @@
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 @@
}
}
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 @@
}
}
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();
diff --git a/webroot/rsrc/css/phui/phui-form.css b/webroot/rsrc/css/phui/phui-form.css
--- a/webroot/rsrc/css/phui/phui-form.css
+++ b/webroot/rsrc/css/phui/phui-form.css
@@ -140,7 +140,7 @@
color: {$lightgreytext};
}
-select[disabled="disabled"],
-input[disabled="disabled"] {
+select[disabled],
+input[disabled] {
opacity: 0.5;
}
diff --git a/webroot/rsrc/js/application/calendar/behavior-recurring-edit.js b/webroot/rsrc/js/application/calendar/behavior-recurring-edit.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/application/calendar/behavior-recurring-edit.js
@@ -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;
+ });
+
+});

File Metadata

Mime Type
text/plain
Expires
Sun, Apr 13, 8:16 AM (1 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7706013
Default Alt Text
D13039.id31486.diff (17 KB)

Event Timeline