Page MenuHomePhorge

D25363.1733322822.diff
No OneTemporary

D25363.1733322822.diff

diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
--- a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
@@ -166,6 +166,7 @@
}
$availability_select->setDropdownMenu($dropdown);
+ $availability_select->setDisabled($event->isImportedEvent());
$header->addActionLink($availability_select);
}
@@ -629,6 +630,7 @@
->setIcon('fa-times grey')
->setHref($this->getApplicationURI("/event/decline/{$id}/"))
->setWorkflow(true)
+ ->setDisabled($event->isImportedEvent())
->setText(pht('Decline'));
$accept_button = id(new PHUIButtonView())
@@ -636,6 +638,7 @@
->setIcon('fa-check green')
->setHref($this->getApplicationURI("/event/accept/{$id}/"))
->setWorkflow(true)
+ ->setDisabled($event->isImportedEvent())
->setText(pht('Accept'));
return array($decline_button, $accept_button);
diff --git a/src/applications/calendar/import/PhabricatorCalendarImportEngine.php b/src/applications/calendar/import/PhabricatorCalendarImportEngine.php
--- a/src/applications/calendar/import/PhabricatorCalendarImportEngine.php
+++ b/src/applications/calendar/import/PhabricatorCalendarImportEngine.php
@@ -207,10 +207,24 @@
$events = null;
}
+ // Verified emails of the Event Uploader, to be eventually matched.
+ // Phorge loves privacy, so emails are generally private.
+ // This just covers a corner case: yourself importing yourself.
+ // NOTE: We are using the omnipotent user since we already have
+ // withUserPHIDs() limiting to a specific person (you).
+ $author_verified_emails = id(new PhabricatorPeopleUserEmailQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withUserPHIDs(array($import->getAuthorPHID()))
+ ->withIsVerified(true)
+ ->execute();
+ $author_verified_emails = mpull($author_verified_emails, 'getAddress');
+ $author_verified_emails = array_fuse($author_verified_emails);
+
$xactions = array();
$update_map = array();
$invitee_map = array();
- $attendee_map = array();
+ $attendee_name_map = array(); // map[eventUID][email from] = Attendee
+ $attendee_user_map = array(); // map[eventUID][userPHID ] = Attendee
foreach ($node_map as $full_uid => $node) {
$event = idx($events, $full_uid);
if (!$event) {
@@ -227,7 +241,8 @@
$xactions[$full_uid] = $this->newUpdateTransactions($event, $node);
$update_map[$full_uid] = $event;
- $attendee_map[$full_uid] = array();
+ $attendee_name_map[$full_uid] = array();
+ $attendee_user_map[$full_uid] = array();
$attendees = $node->getAttendees();
$private_index = 1;
foreach ($attendees as $attendee) {
@@ -236,8 +251,16 @@
// of the product.
$name = $attendee->getName();
if (phutil_nonempty_string($name) && preg_match('/@/', $name)) {
- $name = new PhutilEmailAddress($name);
- $name = $name->getDisplayName();
+ $attendee_mail = new PhutilEmailAddress($name);
+ $name = $attendee_mail->getDisplayName();
+ $address = $attendee_mail->getAddress();
+
+ // Skip creation of dummy "Private User" if it's me, the uploader.
+ if ($address && isset($author_verified_emails[$address])) {
+ $attendee_user_map[$full_uid][$import->getAuthorPHID()] =
+ $attendee;
+ continue;
+ }
}
// If we don't have a name or the name still looks like it's an
@@ -247,12 +270,12 @@
$private_index++;
}
- $attendee_map[$full_uid][$name] = $attendee;
+ $attendee_name_map[$full_uid][$name] = $attendee;
}
}
$attendee_names = array();
- foreach ($attendee_map as $full_uid => $event_attendees) {
+ foreach ($attendee_name_map as $full_uid => $event_attendees) {
foreach ($event_attendees as $name => $attendee) {
$attendee_names[$name] = $attendee;
}
@@ -331,7 +354,8 @@
$update_map = array_select_keys($update_map, $insert_order);
foreach ($update_map as $full_uid => $event) {
- $parent_uid = $this->getParentNodeUID($node_map[$full_uid]);
+ $node = $node_map[$full_uid];
+ $parent_uid = $this->getParentNodeUID($node);
if ($parent_uid) {
$parent_phid = $update_map[$parent_uid]->getPHID();
} else {
@@ -356,19 +380,28 @@
// We're just forcing attendees to the correct values here because
// transactions intentionally don't let you RSVP for other users. This
// might need to be turned into a special type of transaction eventually.
- $attendees = $attendee_map[$full_uid];
+ $attendees_name = $attendee_name_map[$full_uid];
+ $attendees_user = $attendee_user_map[$full_uid];
$old_map = $event->getInvitees();
$old_map = mpull($old_map, null, 'getInviteePHID');
+ $phid_invitees = array();
+ foreach ($attendees_name as $name => $attendee) {
+ $attendee_phid = $external_invitees[$name]->getPHID();
+ $phid_invitees[$attendee_phid] = $attendee;
+ }
+ foreach ($attendees_user as $phid_user_attendee => $attendee) {
+ $phid_invitees[$phid_user_attendee] = $attendee;
+ }
+
$new_map = array();
- foreach ($attendees as $name => $attendee) {
- $phid = $external_invitees[$name]->getPHID();
+ foreach ($phid_invitees as $phid_invitee => $attendee) {
- $invitee = idx($old_map, $phid);
+ $invitee = idx($old_map, $phid_invitee);
if (!$invitee) {
$invitee = id(new PhabricatorCalendarEventInvitee())
->setEventPHID($event->getPHID())
- ->setInviteePHID($phid)
+ ->setInviteePHID($phid_invitee)
->setInviterPHID($import->getPHID());
}
@@ -381,15 +414,26 @@
break;
case PhutilCalendarUserNode::STATUS_INVITED:
default:
- $status = PhabricatorCalendarEventInvitee::STATUS_INVITED;
+ // Is me importing myself? I'm coming!
+ if ($phid_invitee === $import->getAuthorPHID()) {
+ $status = PhabricatorCalendarEventInvitee::STATUS_ATTENDING;
+ } else {
+ $status = PhabricatorCalendarEventInvitee::STATUS_INVITED;
+ }
break;
}
$invitee->setStatus($status);
+ // Import "busy/available", very useful for myself to tell this
+ // to coworkers. This is probably somehow very un-useful for most
+ // "Private user(s)", but let's add it for them too since it
+ // doesn't hurt them.
+ $invitee->importAvailabilityFromTimeTransparency(
+ $node->getTimeTransparency());
$invitee->save();
- $new_map[$phid] = $invitee;
+ $new_map[$phid_invitee] = $invitee;
}
-
+ // Remove old Invitees if they are not invited anymore.
foreach ($old_map as $phid => $invitee) {
if (empty($new_map[$phid])) {
$invitee->delete();
diff --git a/src/applications/calendar/import/__tests__/CalendarImportTestCase.php b/src/applications/calendar/import/__tests__/CalendarImportTestCase.php
--- a/src/applications/calendar/import/__tests__/CalendarImportTestCase.php
+++ b/src/applications/calendar/import/__tests__/CalendarImportTestCase.php
@@ -56,7 +56,7 @@
'fileAuthor' => $lincoln_verified,
'expectedInvitees' => 3,
'expectedInviteesTests' => array(
-// array($lincoln_verified, true), // Self-invitation. T15564
+ array($lincoln_verified, true), // Self-invitation. T15564
array($alice_unverified, false),
array($alien_unverified, false),
array($alien_verified, false),
diff --git a/src/applications/calendar/parser/data/PhutilCalendarEventNode.php b/src/applications/calendar/parser/data/PhutilCalendarEventNode.php
--- a/src/applications/calendar/parser/data/PhutilCalendarEventNode.php
+++ b/src/applications/calendar/parser/data/PhutilCalendarEventNode.php
@@ -15,6 +15,7 @@
private $modifiedDateTime;
private $organizer;
private $attendees = array();
+ private $timeTransparency;
private $recurrenceRule;
private $recurrenceExceptions = array();
private $recurrenceDates = array();
@@ -130,6 +131,24 @@
return $this;
}
+ /**
+ * Get the "time transparency" as described by RFC 5545 3.8.2.7.
+ * @return string|null
+ */
+ public function getTimeTransparency() {
+ return $this->timeTransparency;
+ }
+
+ /**
+ * Set the "time transparency" as described by RFC 5545 3.8.2.7.
+ * @param string|null $time_transparency
+ * @return self
+ */
+ public function setTimeTransparency($time_transparency) {
+ $this->timeTransparency = $time_transparency;
+ return $this;
+ }
+
public function setRecurrenceRule(
PhutilCalendarRecurrenceRule $recurrence_rule) {
$this->recurrenceRule = $recurrence_rule;
diff --git a/src/applications/calendar/parser/ics/PhutilICSParser.php b/src/applications/calendar/parser/ics/PhutilICSParser.php
--- a/src/applications/calendar/parser/ics/PhutilICSParser.php
+++ b/src/applications/calendar/parser/ics/PhutilICSParser.php
@@ -673,6 +673,10 @@
$attendee = $this->newAttendeeFromProperty($parameters, $value);
$node->addAttendee($attendee);
break;
+ case 'TRANSP':
+ $transp = $this->newTextFromProperty($parameters, $value);
+ $node->setTimeTransparency($transp);
+ break;
}
}
diff --git a/src/applications/calendar/parser/ics/PhutilICSWriter.php b/src/applications/calendar/parser/ics/PhutilICSWriter.php
--- a/src/applications/calendar/parser/ics/PhutilICSWriter.php
+++ b/src/applications/calendar/parser/ics/PhutilICSWriter.php
@@ -213,6 +213,17 @@
}
}
+ // In the future you may want to add export support
+ // to the "Time Trasparency" field. In case, please tell us why.
+ // No one needs it at the moment. This is not even persisted
+ // in the event object, so, this cannot be exported.
+// $transp = $event->getTimeTransparency();
+// if ($transp) {
+// $properties[] = $this->newTextProperty(
+// 'TRANSP',
+// $transp);
+// }
+
$rrule = $event->getRecurrenceRule();
if ($rrule) {
$properties[] = $this->newRRULEProperty(
diff --git a/src/applications/calendar/parser/ics/__tests__/PhutilICSParserTestCase.php b/src/applications/calendar/parser/ics/__tests__/PhutilICSParserTestCase.php
--- a/src/applications/calendar/parser/ics/__tests__/PhutilICSParserTestCase.php
+++ b/src/applications/calendar/parser/ics/__tests__/PhutilICSParserTestCase.php
@@ -93,6 +93,17 @@
'raw' => 'This is a simple event.',
),
),
+ array(
+ 'name' => 'TRANSP',
+ 'parameters' => array(),
+ 'value' => array(
+ 'type' => 'TEXT',
+ 'value' => array(
+ 'OPAQUE',
+ ),
+ 'raw' => 'OPAQUE',
+ ),
+ ),
),
$event->getAttribute('ics.properties'));
diff --git a/src/applications/calendar/parser/ics/__tests__/data/simple.ics b/src/applications/calendar/parser/ics/__tests__/data/simple.ics
--- a/src/applications/calendar/parser/ics/__tests__/data/simple.ics
+++ b/src/applications/calendar/parser/ics/__tests__/data/simple.ics
@@ -8,5 +8,6 @@
DTEND;TZID=America/Los_Angeles:20160915T100000
SUMMARY:Simple Event
DESCRIPTION:This is a simple event.
+TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
diff --git a/src/applications/calendar/storage/PhabricatorCalendarEventInvitee.php b/src/applications/calendar/storage/PhabricatorCalendarEventInvitee.php
--- a/src/applications/calendar/storage/PhabricatorCalendarEventInvitee.php
+++ b/src/applications/calendar/storage/PhabricatorCalendarEventInvitee.php
@@ -69,6 +69,33 @@
}
}
+ /**
+ * Import the invitee availability from the Time Transparency
+ * field in an ICS calendar event as per RFC 5545 section 3.8.2.7.
+ * @param wild $time_transp Time transparency like 'OPAQUE'
+ * or 'TRANSPARENT' or null.
+ * @return void
+ */
+ public function importAvailabilityFromTimeTransparency($time_transp) {
+ // How to understand RFC 5545 suburbs. Example conversation:
+ // "Hey dude
+ // I'm a bit *opaque* on this event so I'm not *transparent*"
+ // Means:
+ // "Good morning Sir,
+ // I'm a bit *busy* on this business so I'm not *available*"
+ static $transparency_2_availability = array(
+ 'OPAQUE' => self::AVAILABILITY_BUSY,
+ 'TRANSPARENT' => self::AVAILABILITY_AVAILABLE,
+ );
+
+ // Note that idx($array, $key) likes a null $key.
+ $availability = idx($transparency_2_availability, $time_transp);
+ if ($availability) {
+ $this->setAvailability($availability);
+ }
+ }
+
+
public static function getAvailabilityMap() {
return array(
self::AVAILABILITY_AVAILABLE => array(
diff --git a/src/applications/people/query/PhabricatorPeopleUserEmailQuery.php b/src/applications/people/query/PhabricatorPeopleUserEmailQuery.php
--- a/src/applications/people/query/PhabricatorPeopleUserEmailQuery.php
+++ b/src/applications/people/query/PhabricatorPeopleUserEmailQuery.php
@@ -5,6 +5,8 @@
private $ids;
private $phids;
+ private $userPhids;
+ private $isVerified;
public function withIDs(array $ids) {
$this->ids = $ids;
@@ -16,6 +18,24 @@
return $this;
}
+ /**
+ * With the specified User PHIDs.
+ * @param null|array $phids User PHIDs
+ */
+ public function withUserPHIDs(array $phids) {
+ $this->userPhids = $phids;
+ return $this;
+ }
+
+ /**
+ * With a verified email or not.
+ * @param bool|null $isVerified
+ */
+ public function withIsVerified($verified) {
+ $this->isVerified = $verified;
+ return $this;
+ }
+
public function newResultObject() {
return new PhabricatorUserEmail();
}
@@ -41,6 +61,20 @@
$this->phids);
}
+ if ($this->userPhids !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'email.userPHID IN (%Ls)',
+ $this->userPhids);
+ }
+
+ if ($this->isVerified !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'email.isVerified = %d',
+ (int)$this->isVerified);
+ }
+
return $where;
}

File Metadata

Mime Type
text/plain
Expires
Wed, Dec 4, 14:33 (6 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1003623
Default Alt Text
D25363.1733322822.diff (14 KB)

Event Timeline