Page MenuHomePhabricator

D16557.diff
No OneTemporary

D16557.diff

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

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)

Event Timeline