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 @@ -2021,24 +2021,40 @@ 'PhabricatorCalendarDAO' => 'applications/calendar/storage/PhabricatorCalendarDAO.php', 'PhabricatorCalendarEditEngine' => 'applications/calendar/editor/PhabricatorCalendarEditEngine.php', 'PhabricatorCalendarEvent' => 'applications/calendar/storage/PhabricatorCalendarEvent.php', + 'PhabricatorCalendarEventAcceptTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventAcceptTransaction.php', + 'PhabricatorCalendarEventAllDayTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventAllDayTransaction.php', 'PhabricatorCalendarEventCancelController' => 'applications/calendar/controller/PhabricatorCalendarEventCancelController.php', + 'PhabricatorCalendarEventCancelTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventCancelTransaction.php', + 'PhabricatorCalendarEventDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventDateTransaction.php', + 'PhabricatorCalendarEventDeclineTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventDeclineTransaction.php', + 'PhabricatorCalendarEventDescriptionTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventDescriptionTransaction.php', 'PhabricatorCalendarEventDragController' => 'applications/calendar/controller/PhabricatorCalendarEventDragController.php', 'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php', 'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php', 'PhabricatorCalendarEventEmailCommand' => 'applications/calendar/command/PhabricatorCalendarEventEmailCommand.php', + 'PhabricatorCalendarEventEndDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventEndDateTransaction.php', + 'PhabricatorCalendarEventFrequencyTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventFrequencyTransaction.php', 'PhabricatorCalendarEventFulltextEngine' => 'applications/calendar/search/PhabricatorCalendarEventFulltextEngine.php', + 'PhabricatorCalendarEventIconTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventIconTransaction.php', + 'PhabricatorCalendarEventInviteTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventInviteTransaction.php', 'PhabricatorCalendarEventInvitee' => 'applications/calendar/storage/PhabricatorCalendarEventInvitee.php', 'PhabricatorCalendarEventInviteeQuery' => 'applications/calendar/query/PhabricatorCalendarEventInviteeQuery.php', 'PhabricatorCalendarEventJoinController' => 'applications/calendar/controller/PhabricatorCalendarEventJoinController.php', 'PhabricatorCalendarEventListController' => 'applications/calendar/controller/PhabricatorCalendarEventListController.php', 'PhabricatorCalendarEventMailReceiver' => 'applications/calendar/mail/PhabricatorCalendarEventMailReceiver.php', + 'PhabricatorCalendarEventNameTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventNameTransaction.php', 'PhabricatorCalendarEventPHIDType' => 'applications/calendar/phid/PhabricatorCalendarEventPHIDType.php', 'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php', 'PhabricatorCalendarEventRSVPEmailCommand' => 'applications/calendar/command/PhabricatorCalendarEventRSVPEmailCommand.php', + 'PhabricatorCalendarEventRecurringTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventRecurringTransaction.php', + 'PhabricatorCalendarEventReplyTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventReplyTransaction.php', 'PhabricatorCalendarEventSearchEngine' => 'applications/calendar/query/PhabricatorCalendarEventSearchEngine.php', + 'PhabricatorCalendarEventStartDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventStartDateTransaction.php', 'PhabricatorCalendarEventTransaction' => 'applications/calendar/storage/PhabricatorCalendarEventTransaction.php', 'PhabricatorCalendarEventTransactionComment' => 'applications/calendar/storage/PhabricatorCalendarEventTransactionComment.php', 'PhabricatorCalendarEventTransactionQuery' => 'applications/calendar/query/PhabricatorCalendarEventTransactionQuery.php', + 'PhabricatorCalendarEventTransactionType' => 'applications/calendar/xaction/PhabricatorCalendarEventTransactionType.php', + 'PhabricatorCalendarEventUntilDateTransaction' => 'applications/calendar/xaction/PhabricatorCalendarEventUntilDateTransaction.php', 'PhabricatorCalendarEventViewController' => 'applications/calendar/controller/PhabricatorCalendarEventViewController.php', 'PhabricatorCalendarHoliday' => 'applications/calendar/storage/PhabricatorCalendarHoliday.php', 'PhabricatorCalendarHolidayTestCase' => 'applications/calendar/storage/__tests__/PhabricatorCalendarHolidayTestCase.php', @@ -6629,12 +6645,22 @@ 'PhabricatorSpacesInterface', 'PhabricatorFulltextInterface', ), + 'PhabricatorCalendarEventAcceptTransaction' => 'PhabricatorCalendarEventReplyTransaction', + 'PhabricatorCalendarEventAllDayTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventCancelController' => 'PhabricatorCalendarController', + 'PhabricatorCalendarEventCancelTransaction' => 'PhabricatorCalendarEventTransactionType', + 'PhabricatorCalendarEventDateTransaction' => 'PhabricatorCalendarEventTransactionType', + 'PhabricatorCalendarEventDeclineTransaction' => 'PhabricatorCalendarEventReplyTransaction', + 'PhabricatorCalendarEventDescriptionTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventDragController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorCalendarEventEmailCommand' => 'MetaMTAEmailTransactionCommand', + 'PhabricatorCalendarEventEndDateTransaction' => 'PhabricatorCalendarEventDateTransaction', + 'PhabricatorCalendarEventFrequencyTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventFulltextEngine' => 'PhabricatorFulltextEngine', + 'PhabricatorCalendarEventIconTransaction' => 'PhabricatorCalendarEventTransactionType', + 'PhabricatorCalendarEventInviteTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventInvitee' => array( 'PhabricatorCalendarDAO', 'PhabricatorPolicyInterface', @@ -6643,13 +6669,19 @@ 'PhabricatorCalendarEventJoinController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventListController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventMailReceiver' => 'PhabricatorObjectMailReceiver', + 'PhabricatorCalendarEventNameTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventPHIDType' => 'PhabricatorPHIDType', 'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorCalendarEventRSVPEmailCommand' => 'PhabricatorCalendarEventEmailCommand', + 'PhabricatorCalendarEventRecurringTransaction' => 'PhabricatorCalendarEventTransactionType', + 'PhabricatorCalendarEventReplyTransaction' => 'PhabricatorCalendarEventTransactionType', 'PhabricatorCalendarEventSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'PhabricatorCalendarEventTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorCalendarEventStartDateTransaction' => 'PhabricatorCalendarEventDateTransaction', + 'PhabricatorCalendarEventTransaction' => 'PhabricatorModularTransaction', 'PhabricatorCalendarEventTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorCalendarEventTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorCalendarEventTransactionType' => 'PhabricatorModularTransactionType', + 'PhabricatorCalendarEventUntilDateTransaction' => 'PhabricatorCalendarEventDateTransaction', 'PhabricatorCalendarEventViewController' => 'PhabricatorCalendarController', 'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO', 'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase', diff --git a/src/applications/calendar/command/PhabricatorCalendarEventRSVPEmailCommand.php b/src/applications/calendar/command/PhabricatorCalendarEventRSVPEmailCommand.php --- a/src/applications/calendar/command/PhabricatorCalendarEventRSVPEmailCommand.php +++ b/src/applications/calendar/command/PhabricatorCalendarEventRSVPEmailCommand.php @@ -44,32 +44,24 @@ PhabricatorMetaMTAReceivedMail $mail, $command, array $argv) { - $status_attending = PhabricatorCalendarEventInvitee::STATUS_ATTENDING; - $status_declined = PhabricatorCalendarEventInvitee::STATUS_DECLINED; - $xactions = array(); $target = phutil_utf8_strtolower(implode(' ', $argv)); - $rsvp = null; $yes_values = $this->getYesValues(); $no_values = $this->getNoValues(); if (in_array($target, $yes_values)) { - $rsvp = $status_attending; + $rsvp = PhabricatorCalendarEventAcceptTransaction::TRANSACTIONTYPE; } else if (in_array($target, $no_values)) { - $rsvp = $status_declined; + $rsvp = PhabricatorCalendarEventDeclineTransaction::TRANSACTIONTYPE; } else { - $rsvp = null; - } - - if ($rsvp === null) { return array(); } + $xactions = array(); $xactions[] = $object->getApplicationTransactionTemplate() - ->setTransactionType(PhabricatorCalendarEventTransaction::TYPE_INVITE) - ->setNewValue(array($viewer->getPHID() => $rsvp)); - + ->setTransactionType($rsvp) + ->setNewValue(true); return $xactions; } diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php --- a/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventCancelController.php @@ -38,7 +38,7 @@ $xaction = id(new PhabricatorCalendarEventTransaction()) ->setTransactionType( - PhabricatorCalendarEventTransaction::TYPE_CANCEL) + PhabricatorCalendarEventCancelTransaction::TRANSACTIONTYPE) ->setNewValue(!$is_cancelled); $editor = id(new PhabricatorCalendarEventEditor()) diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventDragController.php b/src/applications/calendar/controller/PhabricatorCalendarEventDragController.php --- a/src/applications/calendar/controller/PhabricatorCalendarEventDragController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventDragController.php @@ -41,13 +41,14 @@ $viewer, $end)); - $xactions[] = id(new PhabricatorCalendarEventTransaction()) - ->setTransactionType(PhabricatorCalendarEventTransaction::TYPE_START_DATE) + ->setTransactionType( + PhabricatorCalendarEventStartDateTransaction::TRANSACTIONTYPE) ->setNewValue($start_value); $xactions[] = id(new PhabricatorCalendarEventTransaction()) - ->setTransactionType(PhabricatorCalendarEventTransaction::TYPE_END_DATE) + ->setTransactionType( + PhabricatorCalendarEventEndDateTransaction::TRANSACTIONTYPE) ->setNewValue($end_value); $editor = id(new PhabricatorCalendarEventEditor()) diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php b/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php --- a/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventJoinController.php @@ -33,9 +33,11 @@ $validation_exception = null; if ($request->isFormPost()) { if ($is_join) { - $xaction_type = PhabricatorCalendarEventTransaction::TYPE_ACCEPT; + $xaction_type = + PhabricatorCalendarEventAcceptTransaction::TRANSACTIONTYPE; } else { - $xaction_type = PhabricatorCalendarEventTransaction::TYPE_DECLINE; + $xaction_type = + PhabricatorCalendarEventDeclineTransaction::TRANSACTIONTYPE; } $xaction = id(new PhabricatorCalendarEventTransaction()) 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 @@ -120,7 +120,7 @@ if ($event->isChildEvent()) { $edit_label = pht('Edit This Instance'); } else { - $edit_label = pht('Edit'); + $edit_label = pht('Edit Event'); } $curtain = $this->newCurtainView($event); diff --git a/src/applications/calendar/editor/PhabricatorCalendarEditEngine.php b/src/applications/calendar/editor/PhabricatorCalendarEditEngine.php --- a/src/applications/calendar/editor/PhabricatorCalendarEditEngine.php +++ b/src/applications/calendar/editor/PhabricatorCalendarEditEngine.php @@ -81,7 +81,8 @@ ->setLabel(pht('Name')) ->setDescription(pht('Name of the event.')) ->setIsRequired(true) - ->setTransactionType(PhabricatorCalendarEventTransaction::TYPE_NAME) + ->setTransactionType( + PhabricatorCalendarEventNameTransaction::TRANSACTIONTYPE) ->setConduitDescription(pht('Rename the event.')) ->setConduitTypeDescription(pht('New event name.')) ->setValue($object->getName()), @@ -90,7 +91,7 @@ ->setLabel(pht('Description')) ->setDescription(pht('Description of the event.')) ->setTransactionType( - PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION) + PhabricatorCalendarEventDescriptionTransaction::TRANSACTIONTYPE) ->setConduitDescription(pht('Update the event description.')) ->setConduitTypeDescription(pht('New event description.')) ->setValue($object->getDescription()), @@ -100,7 +101,7 @@ ->setLabel(pht('Cancelled')) ->setDescription(pht('Cancel the event.')) ->setTransactionType( - PhabricatorCalendarEventTransaction::TYPE_CANCEL) + PhabricatorCalendarEventCancelTransaction::TRANSACTIONTYPE) ->setIsConduitOnly(true) ->setConduitDescription(pht('Cancel or restore the event.')) ->setConduitTypeDescription(pht('True to cancel the event.')) @@ -110,7 +111,8 @@ ->setAliases(array('invite', 'invitee', 'invitees', 'inviteePHID')) ->setLabel(pht('Invitees')) ->setDatasource(new PhabricatorMetaMTAMailableDatasource()) - ->setTransactionType(PhabricatorCalendarEventTransaction::TYPE_INVITE) + ->setTransactionType( + PhabricatorCalendarEventInviteTransaction::TRANSACTIONTYPE) ->setDescription(pht('Users invited to the event.')) ->setConduitDescription(pht('Change invited users.')) ->setConduitTypeDescription(pht('New event invitees.')) @@ -124,7 +126,7 @@ ->setLabel(pht('Recurring')) ->setOptions(pht('One-Time Event'), pht('Recurring Event')) ->setTransactionType( - PhabricatorCalendarEventTransaction::TYPE_RECURRING) + PhabricatorCalendarEventRecurringTransaction::TRANSACTIONTYPE) ->setDescription(pht('One time or recurring event.')) ->setConduitDescription(pht('Make the event recurring.')) ->setConduitTypeDescription(pht('Mark the event as a recurring event.')) @@ -135,7 +137,7 @@ ->setLabel(pht('Frequency')) ->setOptions($frequency_options) ->setTransactionType( - PhabricatorCalendarEventTransaction::TYPE_FREQUENCY) + PhabricatorCalendarEventFrequencyTransaction::TRANSACTIONTYPE) ->setDescription(pht('Recurring event frequency.')) ->setConduitDescription(pht('Change the event frequency.')) ->setConduitTypeDescription(pht('New event frequency.')) @@ -148,7 +150,7 @@ ->setKey('until') ->setLabel(pht('Repeat Until')) ->setTransactionType( - PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE) + PhabricatorCalendarEventUntilDateTransaction::TRANSACTIONTYPE) ->setDescription(pht('Last instance of the event.')) ->setConduitDescription(pht('Change when the event repeats until.')) ->setConduitTypeDescription(pht('New final event time.')) @@ -159,7 +161,8 @@ ->setKey('isAllDay') ->setLabel(pht('All Day')) ->setOptions(pht('Normal Event'), pht('All Day Event')) - ->setTransactionType(PhabricatorCalendarEventTransaction::TYPE_ALL_DAY) + ->setTransactionType( + PhabricatorCalendarEventAllDayTransaction::TRANSACTIONTYPE) ->setDescription(pht('Marks this as an all day event.')) ->setConduitDescription(pht('Make the event an all day event.')) ->setConduitTypeDescription(pht('Mark the event as an all day event.')) @@ -169,7 +172,7 @@ ->setKey('start') ->setLabel(pht('Start')) ->setTransactionType( - PhabricatorCalendarEventTransaction::TYPE_START_DATE) + PhabricatorCalendarEventStartDateTransaction::TRANSACTIONTYPE) ->setDescription(pht('Start time of the event.')) ->setConduitDescription(pht('Change the start time of the event.')) ->setConduitTypeDescription(pht('New event start time.')) @@ -179,7 +182,7 @@ ->setKey('end') ->setLabel(pht('End')) ->setTransactionType( - PhabricatorCalendarEventTransaction::TYPE_END_DATE) + PhabricatorCalendarEventEndDateTransaction::TRANSACTIONTYPE) ->setDescription(pht('End time of the event.')) ->setConduitDescription(pht('Change the end time of the event.')) ->setConduitTypeDescription(pht('New event end time.')) @@ -189,7 +192,8 @@ ->setKey('icon') ->setLabel(pht('Icon')) ->setIconSet(new PhabricatorCalendarIconSet()) - ->setTransactionType(PhabricatorCalendarEventTransaction::TYPE_ICON) + ->setTransactionType( + PhabricatorCalendarEventIconTransaction::TRANSACTIONTYPE) ->setDescription(pht('Event icon.')) ->setConduitDescription(pht('Change the event icon.')) ->setConduitTypeDescription(pht('New event icon.')) diff --git a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php --- a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php +++ b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php @@ -58,21 +58,6 @@ 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_ACCEPT; - $types[] = PhabricatorCalendarEventTransaction::TYPE_DECLINE; - - $types[] = PhabricatorCalendarEventTransaction::TYPE_RECURRING; - $types[] = PhabricatorCalendarEventTransaction::TYPE_FREQUENCY; - $types[] = PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE; - $types[] = PhabricatorTransactions::TYPE_COMMENT; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; @@ -80,217 +65,6 @@ return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - switch ($xaction->getTransactionType()) { - case PhabricatorCalendarEventTransaction::TYPE_RECURRING: - return (int)$object->getIsRecurring(); - case PhabricatorCalendarEventTransaction::TYPE_FREQUENCY: - return $object->getFrequencyUnit(); - case PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE: - return $object->getRecurrenceEndDate(); - 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_ACCEPT: - case PhabricatorCalendarEventTransaction::TYPE_DECLINE: - $actor_phid = $this->getActingAsPHID(); - return $object->getUserInviteStatus($actor_phid); - case PhabricatorCalendarEventTransaction::TYPE_INVITE: - $invitees = $object->getInvitees(); - return mpull($invitees, 'getStatus', 'getInviteePHID'); - } - - return parent::getCustomTransactionOldValue($object, $xaction); - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - switch ($xaction->getTransactionType()) { - case PhabricatorCalendarEventTransaction::TYPE_FREQUENCY: - case PhabricatorCalendarEventTransaction::TYPE_NAME: - case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION: - case PhabricatorCalendarEventTransaction::TYPE_CANCEL: - case PhabricatorCalendarEventTransaction::TYPE_ICON: - return $xaction->getNewValue(); - case PhabricatorCalendarEventTransaction::TYPE_ACCEPT: - return PhabricatorCalendarEventInvitee::STATUS_ATTENDING; - case PhabricatorCalendarEventTransaction::TYPE_DECLINE: - return PhabricatorCalendarEventInvitee::STATUS_DECLINED; - case PhabricatorCalendarEventTransaction::TYPE_ALL_DAY: - case PhabricatorCalendarEventTransaction::TYPE_RECURRING: - return (int)$xaction->getNewValue(); - case PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE: - case PhabricatorCalendarEventTransaction::TYPE_START_DATE: - case PhabricatorCalendarEventTransaction::TYPE_END_DATE: - return $xaction->getNewValue()->getEpoch(); - case PhabricatorCalendarEventTransaction::TYPE_INVITE: - $status_invited = PhabricatorCalendarEventInvitee::STATUS_INVITED; - $status_uninvited = PhabricatorCalendarEventInvitee::STATUS_UNINVITED; - $status_attending = PhabricatorCalendarEventInvitee::STATUS_ATTENDING; - - $invitees = $object->getInvitees(); - foreach ($invitees as $key => $invitee) { - if ($invitee->getStatus() == $status_uninvited) { - unset($invitees[$key]); - } - } - $invitees = mpull($invitees, null, 'getInviteePHID'); - - $new = $xaction->getNewValue(); - $new = array_fuse($new); - - $all = array_keys($invitees + $new); - $map = array(); - foreach ($all as $phid) { - $is_old = isset($invitees[$phid]); - $is_new = isset($new[$phid]); - - if ($is_old && !$is_new) { - $map[$phid] = $status_uninvited; - } else if (!$is_old && $is_new) { - $map[$phid] = $status_invited; - } else { - $map[$phid] = $invitees[$phid]->getStatus(); - } - } - - // If we're creating this event and the actor is inviting themselves, - // mark them as attending. - if ($this->getIsNewObject()) { - $acting_phid = $this->getActingAsPHID(); - if (isset($map[$acting_phid])) { - $map[$acting_phid] = $status_attending; - } - } - - return $map; - } - - return parent::getCustomTransactionNewValue($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorCalendarEventTransaction::TYPE_RECURRING: - return $object->setIsRecurring((int)$xaction->getNewValue()); - case PhabricatorCalendarEventTransaction::TYPE_FREQUENCY: - return $object->setRecurrenceFrequency( - array( - 'rule' => $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: - case PhabricatorCalendarEventTransaction::TYPE_ACCEPT: - case PhabricatorCalendarEventTransaction::TYPE_DECLINE: - 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_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; - case PhabricatorCalendarEventTransaction::TYPE_ACCEPT: - case PhabricatorCalendarEventTransaction::TYPE_DECLINE: - $acting_phid = $this->getActingAsPHID(); - - $invitees = $object->getInvitees(); - $invitees = mpull($invitees, null, 'getInviteePHID'); - - $invitee = idx($invitees, $acting_phid); - if (!$invitee) { - $invitee = id(new PhabricatorCalendarEventInvitee()) - ->setEventPHID($object->getPHID()) - ->setInviteePHID($acting_phid) - ->setInviterPHID($acting_phid); - $invitees[$acting_phid] = $invitee; - } - - $invitee - ->setStatus($xaction->getNewValue()) - ->save(); - - $object->attachInvitees($invitees); - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - protected function applyFinalEffects( PhabricatorLiskDAO $object, array $xactions) { @@ -302,26 +76,21 @@ $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_START_DATE: - case PhabricatorCalendarEventTransaction::TYPE_END_DATE: - case PhabricatorCalendarEventTransaction::TYPE_CANCEL: - case PhabricatorCalendarEventTransaction::TYPE_ALL_DAY: + case PhabricatorCalendarEventUntilDateTransaction::TRANSACTIONTYPE: + case PhabricatorCalendarEventStartDateTransaction::TRANSACTIONTYPE: + case PhabricatorCalendarEventEndDateTransaction::TRANSACTIONTYPE: + case PhabricatorCalendarEventCancelTransaction::TRANSACTIONTYPE: + case PhabricatorCalendarEventAllDayTransaction::TRANSACTIONTYPE: // For these kinds of changes, we need to invalidate the availabilty // caches for all attendees. $invalidate_all = true; break; - - case PhabricatorCalendarEventTransaction::TYPE_ACCEPT: - case PhabricatorCalendarEventTransaction::TYPE_DECLINE: + case PhabricatorCalendarEventAcceptTransaction::TRANSACTIONTYPE: + case PhabricatorCalendarEventDeclineTransaction::TRANSACTIONTYPE: $acting_phid = $this->getActingAsPHID(); $invalidate_phids[$acting_phid] = $acting_phid; break; - case PhabricatorCalendarEventTransaction::TYPE_INVITE: + case PhabricatorCalendarEventInviteTransaction::TRANSACTIONTYPE: foreach ($xaction->getNewValue() as $phid => $ignored) { $invalidate_phids[$phid] = $phid; } @@ -357,14 +126,15 @@ protected function validateAllTransactions( PhabricatorLiskDAO $object, array $xactions) { + $start_date_xaction = - PhabricatorCalendarEventTransaction::TYPE_START_DATE; + PhabricatorCalendarEventStartDateTransaction::TRANSACTIONTYPE; $end_date_xaction = - PhabricatorCalendarEventTransaction::TYPE_END_DATE; + PhabricatorCalendarEventEndDateTransaction::TRANSACTIONTYPE; $is_recurrence_xaction = - PhabricatorCalendarEventTransaction::TYPE_RECURRING; + PhabricatorCalendarEventRecurringTransaction::TRANSACTIONTYPE; $recurrence_end_xaction = - PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE; + PhabricatorCalendarEventUntilDateTransaction::TRANSACTIONTYPE; $start_date = $object->getDateFrom(); $end_date = $object->getDateTo(); @@ -386,19 +156,16 @@ } if ($start_date > $end_date) { - $type = PhabricatorCalendarEventTransaction::TYPE_END_DATE; $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, + $end_date_xaction, 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, + $recurrence_end_xaction, pht('Invalid'), pht('Event must be recurring to have a recurrence end date.'). null); @@ -407,97 +174,6 @@ 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_INVITE: - $old = $object->getInvitees(); - $old = mpull($old, null, 'getInviteePHID'); - foreach ($xactions as $xaction) { - $new = $xaction->getNewValue(); - $new = array_fuse($new); - $add = array_diff_key($new, $old); - if (!$add) { - continue; - } - - // In the UI, we only allow you to invite mailable objects, but there - // is no definitive marker for "invitable object" today. Just allow - // any valid object to be invited. - $objects = id(new PhabricatorObjectQuery()) - ->setViewer($this->getActor()) - ->withPHIDs($add) - ->execute(); - $objects = mpull($objects, null, 'getPHID'); - foreach ($add as $phid) { - if (isset($objects[$phid])) { - continue; - } - - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'Invitee "%s" identifies an object that does not exist or '. - 'which you do not have permission to view.', - $phid)); - } - } - break; - case PhabricatorCalendarEventTransaction::TYPE_START_DATE: - case PhabricatorCalendarEventTransaction::TYPE_END_DATE: - case PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE: - foreach ($xactions as $xaction) { - if ($xaction->getNewValue()->isValid()) { - continue; - } - - switch ($type) { - case PhabricatorCalendarEventTransaction::TYPE_START_DATE: - $message = pht('Start date is invalid.'); - break; - case PhabricatorCalendarEventTransaction::TYPE_END_DATE: - $message = pht('End date is invalid.'); - break; - case PhabricatorCalendarEventTransaction::TYPE_RECURRENCE_END_DATE: - $message = pht('Repeat until date is invalid.'); - break; - } - - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - $message, - $xaction); - } - break; - - } - - return $errors; - } - protected function shouldPublishFeedStory( PhabricatorLiskDAO $object, array $xactions) { diff --git a/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php b/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php --- a/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php +++ b/src/applications/calendar/storage/PhabricatorCalendarEventTransaction.php @@ -1,22 +1,7 @@ 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: - $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: - 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: - 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_ACCEPT: - return pht( - '%s is attending this event.', - $this->renderHandleLink($author_phid)); - case self::TYPE_DECLINE: - return pht( - '%s declined this event.', - $this->renderHandleLink($author_phid)); - case self::TYPE_INVITE: - $text = null; - - list($old, $new) = $this->getSimpleInvites($old, $new); - - 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: - $rule = $new; - if (is_array($rule)) { - $rule = idx($rule, 'rule'); - } - - $text = ''; - switch ($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; - } - 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_ACCEPT: - return pht( - '%s is attending %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case self::TYPE_DECLINE: - return pht( - '%s declined %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case self::TYPE_INVITE: - $text = null; - - list($old, $new) = $this->getSimpleInvites($old, $new); - - 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: - $rule = $new; - if (is_array($rule)) { - $rule = idx($rule, 'rule'); - } - - $text = ''; - switch ($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; - } - - 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 getBaseTransactionClass() { + return 'PhabricatorCalendarEventTransactionType'; } public function getMailTags() { $tags = array(); switch ($this->getTransactionType()) { - case self::TYPE_NAME: - case self::TYPE_DESCRIPTION: - case self::TYPE_INVITE: - case self::TYPE_ICON: + case PhabricatorCalendarEventNameTransaction::TRANSACTIONTYPE: + case PhabricatorCalendarEventDescriptionTransaction::TRANSACTIONTYPE: + case PhabricatorCalendarEventInviteTransaction::TRANSACTIONTYPE: $tags[] = self::MAILTAG_CONTENT; break; - case self::TYPE_START_DATE: - case self::TYPE_END_DATE: - case self::TYPE_CANCEL: + case PhabricatorCalendarEventStartDateTransaction::TRANSACTIONTYPE: + case PhabricatorCalendarEventEndDateTransaction::TRANSACTIONTYPE: + case PhabricatorCalendarEventCancelTransaction::TRANSACTIONTYPE: $tags[] = self::MAILTAG_RESCHEDULE; break; } return $tags; } - private function getSimpleInvites(array $old, array $new) { - // Fill in any new invitees as "uninvited" in the old data, to make - // some of the rendering logic a little easier. - $status_uninvited = PhabricatorCalendarEventInvitee::STATUS_UNINVITED; - $old = $old + array_fill_keys(array_keys($new), $status_uninvited); - - $all = $old + $new; - foreach (array_keys($all) as $key) { - // If the invitee exists in both the old and new lists with the same - // value, remove it from both. - if (isset($old[$key]) && isset($new[$key])) { - if ($old[$key] == $new[$key]) { - unset($old[$key]); - unset($new[$key]); - } - } - } - - return array($old, $new); - } - - } diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventAcceptTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventAcceptTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventAcceptTransaction.php @@ -0,0 +1,25 @@ +renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s is attending %s.', + $this->renderAuthor(), + $this->renderObject()); + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventAllDayTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventAllDayTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventAllDayTransaction.php @@ -0,0 +1,46 @@ +getIsAllDay(); + } + + public function generateNewValue($object, $value) { + return (int)$value; + } + + public function applyInternalEffects($object, $value) { + $object->setIsAllDay($value); + } + + public function getTitle() { + if ($this->getNewValue()) { + return pht( + '%s changed this as an all day event.', + $this->renderAuthor()); + } else { + return pht( + '%s conveted this from an all day event.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + if ($this->getNewValue()) { + return pht( + '%s changed %s to an all day event.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s converted %s from an all day event.', + $this->renderAuthor(), + $this->renderObject()); + } + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventCancelTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventCancelTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventCancelTransaction.php @@ -0,0 +1,46 @@ +getIsCancelled(); + } + + public function generateNewValue($object, $value) { + return (int)$value; + } + + public function applyInternalEffects($object, $value) { + $object->setIsCancelled($value); + } + + public function getTitle() { + if ($this->getNewValue()) { + return pht( + '%s cancelled this event.', + $this->renderAuthor()); + } else { + return pht( + '%s reinstated this event.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + if ($this->getNewValue()) { + return pht( + '%s cancelled %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s reinstated %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventDateTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventDateTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventDateTransaction.php @@ -0,0 +1,27 @@ +getEpoch(); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + foreach ($xactions as $xaction) { + if ($xaction->getNewValue()->isValid()) { + continue; + } + + $message = $this->getInvalidDateMessage(); + $errors[] = $this->newInvalidError($message, $xaction); + } + + return $errors; + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventDeclineTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventDeclineTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventDeclineTransaction.php @@ -0,0 +1,25 @@ +renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s declined %s.', + $this->renderAuthor(), + $this->renderObject()); + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventDescriptionTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventDescriptionTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventDescriptionTransaction.php @@ -0,0 +1,42 @@ +getDescription(); + } + + public function applyInternalEffects($object, $value) { + $object->setDescription($value); + } + + public function getTitle() { + return pht( + '%s updated the event description.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the event description for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventEndDateTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventEndDateTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventEndDateTransaction.php @@ -0,0 +1,37 @@ +getDateTo(); + } + + public function applyInternalEffects($object, $value) { + $object->setDateTo($value); + } + + public function getTitle() { + return pht( + '%s changed the end date for this event from %s to %s.', + $this->renderAuthor(), + $this->renderOldDate(), + $this->renderNewDate()); + } + + public function getTitleForFeed() { + return pht( + '%s changed the end date for %s from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldDate(), + $this->renderNewDate()); + } + + protected function getInvalidDateMessage() { + return pht('End date is invalid.'); + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventFrequencyTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventFrequencyTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventFrequencyTransaction.php @@ -0,0 +1,75 @@ +getFrequencyUnit(); + } + + public function applyInternalEffects($object, $value) { + $object->setRecurrenceFrequency( + array( + 'rule' => $value, + )); + } + + public function getTitle() { + $frequency = $this->getFrequencyUnit($this->getNewValue()); + switch ($frequency) { + case PhabricatorCalendarEvent::FREQUENCY_DAILY: + return pht( + '%s set this event to repeat daily.', + $this->renderAuthor()); + case PhabricatorCalendarEvent::FREQUENCY_WEEKLY: + return pht( + '%s set this event to repeat weekly.', + $this->renderAuthor()); + case PhabricatorCalendarEvent::FREQUENCY_MONTHLY: + return pht( + '%s set this event to repeat monthly.', + $this->renderAuthor()); + case PhabricatorCalendarEvent::FREQUENCY_YEARLY: + return pht( + '%s set this event to repeat yearly.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + $frequency = $this->getFrequencyUnit($this->getNewValue()); + switch ($frequency) { + case PhabricatorCalendarEvent::FREQUENCY_DAILY: + return pht( + '%s set %s to repeat daily.', + $this->renderAuthor(), + $this->renderObject()); + case PhabricatorCalendarEvent::FREQUENCY_WEEKLY: + return pht( + '%s set %s to repeat weekly.', + $this->renderAuthor(), + $this->renderObject()); + case PhabricatorCalendarEvent::FREQUENCY_MONTHLY: + return pht( + '%s set %s to repeat monthly.', + $this->renderAuthor(), + $this->renderObject()); + case PhabricatorCalendarEvent::FREQUENCY_YEARLY: + return pht( + '%s set %s to repeat yearly.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + private function getFrequencyUnit($value) { + if (is_array($value)) { + $value = idx($value, 'rule'); + } else { + return $value; + } + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventIconTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventIconTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventIconTransaction.php @@ -0,0 +1,44 @@ +getIcon(); + } + + public function applyInternalEffects($object, $value) { + $object->setIcon($value); + } + + public function getTitle() { + $old = $this->getIconLabel($this->getOldValue()); + $new = $this->getIconLabel($this->getNewValue()); + + return pht( + '%s changed the event icon from %s to %s.', + $this->renderAuthor(), + $this->renderValue($old), + $this->renderValue($new)); + } + + public function getTitleForFeed() { + $old = $this->getIconLabel($this->getOldValue()); + $new = $this->getIconLabel($this->getNewValue()); + + return pht( + '%s changed the icon for %s from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderValue($old), + $this->renderValue($new)); + } + + private function getIconLabel($icon) { + $set = new PhabricatorCalendarIconSet(); + return $set->getIconLabel($icon); + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventInviteTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventInviteTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventInviteTransaction.php @@ -0,0 +1,191 @@ +getInvitees(); + foreach ($invitees as $key => $invitee) { + if ($invitee->getStatus() == $status_uninvited) { + unset($invitees[$key]); + } + } + + return mpull($invitees, 'getStatus', 'getInviteePHID'); + } + + public function generateNewValue($object, $value) { + $status_invited = PhabricatorCalendarEventInvitee::STATUS_INVITED; + $status_uninvited = PhabricatorCalendarEventInvitee::STATUS_UNINVITED; + $status_attending = PhabricatorCalendarEventInvitee::STATUS_ATTENDING; + + $invitees = $this->generateOldValue($object); + + $new = array_fuse($value); + + $all = array_keys($invitees + $new); + $map = array(); + foreach ($all as $phid) { + $is_old = isset($invitees[$phid]); + $is_new = isset($new[$phid]); + + if ($is_old && !$is_new) { + $map[$phid] = $status_uninvited; + } else if (!$is_old && $is_new) { + $map[$phid] = $status_invited; + } else { + $map[$phid] = $invitees[$phid]; + } + } + + // If we're creating this event and the actor is inviting themselves, + // mark them as attending. + if ($this->isNewObject()) { + $acting_phid = $this->getActingAsPHID(); + if (isset($map[$acting_phid])) { + $map[$acting_phid] = $status_attending; + } + } + + return $map; + } + + public function applyExternalEffects($object, $value) { + $phids = array_keys($value); + $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($value[$phid]) + ->save(); + } + + $object->attachInvitees($invitees); + } + + public function validateTransactions($object, array $xactions) { + $actor = $this->getActor(); + + $errors = array(); + + $old = $object->getInvitees(); + $old = mpull($old, null, 'getInviteePHID'); + foreach ($xactions as $xaction) { + $new = $xaction->getNewValue(); + $new = array_fuse($new); + $add = array_diff_key($new, $old); + if (!$add) { + continue; + } + + // In the UI, we only allow you to invite mailable objects, but there + // is no definitive marker for "invitable object" today. Just allow + // any valid object to be invited. + $objects = id(new PhabricatorObjectQuery()) + ->setViewer($actor) + ->withPHIDs($add) + ->execute(); + $objects = mpull($objects, null, 'getPHID'); + foreach ($add as $phid) { + if (isset($objects[$phid])) { + continue; + } + + $errors[] = $this->newInvalidError( + pht( + 'Invitee "%s" identifies an object that does not exist or '. + 'which you do not have permission to view.', + $phid), + $xaction); + } + } + + return $errors; + } + + public function getIcon() { + return 'fa-user-plus'; + } + + public function getTitle() { + list($add, $rem) = $this->getChanges(); + + if ($add && !$rem) { + return pht( + '%s invited %s attendee(s): %s.', + $this->renderAuthor(), + phutil_count($add), + $this->renderHandleList($add)); + } else if (!$add && $rem) { + return pht( + '%s uninvited %s attendee(s): %s.', + $this->renderAuthor(), + phutil_count($rem), + $this->renderHandleList($rem)); + } else { + return pht( + '%s invited %s attendee(s): %s; uninvinted %s attendee(s): %s.', + $this->renderAuthor(), + phutil_count($add), + $this->renderHandleList($add), + phutil_count($rem), + $this->renderHandleList($rem)); + } + } + + public function getTitleForFeed() { + list($add, $rem) = $this->getChanges(); + + if ($add && !$rem) { + return pht( + '%s invited %s attendee(s) to %s: %s.', + $this->renderAuthor(), + phutil_count($add), + $this->renderObject(), + $this->renderHandleList($add)); + } else if (!$add && $rem) { + return pht( + '%s uninvited %s attendee(s) to %s: %s.', + $this->renderAuthor(), + phutil_count($rem), + $this->renderObject(), + $this->renderHandleList($rem)); + } else { + return pht( + '%s updated the invite list for %s, invited %s: %s; '. + 'uninvinted %s: %s.', + $this->renderAuthor(), + $this->renderObject(), + phutil_count($add), + $this->renderHandleList($add), + phutil_count($rem), + $this->renderHandleList($rem)); + } + } + + private function getChanges() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $add = array_diff_key($new, $old); + $rem = array_diff_key($old, $new); + + $add = array_keys($add); + $rem = array_keys($rem); + + return array(array_fuse($add), array_fuse($rem)); + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventNameTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventNameTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventNameTransaction.php @@ -0,0 +1,44 @@ +getName(); + } + + public function applyInternalEffects($object, $value) { + $object->setName($value); + } + + public function getTitle() { + return pht( + '%s renamed this event from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function getTitleForFeed() { + return pht( + '%s renamed %s from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Events must have a name.')); + } + + return $errors; + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventRecurringTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventRecurringTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventRecurringTransaction.php @@ -0,0 +1,44 @@ +getIsRecurring(); + } + + public function generateNewValue($object, $value) { + return (int)$value; + } + + public function applyInternalEffects($object, $value) { + $object->setIsRecurring($value); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $old = $object->getIsRecurring(); + foreach ($xactions as $xaction) { + if ($this->getIsNewObject()) { + continue; + } + + if ($xaction->getNewValue() == $old) { + continue; + } + + $errors[] = $this->newInvalidError( + pht( + 'An event can only be made recurring when it is created. '. + 'You can not convert an existing event into a recurring '. + 'event or vice versa.'), + $xaction); + } + + return $errors; + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventReplyTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventReplyTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventReplyTransaction.php @@ -0,0 +1,33 @@ +getActingAsPHID(); + return $object->getUserInviteStatus($actor_phid); + } + + public function applyExternalEffects($object, $value) { + $acting_phid = $this->getActingAsPHID(); + + $invitees = $object->getInvitees(); + $invitees = mpull($invitees, null, 'getInviteePHID'); + + $invitee = idx($invitees, $acting_phid); + if (!$invitee) { + $invitee = id(new PhabricatorCalendarEventInvitee()) + ->setEventPHID($object->getPHID()) + ->setInviteePHID($acting_phid) + ->setInviterPHID($acting_phid); + $invitees[$acting_phid] = $invitee; + } + + $invitee + ->setStatus($value) + ->save(); + + $object->attachInvitees($invitees); + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventStartDateTransaction.php b/src/applications/calendar/xaction/PhabricatorCalendarEventStartDateTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventStartDateTransaction.php @@ -0,0 +1,37 @@ +getDateFrom(); + } + + public function applyInternalEffects($object, $value) { + $object->setDateFrom($value); + } + + public function getTitle() { + return pht( + '%s changed the start date for this event from %s to %s.', + $this->renderAuthor(), + $this->renderOldDate(), + $this->renderNewDate()); + } + + public function getTitleForFeed() { + return pht( + '%s changed the start date for %s from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldDate(), + $this->renderNewDate()); + } + + protected function getInvalidDateMessage() { + return pht('Start date is invalid.'); + } + +} diff --git a/src/applications/calendar/xaction/PhabricatorCalendarEventTransactionType.php b/src/applications/calendar/xaction/PhabricatorCalendarEventTransactionType.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/xaction/PhabricatorCalendarEventTransactionType.php @@ -0,0 +1,4 @@ +getRecurrenceEndDate(); + } + + public function applyInternalEffects($object, $value) { + $object->setRecurrenceEndDate($value); + } + + public function getTitle() { + return pht( + '%s changed this event to repeat until %s.', + $this->renderAuthor(), + $this->renderNewDate()); + } + + public function getTitleForFeed() { + return pht( + '%s changed %s to repeat until %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderNewDate()); + } + + protected function getInvalidDateMessage() { + return pht('Repeat until date is invalid.'); + } + +} diff --git a/src/applications/phid/view/PHUIHandleListView.php b/src/applications/phid/view/PHUIHandleListView.php --- a/src/applications/phid/view/PHUIHandleListView.php +++ b/src/applications/phid/view/PHUIHandleListView.php @@ -12,6 +12,7 @@ private $handleList; private $asInline; + private $asText; public function setHandleList(PhabricatorHandleList $list) { $this->handleList = $list; @@ -27,6 +28,15 @@ return $this->asInline; } + public function setAsText($as_text) { + $this->asText = $as_text; + return $this; + } + + public function getAsText() { + return $this->asText; + } + protected function getTagName() { // TODO: It would be nice to render this with a proper