mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-17 20:32:41 +01:00
Allow users to mark themselves as "Available", "Busy" or "Away" while attending an event
Summary: Ref T11816. - Now that we can do something meaningful with them, bring back the yellow dots for "busy". - Default to "busy" when attending events (we could make this "busy" for short events and "away" for long events or something). - Let users pick how to display their attending status on the event page. - Also show which event the user is attending since I had to mess with the cache code anyway. We can get rid of this again if it doesn't feel good. Test Plan: {F1904179} {F1904180} Reviewers: chad Reviewed By: chad Maniphest Tasks: T11816 Differential Revision: https://secure.phabricator.com/D16802
This commit is contained in:
parent
ac8b156e4b
commit
e337029769
12 changed files with 269 additions and 8 deletions
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_calendar.calendar_eventinvitee
|
||||||
|
ADD availability VARCHAR(64) NOT NULL;
|
|
@ -0,0 +1,3 @@
|
||||||
|
UPDATE {$NAMESPACE}_calendar.calendar_eventinvitee
|
||||||
|
SET availability = 'default'
|
||||||
|
WHERE availability = '';
|
|
@ -2035,6 +2035,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarEvent' => 'applications/calendar/storage/PhabricatorCalendarEvent.php',
|
'PhabricatorCalendarEvent' => 'applications/calendar/storage/PhabricatorCalendarEvent.php',
|
||||||
'PhabricatorCalendarEventAcceptTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventAcceptTransaction.php',
|
'PhabricatorCalendarEventAcceptTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventAcceptTransaction.php',
|
||||||
'PhabricatorCalendarEventAllDayTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventAllDayTransaction.php',
|
'PhabricatorCalendarEventAllDayTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventAllDayTransaction.php',
|
||||||
|
'PhabricatorCalendarEventAvailabilityController' => 'applications/calendar/controller/PhabricatorCalendarEventAvailabilityController.php',
|
||||||
'PhabricatorCalendarEventCancelController' => 'applications/calendar/controller/PhabricatorCalendarEventCancelController.php',
|
'PhabricatorCalendarEventCancelController' => 'applications/calendar/controller/PhabricatorCalendarEventCancelController.php',
|
||||||
'PhabricatorCalendarEventCancelTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventCancelTransaction.php',
|
'PhabricatorCalendarEventCancelTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventCancelTransaction.php',
|
||||||
'PhabricatorCalendarEventDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventDateTransaction.php',
|
'PhabricatorCalendarEventDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventDateTransaction.php',
|
||||||
|
@ -6881,6 +6882,7 @@ phutil_register_library_map(array(
|
||||||
),
|
),
|
||||||
'PhabricatorCalendarEventAcceptTransaction' => 'PhabricatorCalendarEventReplyTransaction',
|
'PhabricatorCalendarEventAcceptTransaction' => 'PhabricatorCalendarEventReplyTransaction',
|
||||||
'PhabricatorCalendarEventAllDayTransaction' => 'PhabricatorCalendarEventTransactionType',
|
'PhabricatorCalendarEventAllDayTransaction' => 'PhabricatorCalendarEventTransactionType',
|
||||||
|
'PhabricatorCalendarEventAvailabilityController' => 'PhabricatorCalendarController',
|
||||||
'PhabricatorCalendarEventCancelController' => 'PhabricatorCalendarController',
|
'PhabricatorCalendarEventCancelController' => 'PhabricatorCalendarController',
|
||||||
'PhabricatorCalendarEventCancelTransaction' => 'PhabricatorCalendarEventTransactionType',
|
'PhabricatorCalendarEventCancelTransaction' => 'PhabricatorCalendarEventTransactionType',
|
||||||
'PhabricatorCalendarEventDateTransaction' => 'PhabricatorCalendarEventTransactionType',
|
'PhabricatorCalendarEventDateTransaction' => 'PhabricatorCalendarEventTransactionType',
|
||||||
|
|
|
@ -61,6 +61,8 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication {
|
||||||
=> 'PhabricatorCalendarEventJoinController',
|
=> 'PhabricatorCalendarEventJoinController',
|
||||||
'export/(?P<id>[1-9]\d*)/(?P<filename>[^/]*)'
|
'export/(?P<id>[1-9]\d*)/(?P<filename>[^/]*)'
|
||||||
=> 'PhabricatorCalendarEventExportController',
|
=> 'PhabricatorCalendarEventExportController',
|
||||||
|
'availability/(?P<id>[1-9]\d*)/(?P<availability>[^/]+)/'
|
||||||
|
=> 'PhabricatorCalendarEventAvailabilityController',
|
||||||
),
|
),
|
||||||
'export/' => array(
|
'export/' => array(
|
||||||
$this->getQueryRoutePattern()
|
$this->getQueryRoutePattern()
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCalendarEventAvailabilityController
|
||||||
|
extends PhabricatorCalendarController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$id = $request->getURIData('id');
|
||||||
|
|
||||||
|
$event = id(new PhabricatorCalendarEventQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($id))
|
||||||
|
->executeOne();
|
||||||
|
if (!$event) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->newImportedEventResponse($event);
|
||||||
|
if ($response) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cancel_uri = $event->getURI();
|
||||||
|
|
||||||
|
if (!$event->getIsUserAttending($viewer->getPHID())) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Not Attending Event'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'You can not change your display availability for events you '.
|
||||||
|
'are not attending.'))
|
||||||
|
->addCancelButton($cancel_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This endpoint currently only works via AJAX. It would be vaguely
|
||||||
|
// nice to provide a plain HTML version of the workflow where we return
|
||||||
|
// a dialog with a vanilla <select /> in it for cases where all the JS
|
||||||
|
// breaks.
|
||||||
|
$request->validateCSRF();
|
||||||
|
|
||||||
|
$invitee = $event->getInviteeForPHID($viewer->getPHID());
|
||||||
|
|
||||||
|
$map = PhabricatorCalendarEventInvitee::getAvailabilityMap();
|
||||||
|
$new_availability = $request->getURIData('availability');
|
||||||
|
if (isset($map[$new_availability])) {
|
||||||
|
$invitee
|
||||||
|
->setAvailability($new_availability)
|
||||||
|
->save();
|
||||||
|
|
||||||
|
// Invalidate the availability cache.
|
||||||
|
$viewer->writeAvailabilityCache(array(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
|
||||||
|
}
|
||||||
|
}
|
|
@ -132,6 +132,43 @@ final class PhabricatorCalendarEventViewController
|
||||||
$header->addActionLink($action);
|
$header->addActionLink($action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$options = PhabricatorCalendarEventInvitee::getAvailabilityMap();
|
||||||
|
|
||||||
|
$is_attending = $event->getIsUserAttending($viewer->getPHID());
|
||||||
|
if ($is_attending) {
|
||||||
|
$invitee = $event->getInviteeForPHID($viewer->getPHID());
|
||||||
|
|
||||||
|
$selected = $invitee->getDisplayAvailability($event);
|
||||||
|
if (!$selected) {
|
||||||
|
$selected = PhabricatorCalendarEventInvitee::AVAILABILITY_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$selected_option = idx($options, $selected);
|
||||||
|
|
||||||
|
$availability_select = id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setIcon('fa-circle '.$selected_option['color'])
|
||||||
|
->setText(pht('Availability: %s', $selected_option['name']));
|
||||||
|
|
||||||
|
$dropdown = id(new PhabricatorActionListView())
|
||||||
|
->setUser($viewer);
|
||||||
|
|
||||||
|
foreach ($options as $key => $option) {
|
||||||
|
$uri = "event/availability/{$id}/{$key}/";
|
||||||
|
$uri = $this->getApplicationURI($uri);
|
||||||
|
|
||||||
|
$dropdown->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName($option['name'])
|
||||||
|
->setIcon('fa-circle '.$option['color'])
|
||||||
|
->setHref($uri)
|
||||||
|
->setWorkflow(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
$availability_select->setDropdownMenu($dropdown);
|
||||||
|
$header->addActionLink($availability_select);
|
||||||
|
}
|
||||||
|
|
||||||
return $header;
|
return $header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -448,6 +448,12 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
||||||
return $this->assertAttached($this->invitees);
|
return $this->assertAttached($this->invitees);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getInviteeForPHID($phid) {
|
||||||
|
$invitees = $this->getInvitees();
|
||||||
|
$invitees = mpull($invitees, null, 'getInviteePHID');
|
||||||
|
return idx($invitees, $phid);
|
||||||
|
}
|
||||||
|
|
||||||
public static function getFrequencyMap() {
|
public static function getFrequencyMap() {
|
||||||
return array(
|
return array(
|
||||||
PhutilCalendarRecurrenceRule::FREQUENCY_DAILY => array(
|
PhutilCalendarRecurrenceRule::FREQUENCY_DAILY => array(
|
||||||
|
|
|
@ -7,12 +7,18 @@ final class PhabricatorCalendarEventInvitee extends PhabricatorCalendarDAO
|
||||||
protected $inviteePHID;
|
protected $inviteePHID;
|
||||||
protected $inviterPHID;
|
protected $inviterPHID;
|
||||||
protected $status;
|
protected $status;
|
||||||
|
protected $availability = self::AVAILABILITY_DEFAULT;
|
||||||
|
|
||||||
const STATUS_INVITED = 'invited';
|
const STATUS_INVITED = 'invited';
|
||||||
const STATUS_ATTENDING = 'attending';
|
const STATUS_ATTENDING = 'attending';
|
||||||
const STATUS_DECLINED = 'declined';
|
const STATUS_DECLINED = 'declined';
|
||||||
const STATUS_UNINVITED = 'uninvited';
|
const STATUS_UNINVITED = 'uninvited';
|
||||||
|
|
||||||
|
const AVAILABILITY_DEFAULT = 'default';
|
||||||
|
const AVAILABILITY_AVAILABLE = 'available';
|
||||||
|
const AVAILABILITY_BUSY = 'busy';
|
||||||
|
const AVAILABILITY_AWAY = 'away';
|
||||||
|
|
||||||
public static function initializeNewCalendarEventInvitee(
|
public static function initializeNewCalendarEventInvitee(
|
||||||
PhabricatorUser $actor, $event) {
|
PhabricatorUser $actor, $event) {
|
||||||
return id(new PhabricatorCalendarEventInvitee())
|
return id(new PhabricatorCalendarEventInvitee())
|
||||||
|
@ -25,6 +31,7 @@ final class PhabricatorCalendarEventInvitee extends PhabricatorCalendarDAO
|
||||||
return array(
|
return array(
|
||||||
self::CONFIG_COLUMN_SCHEMA => array(
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
'status' => 'text64',
|
'status' => 'text64',
|
||||||
|
'availability' => 'text64',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
'key_event' => array(
|
'key_event' => array(
|
||||||
|
@ -50,6 +57,50 @@ final class PhabricatorCalendarEventInvitee extends PhabricatorCalendarDAO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDisplayAvailability(PhabricatorCalendarEvent $event) {
|
||||||
|
switch ($this->getAvailability()) {
|
||||||
|
case self::AVAILABILITY_DEFAULT:
|
||||||
|
case self::AVAILABILITY_BUSY:
|
||||||
|
return self::AVAILABILITY_BUSY;
|
||||||
|
case self::AVAILABILITY_AWAY:
|
||||||
|
return self::AVAILABILITY_AWAY;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAvailabilityMap() {
|
||||||
|
return array(
|
||||||
|
self::AVAILABILITY_AVAILABLE => array(
|
||||||
|
'color' => 'green',
|
||||||
|
'name' => pht('Available'),
|
||||||
|
),
|
||||||
|
self::AVAILABILITY_BUSY => array(
|
||||||
|
'color' => 'yellow',
|
||||||
|
'name' => pht('Busy'),
|
||||||
|
),
|
||||||
|
self::AVAILABILITY_AWAY => array(
|
||||||
|
'color' => 'red',
|
||||||
|
'name' => pht('Away'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAvailabilitySpec($const) {
|
||||||
|
return idx(self::getAvailabilityMap(), $const, array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAvailabilityName($const) {
|
||||||
|
$spec = self::getAvailabilitySpec($const);
|
||||||
|
return idx($spec, 'name', $const);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAvailabilityColor($const) {
|
||||||
|
$spec = self::getAvailabilitySpec($const);
|
||||||
|
return idx($spec, 'color', 'indigo');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,16 +23,57 @@ final class PHUIUserAvailabilityView
|
||||||
return pht('Available');
|
return pht('Available');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$const = $user->getDisplayAvailability();
|
||||||
|
$name = PhabricatorCalendarEventInvitee::getAvailabilityName($const);
|
||||||
|
$color = PhabricatorCalendarEventInvitee::getAvailabilityColor($const);
|
||||||
|
|
||||||
$away_tag = id(new PHUITagView())
|
$away_tag = id(new PHUITagView())
|
||||||
->setType(PHUITagView::TYPE_SHADE)
|
->setType(PHUITagView::TYPE_SHADE)
|
||||||
->setShade(PHUITagView::COLOR_RED)
|
->setShade($color)
|
||||||
->setName(pht('Away'))
|
->setName($name)
|
||||||
->setDotColor(PHUITagView::COLOR_RED);
|
->setDotColor($color);
|
||||||
|
|
||||||
$now = PhabricatorTime::getNow();
|
$now = PhabricatorTime::getNow();
|
||||||
|
|
||||||
|
// Try to load the event handle. If it's invalid or the user can't see it,
|
||||||
|
// we'll just render a generic message.
|
||||||
|
$object_phid = $user->getAvailabilityEventPHID();
|
||||||
|
$handle = null;
|
||||||
|
if ($object_phid) {
|
||||||
|
$handles = $viewer->loadHandles(array($object_phid));
|
||||||
|
$handle = $handles[$object_phid];
|
||||||
|
if (!$handle->isComplete() || $handle->getPolicyFiltered()) {
|
||||||
|
$handle = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($const) {
|
||||||
|
case PhabricatorCalendarEventInvitee::AVAILABILITY_AWAY:
|
||||||
|
if ($handle) {
|
||||||
$description = pht(
|
$description = pht(
|
||||||
'Away until %s',
|
'Away at %s until %s.',
|
||||||
|
$handle->renderLink(),
|
||||||
$viewer->formatShortDateTime($until, $now));
|
$viewer->formatShortDateTime($until, $now));
|
||||||
|
} else {
|
||||||
|
$description = pht(
|
||||||
|
'Away until %s.',
|
||||||
|
$viewer->formatShortDateTime($until, $now));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PhabricatorCalendarEventInvitee::AVAILABILITY_BUSY:
|
||||||
|
default:
|
||||||
|
if ($handle) {
|
||||||
|
$description = pht(
|
||||||
|
'Busy at %s until %s.',
|
||||||
|
$handle->renderLink(),
|
||||||
|
$viewer->formatShortDateTime($until, $now));
|
||||||
|
} else {
|
||||||
|
$description = pht(
|
||||||
|
'Busy until %s.',
|
||||||
|
$viewer->formatShortDateTime($until, $now));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
$away_tag,
|
$away_tag,
|
||||||
|
|
|
@ -66,7 +66,12 @@ final class PhabricatorPeopleUserPHIDType extends PhabricatorPHIDType {
|
||||||
} else {
|
} else {
|
||||||
$until = $user->getAwayUntil();
|
$until = $user->getAwayUntil();
|
||||||
if ($until) {
|
if ($until) {
|
||||||
|
$away = PhabricatorCalendarEventInvitee::AVAILABILITY_AWAY;
|
||||||
|
if ($user->getDisplayAvailability() == $away) {
|
||||||
$availability = PhabricatorObjectHandle::AVAILABILITY_NONE;
|
$availability = PhabricatorObjectHandle::AVAILABILITY_NONE;
|
||||||
|
} else {
|
||||||
|
$availability = PhabricatorObjectHandle::AVAILABILITY_PARTIAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -395,18 +395,28 @@ final class PhabricatorPeopleQuery
|
||||||
// Group all the events by invited user. Only examine events that users
|
// Group all the events by invited user. Only examine events that users
|
||||||
// are actually attending.
|
// are actually attending.
|
||||||
$map = array();
|
$map = array();
|
||||||
|
$invitee_map = array();
|
||||||
foreach ($events as $event) {
|
foreach ($events as $event) {
|
||||||
foreach ($event->getInvitees() as $invitee) {
|
foreach ($event->getInvitees() as $invitee) {
|
||||||
if (!$invitee->isAttending()) {
|
if (!$invitee->isAttending()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the user is set to "Available" for this event, don't consider it
|
||||||
|
// when computin their away status.
|
||||||
|
if (!$invitee->getDisplayAvailability($event)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$invitee_phid = $invitee->getInviteePHID();
|
$invitee_phid = $invitee->getInviteePHID();
|
||||||
if (!isset($rebuild[$invitee_phid])) {
|
if (!isset($rebuild[$invitee_phid])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$map[$invitee_phid][] = $event;
|
$map[$invitee_phid][] = $event;
|
||||||
|
|
||||||
|
$event_phid = $event->getPHID();
|
||||||
|
$invitee_map[$invitee_phid][$event_phid] = $invitee;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,6 +436,7 @@ final class PhabricatorPeopleQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
$cursor = $min_range;
|
$cursor = $min_range;
|
||||||
|
$next_event = null;
|
||||||
if ($events) {
|
if ($events) {
|
||||||
// Find the next time when the user has no meetings. If we move forward
|
// Find the next time when the user has no meetings. If we move forward
|
||||||
// because of an event, we check again for events after that one ends.
|
// because of an event, we check again for events after that one ends.
|
||||||
|
@ -435,6 +446,9 @@ final class PhabricatorPeopleQuery
|
||||||
$to = $event->getEndDateTimeEpoch();
|
$to = $event->getEndDateTimeEpoch();
|
||||||
if (($from <= $cursor) && ($to > $cursor)) {
|
if (($from <= $cursor) && ($to > $cursor)) {
|
||||||
$cursor = $to;
|
$cursor = $to;
|
||||||
|
if (!$next_event) {
|
||||||
|
$next_event = $event;
|
||||||
|
}
|
||||||
continue 2;
|
continue 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,13 +457,29 @@ final class PhabricatorPeopleQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cursor > $min_range) {
|
if ($cursor > $min_range) {
|
||||||
|
$invitee = $invitee_map[$phid][$next_event->getPHID()];
|
||||||
|
$availability_type = $invitee->getDisplayAvailability($next_event);
|
||||||
$availability = array(
|
$availability = array(
|
||||||
'until' => $cursor,
|
'until' => $cursor,
|
||||||
|
'eventPHID' => $event->getPHID(),
|
||||||
|
'availability' => $availability_type,
|
||||||
);
|
);
|
||||||
$availability_ttl = $cursor;
|
|
||||||
|
// We only cache this availability until the end of the current event,
|
||||||
|
// since the event PHID (and possibly the availability type) are only
|
||||||
|
// valid for that long.
|
||||||
|
|
||||||
|
// NOTE: This doesn't handle overlapping events with the greatest
|
||||||
|
// possible care. In theory, if you're attenting multiple events
|
||||||
|
// simultaneously we should accommodate that. However, it's complex
|
||||||
|
// to compute, rare, and probably not confusing most of the time.
|
||||||
|
|
||||||
|
$availability_ttl = $next_event->getStartDateTimeEpochForCache();
|
||||||
} else {
|
} else {
|
||||||
$availability = array(
|
$availability = array(
|
||||||
'until' => null,
|
'until' => null,
|
||||||
|
'eventPHID' => null,
|
||||||
|
'availability' => null,
|
||||||
);
|
);
|
||||||
$availability_ttl = $max_range;
|
$availability_ttl = $max_range;
|
||||||
}
|
}
|
||||||
|
|
|
@ -960,6 +960,32 @@ final class PhabricatorUser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getDisplayAvailability() {
|
||||||
|
$availability = $this->availability;
|
||||||
|
|
||||||
|
$this->assertAttached($availability);
|
||||||
|
if (!$availability) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$busy = PhabricatorCalendarEventInvitee::AVAILABILITY_BUSY;
|
||||||
|
|
||||||
|
return idx($availability, 'availability', $busy);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getAvailabilityEventPHID() {
|
||||||
|
$availability = $this->availability;
|
||||||
|
|
||||||
|
$this->assertAttached($availability);
|
||||||
|
if (!$availability) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx($availability, 'eventPHID');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get cached availability, if present.
|
* Get cached availability, if present.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue