Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15491861
D13039.id31486.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
17 KB
Referenced Files
None
Subscribers
None
D13039.id31486.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D13039: DRAFT Add db columns for recurring events
Attached
Detach File
Event Timeline
Log In to Comment