Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15300839
D16557.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
D16557.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -143,6 +143,7 @@
'PhutilCalendarRawNode' => 'parser/calendar/data/PhutilCalendarRawNode.php',
'PhutilCalendarRelativeDateTime' => 'parser/calendar/data/PhutilCalendarRelativeDateTime.php',
'PhutilCalendarRootNode' => 'parser/calendar/data/PhutilCalendarRootNode.php',
+ 'PhutilCalendarUserNode' => 'parser/calendar/data/PhutilCalendarUserNode.php',
'PhutilCallbackFilterIterator' => 'utils/PhutilCallbackFilterIterator.php',
'PhutilCallbackSignalHandler' => 'future/exec/PhutilCallbackSignalHandler.php',
'PhutilChannel' => 'channel/PhutilChannel.php',
@@ -726,6 +727,7 @@
'PhutilCalendarRawNode' => 'PhutilCalendarContainerNode',
'PhutilCalendarRelativeDateTime' => 'PhutilCalendarProxyDateTime',
'PhutilCalendarRootNode' => 'PhutilCalendarContainerNode',
+ 'PhutilCalendarUserNode' => 'PhutilCalendarNode',
'PhutilCallbackFilterIterator' => 'FilterIterator',
'PhutilCallbackSignalHandler' => 'PhutilSignalHandler',
'PhutilChannel' => 'Phobject',
diff --git a/src/parser/calendar/data/PhutilCalendarEventNode.php b/src/parser/calendar/data/PhutilCalendarEventNode.php
--- a/src/parser/calendar/data/PhutilCalendarEventNode.php
+++ b/src/parser/calendar/data/PhutilCalendarEventNode.php
@@ -13,6 +13,8 @@
private $duration;
private $createdDateTime;
private $modifiedDateTime;
+ private $organizer;
+ private $attendees = array();
public function setUID($uid) {
$this->uid = $uid;
@@ -99,4 +101,28 @@
return $this->modifiedDateTime;
}
+ public function setOrganizer(PhutilCalendarUserNode $organizer) {
+ $this->organizer = $organizer;
+ return $this;
+ }
+
+ public function getOrganizer() {
+ return $this->organizer;
+ }
+
+ public function setAttendees(array $attendees) {
+ assert_instances_of($attendees, 'PhutilCalendarUserNode');
+ $this->attendees = $attendees;
+ return $this;
+ }
+
+ public function getAttendees() {
+ return $this->attendees;
+ }
+
+ public function addAttendee(PhutilCalendarUserNode $attendee) {
+ $this->attendees[] = $attendee;
+ return $this;
+ }
+
}
diff --git a/src/parser/calendar/data/PhutilCalendarUserNode.php b/src/parser/calendar/data/PhutilCalendarUserNode.php
new file mode 100644
--- /dev/null
+++ b/src/parser/calendar/data/PhutilCalendarUserNode.php
@@ -0,0 +1,40 @@
+<?php
+
+final class PhutilCalendarUserNode extends PhutilCalendarNode {
+
+ private $name;
+ private $uri;
+ private $status;
+
+ const STATUS_INVITED = 'invited';
+ const STATUS_ACCEPTED = 'accepted';
+ const STATUS_DECLINED = 'declined';
+
+ public function setName($name) {
+ $this->name = $name;
+ return $this;
+ }
+
+ public function getName() {
+ return $this->name;
+ }
+
+ public function setURI($uri) {
+ $this->uri = $uri;
+ return $this;
+ }
+
+ public function getURI() {
+ return $this->uri;
+ }
+
+ public function setStatus($status) {
+ $this->status = $status;
+ return $this;
+ }
+
+ public function getStatus() {
+ return $this->status;
+ }
+
+}
diff --git a/src/parser/calendar/ics/PhutilICSWriter.php b/src/parser/calendar/ics/PhutilICSWriter.php
--- a/src/parser/calendar/ics/PhutilICSWriter.php
+++ b/src/parser/calendar/ics/PhutilICSWriter.php
@@ -193,6 +193,22 @@
$description);
}
+ $organizer = $event->getOrganizer();
+ if ($organizer) {
+ $properties[] = $this->newUserProperty(
+ 'ORGANIZER',
+ $organizer);
+ }
+
+ $attendees = $event->getAttendees();
+ if ($attendees) {
+ foreach ($attendees as $attendee) {
+ $properties[] = $this->newUserProperty(
+ 'ATTENDEE',
+ $attendee);
+ }
+ }
+
return $properties;
}
@@ -236,6 +252,46 @@
return $this->newProperty($name, $datetime, $parameters);
}
+ private function newUserProperty(
+ $name,
+ PhutilCalendarUserNode $value,
+ array $parameters = array()) {
+
+ $parameters[] = array(
+ 'name' => 'CN',
+ 'values' => array(
+ $value->getName(),
+ ),
+ );
+
+ $partstat = null;
+ switch ($value->getStatus()) {
+ case PhutilCalendarUserNode::STATUS_INVITED:
+ $partstat = 'NEEDS-ACTION';
+ break;
+ case PhutilCalendarUserNode::STATUS_ACCEPTED:
+ $partstat = 'ACCEPTED';
+ break;
+ case PhutilCalendarUserNode::STATUS_DECLINED:
+ $partstat = 'DECLINED';
+ break;
+ }
+
+ if ($partstat !== null) {
+ $parameters[] = array(
+ 'name' => 'PARTSTAT',
+ 'values' => array(
+ $partstat,
+ ),
+ );
+ }
+
+ // TODO: We could reasonably fill in "ROLE" and "RSVP" here too, but it
+ // isn't clear if these are important to external programs or not.
+
+ return $this->newProperty($name, $value->getURI(), $parameters);
+ }
+
private function newProperty(
$name,
$value,
@@ -257,7 +313,7 @@
// RFC5545 says that we MUST quote it if it has a colon, a semicolon,
// or a comma, and that we MUST quote it if it's a URI.
- if (!preg_match('/^[A-Za-z0-9]*\z/', $v)) {
+ if (!preg_match('/^[A-Za-z0-9-]*\z/', $v)) {
$v = '"'.$v.'"';
}
diff --git a/src/parser/calendar/ics/__tests__/PhutilICSWriterTestCase.php b/src/parser/calendar/ics/__tests__/PhutilICSWriterTestCase.php
--- a/src/parser/calendar/ics/__tests__/PhutilICSWriterTestCase.php
+++ b/src/parser/calendar/ics/__tests__/PhutilICSWriterTestCase.php
@@ -56,6 +56,37 @@
$this->assertICS('writer-christmas.ics', $ics_data);
}
+ public function testICSWriterUsers() {
+ $event = id(new PhutilCalendarEventNode())
+ ->setUID('office-party')
+ ->setName('Office Party')
+ ->setCreatedDateTime(
+ PhutilCalendarAbsoluteDateTime::newFromISO8601('20161001T120000Z'))
+ ->setModifiedDateTime(
+ PhutilCalendarAbsoluteDateTime::newFromISO8601('20161001T120000Z'))
+ ->setStartDateTime(
+ PhutilCalendarAbsoluteDateTime::newFromISO8601('20161215T200000Z'))
+ ->setEndDateTime(
+ PhutilCalendarAbsoluteDateTime::newFromISO8601('20161215T230000Z'))
+ ->setOrganizer(
+ id(new PhutilCalendarUserNode())
+ ->setName('Big Boss')
+ ->setURI('mailto:big.boss@example.com'))
+ ->addAttendee(
+ id(new PhutilCalendarUserNode())
+ ->setName('Milton')
+ ->setStatus(PhutilCalendarUserNode::STATUS_INVITED)
+ ->setURI('mailto:milton@example.com'))
+ ->addAttendee(
+ id(new PhutilCalendarUserNode())
+ ->setName('Nancy')
+ ->setStatus(PhutilCalendarUserNode::STATUS_ACCEPTED)
+ ->setURI('mailto:nancy@example.com'));
+
+ $ics_data = $this->writeICSSingleEvent($event);
+ $this->assertICS('writer-office-party.ics', $ics_data);
+ }
+
private function writeICSSingleEvent(PhutilCalendarEventNode $event) {
$calendar = id(new PhutilCalendarDocumentNode())
->appendChild($event);
diff --git a/src/parser/calendar/ics/__tests__/data/writer-office-party.ics b/src/parser/calendar/ics/__tests__/data/writer-office-party.ics
new file mode 100644
--- /dev/null
+++ b/src/parser/calendar/ics/__tests__/data/writer-office-party.ics
@@ -0,0 +1,15 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Phacility//Phabricator//EN
+BEGIN:VEVENT
+UID:office-party
+CREATED:20161001T120000Z
+DTSTAMP:20161001T120000Z
+DTSTART:20161215T200000Z
+DTEND:20161215T230000Z
+SUMMARY:Office Party
+ORGANIZER;CN="Big Boss":mailto:big.boss@example.com
+ATTENDEE;CN=Milton;PARTSTAT=NEEDS-ACTION:mailto:milton@example.com
+ATTENDEE;CN=Nancy;PARTSTAT=ACCEPTED:mailto:nancy@example.com
+END:VEVENT
+END:VCALENDAR
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Mar 6, 5:10 PM (2 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7292949
Default Alt Text
D16557.diff (7 KB)
Attached To
Mode
D16557: Add "ORGANIZER" and "ATTENDEE" sections to ICS writer
Attached
Detach File
Event Timeline
Log In to Comment