diff --git a/src/applications/calendar/editor/PhabricatorCalendarEditEngine.php b/src/applications/calendar/editor/PhabricatorCalendarEditEngine.php index 33a8462075..4aaab4634d 100644 --- a/src/applications/calendar/editor/PhabricatorCalendarEditEngine.php +++ b/src/applications/calendar/editor/PhabricatorCalendarEditEngine.php @@ -1,78 +1,107 @@ getViewer(), $mode = null); } protected function newObjectQuery() { return new PhabricatorCalendarEventQuery(); } protected function getObjectCreateTitleText($object) { return pht('Create New Event'); } protected function getObjectEditTitleText($object) { return pht('Edit Event: %s', $object->getName()); } protected function getObjectEditShortText($object) { return $object->getMonogram(); } protected function getObjectCreateShortText() { return pht('Create Event'); } protected function getObjectName() { return pht('Event'); } protected function getObjectViewURI($object) { return $object->getURI(); } protected function getEditorURI() { return $this->getApplication()->getApplicationURI('event/editpro/'); } protected function buildCustomEditFields($object) { $fields = array( id(new PhabricatorTextEditField()) ->setKey('name') ->setLabel(pht('Name')) ->setDescription(pht('Name of the event.')) + ->setIsRequired(true) + ->setTransactionType(PhabricatorCalendarEventTransaction::TYPE_NAME) ->setConduitDescription(pht('Rename the event.')) ->setConduitTypeDescription(pht('New event name.')) - ->setTransactionType(PhabricatorCalendarEventTransaction::TYPE_NAME) - ->setIsRequired(true) ->setValue($object->getName()), + id(new PhabricatorRemarkupEditField()) + ->setKey('description') + ->setLabel(pht('Description')) + ->setDescription(pht('Description of the event.')) + ->setTransactionType( + PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION) + ->setConduitDescription(pht('Update the event description.')) + ->setConduitTypeDescription(pht('New event description.')) + ->setValue($object->getDescription()), + id(new PhabricatorBoolEditField()) + ->setKey('cancelled') + ->setOptions(pht('Active'), pht('Cancelled')) + ->setLabel(pht('Cancelled')) + ->setDescription(pht('Cancel the event.')) + ->setTransactionType( + PhabricatorCalendarEventTransaction::TYPE_CANCEL) + ->setIsConduitOnly(true) + ->setConduitDescription(pht('Cancel or restore the event.')) + ->setConduitTypeDescription(pht('True to cancel the event.')) + ->setValue($object->getIsCancelled()), + id(new PhabricatorIconSetEditField()) + ->setKey('icon') + ->setLabel(pht('Icon')) + ->setIconSet(new PhabricatorCalendarIconSet()) + ->setTransactionType(PhabricatorCalendarEventTransaction::TYPE_ICON) + ->setDescription(pht('Event icon.')) + ->setConduitDescription(pht('Change the event icon.')) + ->setConduitTypeDescription(pht('New event icon.')) + ->setValue($object->getIcon()), ); return $fields; } } diff --git a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php index e8ef5528e8..5b46a42e7c 100644 --- a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php +++ b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php @@ -1,485 +1,474 @@ requireActor(); $object->removeViewerTimezone($actor); if ($object->getIsStub()) { $this->materializeStub($object); } } private function materializeStub(PhabricatorCalendarEvent $event) { if (!$event->getIsStub()) { throw new Exception( pht('Can not materialize an event stub: this event is not a stub.')); } $actor = $this->getActor(); $event->copyFromParent($actor); $event->setIsStub(0); $invitees = $event->getParentEvent()->getInvitees(); + + $new_invitees = array(); foreach ($invitees as $invitee) { $invitee = id(new PhabricatorCalendarEventInvitee()) ->setEventPHID($event->getPHID()) ->setInviteePHID($invitee->getInviteePHID()) ->setInviterPHID($invitee->getInviterPHID()) ->setStatus($invitee->getStatus()) ->save(); + + $new_invitees[] = $invitee; } $event->save(); + $event->attachInvitees($new_invitees); } public function getTransactionTypes() { $types = parent::getTransactionTypes(); $types[] = PhabricatorCalendarEventTransaction::TYPE_NAME; $types[] = PhabricatorCalendarEventTransaction::TYPE_START_DATE; $types[] = PhabricatorCalendarEventTransaction::TYPE_END_DATE; $types[] = PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION; $types[] = PhabricatorCalendarEventTransaction::TYPE_CANCEL; $types[] = PhabricatorCalendarEventTransaction::TYPE_INVITE; $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; return $types; } protected function getCustomTransactionOldValue( 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: return $object->getDateFrom(); case PhabricatorCalendarEventTransaction::TYPE_END_DATE: return $object->getDateTo(); case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: return $object->getDescription(); case PhabricatorCalendarEventTransaction::TYPE_CANCEL: return $object->getIsCancelled(); case PhabricatorCalendarEventTransaction::TYPE_ALL_DAY: return (int)$object->getIsAllDay(); case PhabricatorCalendarEventTransaction::TYPE_ICON: return $object->getIcon(); case PhabricatorCalendarEventTransaction::TYPE_INVITE: $map = $xaction->getNewValue(); $phids = array_keys($map); $invitees = mpull($object->getInvitees(), null, 'getInviteePHID'); $old = array(); foreach ($phids as $phid) { $invitee = idx($invitees, $phid); if ($invitee) { $old[$phid] = $invitee->getStatus(); } else { $old[$phid] = PhabricatorCalendarEventInvitee::STATUS_UNINVITED; } } return $old; } return parent::getCustomTransactionOldValue($object, $xaction); } protected function getCustomTransactionNewValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorCalendarEventTransaction::TYPE_RECURRING: case PhabricatorCalendarEventTransaction::TYPE_FREQUENCY: - case PhabricatorCalendarEventTransaction::TYPE_INSTANCE_OF_EVENT: - case PhabricatorCalendarEventTransaction::TYPE_SEQUENCE_INDEX: case PhabricatorCalendarEventTransaction::TYPE_NAME: case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: case PhabricatorCalendarEventTransaction::TYPE_CANCEL: case PhabricatorCalendarEventTransaction::TYPE_INVITE: case PhabricatorCalendarEventTransaction::TYPE_ICON: return $xaction->getNewValue(); case PhabricatorCalendarEventTransaction::TYPE_ALL_DAY: return (int)$xaction->getNewValue(); case PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE: case PhabricatorCalendarEventTransaction::TYPE_START_DATE: case PhabricatorCalendarEventTransaction::TYPE_END_DATE: return $xaction->getNewValue()->getEpoch(); } return parent::getCustomTransactionNewValue($object, $xaction); } protected function applyCustomInternalTransaction( PhabricatorLiskDAO $object, 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_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()); return; case PhabricatorCalendarEventTransaction::TYPE_START_DATE: $object->setDateFrom($xaction->getNewValue()); return; case PhabricatorCalendarEventTransaction::TYPE_END_DATE: $object->setDateTo($xaction->getNewValue()); return; case PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE: $object->setRecurrenceEndDate($xaction->getNewValue()); return; case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: $object->setDescription($xaction->getNewValue()); return; case PhabricatorCalendarEventTransaction::TYPE_CANCEL: $object->setIsCancelled((int)$xaction->getNewValue()); return; case PhabricatorCalendarEventTransaction::TYPE_ALL_DAY: $object->setIsAllDay((int)$xaction->getNewValue()); return; case PhabricatorCalendarEventTransaction::TYPE_ICON: $object->setIcon($xaction->getNewValue()); return; case PhabricatorCalendarEventTransaction::TYPE_INVITE: return; } return parent::applyCustomInternalTransaction($object, $xaction); } protected function applyCustomExternalTransaction( 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_START_DATE: case PhabricatorCalendarEventTransaction::TYPE_END_DATE: case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: case PhabricatorCalendarEventTransaction::TYPE_CANCEL: case PhabricatorCalendarEventTransaction::TYPE_ALL_DAY: case PhabricatorCalendarEventTransaction::TYPE_ICON: return; case PhabricatorCalendarEventTransaction::TYPE_INVITE: $map = $xaction->getNewValue(); $phids = array_keys($map); $invitees = $object->getInvitees(); $invitees = mpull($invitees, null, 'getInviteePHID'); foreach ($phids as $phid) { $invitee = idx($invitees, $phid); if (!$invitee) { $invitee = id(new PhabricatorCalendarEventInvitee()) ->setEventPHID($object->getPHID()) ->setInviteePHID($phid) ->setInviterPHID($this->getActingAsPHID()); $invitees[] = $invitee; } $invitee->setStatus($map[$phid]) ->save(); } $object->attachInvitees($invitees); return; } return parent::applyCustomExternalTransaction($object, $xaction); } protected function applyFinalEffects( PhabricatorLiskDAO $object, array $xactions) { // Clear the availability caches for users whose availability is affected // by this edit. $invalidate_all = false; $invalidate_phids = array(); foreach ($xactions as $xaction) { 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: case PhabricatorCalendarEventTransaction::TYPE_ALL_DAY: // For these kinds of changes, we need to invalidate the availabilty // caches for all attendees. $invalidate_all = true; break; case PhabricatorCalendarEventTransaction::TYPE_INVITE: foreach ($xaction->getNewValue() as $phid => $ignored) { $invalidate_phids[$phid] = $phid; } break; } } $phids = mpull($object->getInvitees(), 'getInviteePHID'); $phids = array_fuse($phids); if (!$invalidate_all) { $phids = array_select_keys($phids, $invalidate_phids); } if ($phids) { $user = new PhabricatorUser(); $conn_w = $user->establishConnection('w'); queryfx( $conn_w, 'UPDATE %T SET availabilityCacheTTL = NULL WHERE phid IN (%Ls) AND availabilityCacheTTL >= %d', $user->getTableName(), $phids, $object->getDateFromForCache()); } return $xactions; } protected function validateAllTransactions( PhabricatorLiskDAO $object, array $xactions) { $start_date_xaction = PhabricatorCalendarEventTransaction::TYPE_START_DATE; $end_date_xaction = PhabricatorCalendarEventTransaction::TYPE_END_DATE; $is_recurrence_xaction = PhabricatorCalendarEventTransaction::TYPE_RECURRING; $recurrence_end_xaction = PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE; $start_date = $object->getDateFrom(); $end_date = $object->getDateTo(); $recurrence_end = $object->getRecurrenceEndDate(); $is_recurring = $object->getIsRecurring(); $errors = array(); foreach ($xactions as $xaction) { if ($xaction->getTransactionType() == $start_date_xaction) { $start_date = $xaction->getNewValue()->getEpoch(); } else if ($xaction->getTransactionType() == $end_date_xaction) { $end_date = $xaction->getNewValue()->getEpoch(); } else if ($xaction->getTransactionType() == $recurrence_end_xaction) { $recurrence_end = $xaction->getNewValue(); } else if ($xaction->getTransactionType() == $is_recurrence_xaction) { $is_recurring = $xaction->getNewValue(); } } if ($start_date > $end_date) { $type = PhabricatorCalendarEventTransaction::TYPE_END_DATE; $errors[] = new PhabricatorApplicationTransactionValidationError( $type, pht('Invalid'), pht('End date must be after start date.'), null); } if ($recurrence_end && !$is_recurring) { $type = PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE; $errors[] = new PhabricatorApplicationTransactionValidationError( $type, pht('Invalid'), pht('Event must be recurring to have a recurrence end date.'). null); } return $errors; } protected function validateTransaction( PhabricatorLiskDAO $object, $type, array $xactions) { $errors = parent::validateTransaction($object, $type, $xactions); switch ($type) { case PhabricatorCalendarEventTransaction::TYPE_NAME: $missing = $this->validateIsEmptyTextField( $object->getName(), $xactions); if ($missing) { $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Required'), pht('Event name is required.'), nonempty(last($xactions), null)); $error->setIsMissingFieldError(true); $errors[] = $error; } break; case PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE: case PhabricatorCalendarEventTransaction::TYPE_START_DATE: case PhabricatorCalendarEventTransaction::TYPE_END_DATE: foreach ($xactions as $xaction) { $date_value = $xaction->getNewValue(); if (!$date_value->isValid()) { $errors[] = new PhabricatorApplicationTransactionValidationError( $type, pht('Invalid'), pht('Invalid date.'), $xaction); } } break; } return $errors; } protected function shouldPublishFeedStory( PhabricatorLiskDAO $object, array $xactions) { return true; } protected function supportsSearch() { return true; } protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { return true; } protected function getMailSubjectPrefix() { return pht('[Calendar]'); } protected function getMailTo(PhabricatorLiskDAO $object) { $phids = array(); if ($object->getUserPHID()) { $phids[] = $object->getUserPHID(); } $phids[] = $this->getActingAsPHID(); $invitees = $object->getInvitees(); foreach ($invitees as $invitee) { $status = $invitee->getStatus(); if ($status === PhabricatorCalendarEventInvitee::STATUS_ATTENDING || $status === PhabricatorCalendarEventInvitee::STATUS_INVITED) { $phids[] = $invitee->getInviteePHID(); } } $phids = array_unique($phids); return $phids; } public function getMailTagsMap() { return array( PhabricatorCalendarEventTransaction::MAILTAG_CONTENT => pht( "An event's name, status, invite list, ". "icon, and description changes."), PhabricatorCalendarEventTransaction::MAILTAG_RESCHEDULE => pht( "An event's start and end date ". "and cancellation status changes."), PhabricatorCalendarEventTransaction::MAILTAG_OTHER => pht('Other event activity not listed above occurs.'), ); } protected function buildReplyHandler(PhabricatorLiskDAO $object) { return id(new PhabricatorCalendarReplyHandler()) ->setMailReceiver($object); } protected function buildMailTemplate(PhabricatorLiskDAO $object) { $id = $object->getID(); $name = $object->getName(); return id(new PhabricatorMetaMTAMail()) ->setSubject("E{$id}: {$name}") ->addHeader('Thread-Topic', "E{$id}: ".$object->getName()); } protected function buildMailBody( PhabricatorLiskDAO $object, array $xactions) { $description = $object->getDescription(); $body = parent::buildMailBody($object, $xactions); if (strlen($description)) { $body->addRemarkupSection( pht('EVENT DESCRIPTION'), $description); } $body->addLinkSection( pht('EVENT DETAIL'), PhabricatorEnv::getProductionURI('/E'.$object->getID())); return $body; } } diff --git a/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php b/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php index f9c9e79409..573428d8bc 100644 --- a/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php +++ b/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php @@ -1,572 +1,557 @@ getTransactionType()) { case self::TYPE_NAME: case self::TYPE_START_DATE: case self::TYPE_END_DATE: 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: $new = $this->getNewValue(); foreach ($new as $phid => $status) { $phids[] = $phid; } break; } return $phids; } public function shouldHide() { $old = $this->getOldValue(); switch ($this->getTransactionType()) { case self::TYPE_START_DATE: case self::TYPE_END_DATE: case self::TYPE_DESCRIPTION: 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(); } public function getIcon() { switch ($this->getTransactionType()) { case self::TYPE_ICON: return $this->getNewValue(); case self::TYPE_NAME: case self::TYPE_START_DATE: case self::TYPE_END_DATE: 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: return 'fa-user-plus'; break; } return parent::getIcon(); } public function getTitle() { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); $type = $this->getTransactionType(); switch ($type) { case self::TYPE_NAME: if ($old === null) { return pht( '%s created this event.', $this->renderHandleLink($author_phid)); } else { return pht( '%s changed the name of this event from %s to %s.', $this->renderHandleLink($author_phid), $old, $new); } case self::TYPE_START_DATE: if ($old) { return pht( '%s edited the start date of this event.', $this->renderHandleLink($author_phid)); } break; case self::TYPE_END_DATE: if ($old) { return pht( '%s edited the end date of this event.', $this->renderHandleLink($author_phid)); } break; case self::TYPE_DESCRIPTION: return pht( "%s updated the event's description.", $this->renderHandleLink($author_phid)); case self::TYPE_ALL_DAY: if ($new) { return pht( '%s made this an all day event.', $this->renderHandleLink($author_phid)); } else { return pht( '%s converted this from an all day event.', $this->renderHandleLink($author_phid)); } case self::TYPE_ICON: $set = new PhabricatorCalendarIconSet(); return pht( '%s set this event\'s icon to %s.', $this->renderHandleLink($author_phid), $set->getIconLabel($new)); break; case self::TYPE_CANCEL: if ($new) { return pht( '%s cancelled this event.', $this->renderHandleLink($author_phid)); } else { return pht( '%s reinstated this event.', $this->renderHandleLink($author_phid)); } case self::TYPE_INVITE: $text = null; if (count($old) === 1 && count($new) === 1 && isset($old[$author_phid])) { // user joined/declined/accepted event themself $old_status = $old[$author_phid]; $new_status = $new[$author_phid]; if ($old_status !== $new_status) { switch ($new_status) { case PhabricatorCalendarEventInvitee::STATUS_INVITED: $text = pht( '%s has joined this event.', $this->renderHandleLink($author_phid)); break; case PhabricatorCalendarEventInvitee::STATUS_ATTENDING: $text = pht( '%s is attending this event.', $this->renderHandleLink($author_phid)); break; case PhabricatorCalendarEventInvitee::STATUS_DECLINED: case PhabricatorCalendarEventInvitee::STATUS_UNINVITED: $text = pht( '%s has declined this event.', $this->renderHandleLink($author_phid)); break; default: $text = pht( '%s has changed their status for this event.', $this->renderHandleLink($author_phid)); break; } } } else { // user changed status for many users $self_joined = null; $self_declined = null; $added = array(); $uninvited = array(); foreach ($new as $phid => $status) { if ($status == PhabricatorCalendarEventInvitee::STATUS_INVITED || $status == PhabricatorCalendarEventInvitee::STATUS_ATTENDING) { // added users $added[] = $phid; } else if ( $status == PhabricatorCalendarEventInvitee::STATUS_DECLINED || $status == PhabricatorCalendarEventInvitee::STATUS_UNINVITED) { $uninvited[] = $phid; } } $count_added = count($added); $count_uninvited = count($uninvited); $added_text = null; $uninvited_text = null; if ($count_added > 0 && $count_uninvited == 0) { $added_text = $this->renderHandleList($added); $text = pht('%s invited %s.', $this->renderHandleLink($author_phid), $added_text); } else if ($count_added > 0 && $count_uninvited > 0) { $added_text = $this->renderHandleList($added); $uninvited_text = $this->renderHandleList($uninvited); $text = pht('%s invited %s and uninvited %s.', $this->renderHandleLink($author_phid), $added_text, $uninvited_text); } else if ($count_added == 0 && $count_uninvited > 0) { $uninvited_text = $this->renderHandleList($uninvited); $text = pht('%s uninvited %s.', $this->renderHandleLink($author_phid), $uninvited_text); } else { $text = pht('%s updated the invitee list.', $this->renderHandleLink($author_phid)); } } return $text; case self::TYPE_RECURRING: $text = pht('%s made this event recurring.', $this->renderHandleLink($author_phid)); return $text; case self::TYPE_FREQUENCY: $text = ''; switch ($new['rule']) { case PhabricatorCalendarEvent::FREQUENCY_DAILY: $text = pht('%s set this event to repeat daily.', $this->renderHandleLink($author_phid)); break; case PhabricatorCalendarEvent::FREQUENCY_WEEKLY: $text = pht('%s set this event to repeat weekly.', $this->renderHandleLink($author_phid)); break; case PhabricatorCalendarEvent::FREQUENCY_MONTHLY: $text = pht('%s set this event to repeat monthly.', $this->renderHandleLink($author_phid)); break; case PhabricatorCalendarEvent::FREQUENCY_YEARLY: $text = pht('%s set this event to repeat yearly.', $this->renderHandleLink($author_phid)); break; } return $text; case self::TYPE_RECURRENCE_END_DATE: $text = pht('%s has changed the recurrence end date of this event.', $this->renderHandleLink($author_phid)); return $text; - case self::TYPE_INSTANCE_OF_EVENT: - case self::TYPE_SEQUENCE_INDEX: - return pht('Recurring event has been updated.'); } return parent::getTitle(); } public function getTitleForFeed() { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); $viewer = $this->getViewer(); $type = $this->getTransactionType(); switch ($type) { case self::TYPE_NAME: if ($old === null) { return pht( '%s created %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } else { return pht( '%s changed the name of %s from %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old, $new); } case self::TYPE_START_DATE: if ($old) { $old = phabricator_datetime($old, $viewer); $new = phabricator_datetime($new, $viewer); return pht( '%s changed the start date of %s from %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old, $new); } break; case self::TYPE_END_DATE: if ($old) { $old = phabricator_datetime($old, $viewer); $new = phabricator_datetime($new, $viewer); return pht( '%s edited the end date of %s from %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old, $new); } break; case self::TYPE_DESCRIPTION: return pht( '%s updated the description of %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); case self::TYPE_ALL_DAY: if ($new) { return pht( '%s made %s an all day event.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } else { return pht( '%s converted %s from an all day event.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } case self::TYPE_ICON: $set = new PhabricatorCalendarIconSet(); return pht( '%s set the icon for %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $set->getIconLabel($new)); case self::TYPE_CANCEL: if ($new) { return pht( '%s cancelled %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } else { return pht( '%s reinstated %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } case self::TYPE_INVITE: $text = null; if (count($old) === 1 && count($new) === 1 && isset($old[$author_phid])) { // user joined/declined/accepted event themself $old_status = $old[$author_phid]; $new_status = $new[$author_phid]; if ($old_status !== $new_status) { switch ($new_status) { case PhabricatorCalendarEventInvitee::STATUS_INVITED: $text = pht( '%s has joined %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case PhabricatorCalendarEventInvitee::STATUS_ATTENDING: $text = pht( '%s is attending %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case PhabricatorCalendarEventInvitee::STATUS_DECLINED: case PhabricatorCalendarEventInvitee::STATUS_UNINVITED: $text = pht( '%s has declined %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; default: $text = pht( '%s has changed their status of %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; } } } else { // user changed status for many users $self_joined = null; $self_declined = null; $added = array(); $uninvited = array(); foreach ($new as $phid => $status) { if ($status == PhabricatorCalendarEventInvitee::STATUS_INVITED || $status == PhabricatorCalendarEventInvitee::STATUS_ATTENDING) { // added users $added[] = $phid; } else if ( $status == PhabricatorCalendarEventInvitee::STATUS_DECLINED || $status == PhabricatorCalendarEventInvitee::STATUS_UNINVITED) { $uninvited[] = $phid; } } $count_added = count($added); $count_uninvited = count($uninvited); $added_text = null; $uninvited_text = null; if ($count_added > 0 && $count_uninvited == 0) { $added_text = $this->renderHandleList($added); $text = pht('%s invited %s to %s.', $this->renderHandleLink($author_phid), $added_text, $this->renderHandleLink($object_phid)); } else if ($count_added > 0 && $count_uninvited > 0) { $added_text = $this->renderHandleList($added); $uninvited_text = $this->renderHandleList($uninvited); $text = pht('%s invited %s and uninvited %s to %s.', $this->renderHandleLink($author_phid), $added_text, $uninvited_text, $this->renderHandleLink($object_phid)); } else if ($count_added == 0 && $count_uninvited > 0) { $uninvited_text = $this->renderHandleList($uninvited); $text = pht('%s uninvited %s to %s.', $this->renderHandleLink($author_phid), $uninvited_text, $this->renderHandleLink($object_phid)); } else { $text = pht('%s updated the invitee list of %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } } return $text; case self::TYPE_RECURRING: $text = pht('%s made %s a recurring event.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); return $text; case self::TYPE_FREQUENCY: $text = ''; switch ($new['rule']) { case PhabricatorCalendarEvent::FREQUENCY_DAILY: $text = pht('%s set %s to repeat daily.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case PhabricatorCalendarEvent::FREQUENCY_WEEKLY: $text = pht('%s set %s to repeat weekly.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case PhabricatorCalendarEvent::FREQUENCY_MONTHLY: $text = pht('%s set %s to repeat monthly.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case PhabricatorCalendarEvent::FREQUENCY_YEARLY: $text = pht('%s set %s to repeat yearly.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; } return $text; case self::TYPE_RECURRENCE_END_DATE: $text = pht('%s set the recurrence end date of %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $new); return $text; - case self::TYPE_INSTANCE_OF_EVENT: - case self::TYPE_SEQUENCE_INDEX: - return pht('Recurring event has been updated.'); } return parent::getTitleForFeed(); } public function getColor() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_NAME: case self::TYPE_START_DATE: case self::TYPE_END_DATE: case self::TYPE_DESCRIPTION: case self::TYPE_CANCEL: case self::TYPE_INVITE: return PhabricatorTransactions::COLOR_GREEN; } return parent::getColor(); } public function hasChangeDetails() { switch ($this->getTransactionType()) { case self::TYPE_DESCRIPTION: return ($this->getOldValue() !== null); } return parent::hasChangeDetails(); } public function renderChangeDetails(PhabricatorUser $viewer) { switch ($this->getTransactionType()) { case self::TYPE_DESCRIPTION: $old = $this->getOldValue(); $new = $this->getNewValue(); return $this->renderTextCorpusChangeDetails( $viewer, $old, $new); } return parent::renderChangeDetails($viewer); } public function getMailTags() { $tags = array(); switch ($this->getTransactionType()) { case self::TYPE_NAME: case self::TYPE_DESCRIPTION: case self::TYPE_INVITE: case self::TYPE_ICON: $tags[] = self::MAILTAG_CONTENT; break; case self::TYPE_START_DATE: case self::TYPE_END_DATE: case self::TYPE_CANCEL: $tags[] = self::MAILTAG_RESCHEDULE; break; } return $tags; } }