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 @@ -1498,6 +1498,7 @@ 'PhabricatorCalendarEventCommentController' => 'applications/calendar/controller/PhabricatorCalendarEventCommentController.php', 'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php', 'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php', + 'PhabricatorCalendarEventEmailCommand' => 'applications/calendar/command/PhabricatorCalendarEventEmailCommand.php', 'PhabricatorCalendarEventInvalidEpochException' => 'applications/calendar/exception/PhabricatorCalendarEventInvalidEpochException.php', 'PhabricatorCalendarEventInvitee' => 'applications/calendar/storage/PhabricatorCalendarEventInvitee.php', 'PhabricatorCalendarEventInviteeQuery' => 'applications/calendar/query/PhabricatorCalendarEventInviteeQuery.php', @@ -1506,6 +1507,7 @@ 'PhabricatorCalendarEventMailReceiver' => 'applications/calendar/mail/PhabricatorCalendarEventMailReceiver.php', 'PhabricatorCalendarEventPHIDType' => 'applications/calendar/phid/PhabricatorCalendarEventPHIDType.php', 'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php', + 'PhabricatorCalendarEventRSVPEmailCommand' => 'applications/calendar/command/PhabricatorCalendarEventRSVPEmailCommand.php', 'PhabricatorCalendarEventSearchEngine' => 'applications/calendar/query/PhabricatorCalendarEventSearchEngine.php', 'PhabricatorCalendarEventSearchIndexer' => 'applications/calendar/search/PhabricatorCalendarEventSearchIndexer.php', 'PhabricatorCalendarEventTransaction' => 'applications/calendar/storage/PhabricatorCalendarEventTransaction.php', @@ -4848,6 +4850,7 @@ 'PhabricatorCalendarEventCommentController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhabricatorCalendarEventEmailCommand' => 'MetaMTAEmailTransactionCommand', 'PhabricatorCalendarEventInvalidEpochException' => 'Exception', 'PhabricatorCalendarEventInvitee' => array( 'PhabricatorCalendarDAO', @@ -4859,6 +4862,7 @@ 'PhabricatorCalendarEventMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorCalendarEventPHIDType' => 'PhabricatorPHIDType', 'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorCalendarEventRSVPEmailCommand' => 'PhabricatorCalendarEventEmailCommand', 'PhabricatorCalendarEventSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorCalendarEventSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PhabricatorCalendarEventTransaction' => 'PhabricatorApplicationTransaction', diff --git a/src/applications/calendar/command/PhabricatorCalendarEventEmailCommand.php b/src/applications/calendar/command/PhabricatorCalendarEventEmailCommand.php new file mode 100644 --- /dev/null +++ b/src/applications/calendar/command/PhabricatorCalendarEventEmailCommand.php @@ -0,0 +1,11 @@ +getYesValues()); + $no_values = implode(', ', $this->getNoValues()); + + $table = array(); + $table[] = '| '.pht('RSVP').' | '.pht('Keywords'); + $table[] = '|---|---|'; + $table[] = '| '.$status_attending.' | '.$yes_values; + $table[] = '| '.$status_declined.' | '.$no_values; + $table = implode("\n", $table); + + return pht( + 'To RSVP to the event, specify the desired RSVP, like '. + '`!rsvp yes`. This table shows the configured names for rsvp\'s.'. + "\n\n%s\n\n". + 'If you specify an invalid rsvp, the command is ignored. This '. + 'command has no effect if you do not specify an rsvp.', + $table); + } + + public function buildTransactions( + PhabricatorUser $viewer, + PhabricatorApplicationTransactionInterface $object, + 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; + } else if (in_array($target, $no_values)) { + $rsvp = $status_declined; + } else { + $rsvp = null; + } + + if ($rsvp === null) { + return array(); + } + + $xactions[] = $object->getApplicationTransactionTemplate() + ->setTransactionType(PhabricatorCalendarEventTransaction::TYPE_INVITE) + ->setNewValue(array($viewer->getPHID() => $rsvp)); + + return $xactions; + } + + private function getYesValues() { + return array( + 'yes', + 'yep', + 'sounds good', + 'going', + 'attending', + 'will be there', + 'sure', + 'accept', + 'ya', + 'yeah', + 'yuh', + 'uhuh', + 'ok', + 'okay', + 'yiss', + 'aww yiss', + 'attend', + 'intend to attend', + 'confirm', + 'confirmed', + 'bringing dessert', + 'bringing desert', + 'time2business', + 'time4business', + ); + } + + private function getNoValues() { + return array( + 'no', + 'nope', + 'no thank you', + 'next time', + 'nah', + 'nuh', + 'huh', + 'wut', + 'no way', + 'nuhuh', + 'decline', + 'declined', + 'leave', + 'cancel', + ); + } + +} 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 @@ -147,16 +147,8 @@ case PhabricatorCalendarEventTransaction::TYPE_INVITE: $map = $xaction->getNewValue(); $phids = array_keys($map); - $invitees = array(); - - if ($map) { - $invitees = id(new PhabricatorCalendarEventInviteeQuery()) - ->setViewer($this->getActor()) - ->withEventPHIDs(array($object->getPHID())) - ->withInviteePHIDs($phids) - ->execute(); - $invitees = mpull($invitees, null, 'getInviteePHID'); - } + $invitees = $object->getInvitees(); + $invitees = mpull($invitees, null, 'getInviteePHID'); foreach ($phids as $phid) { $invitee = idx($invitees, $phid); @@ -165,10 +157,12 @@ ->setEventPHID($object->getPHID()) ->setInviteePHID($phid) ->setInviterPHID($this->getActingAsPHID()); + $invitees[] = $invitee; } $invitee->setStatus($map[$phid]) ->save(); } + $object->attachInvitees($invitees); return; case PhabricatorTransactions::TYPE_COMMENT: case PhabricatorTransactions::TYPE_VIEW_POLICY: @@ -254,14 +248,16 @@ $phids[] = $this->getActingAsPHID(); $invitees = $object->getInvitees(); - foreach ($invitees as $phid => $status) { + foreach ($invitees as $invitee) { + $status = $invitee->getStatus(); if ($status === PhabricatorCalendarEventInvitee::STATUS_ATTENDING || $status === PhabricatorCalendarEventInvitee::STATUS_INVITED) { - $phids[] = $phid; + $phids[] = $invitee->getInviteePHID(); } } $phids = array_unique($phids); + return $phids; } diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php --- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php +++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php @@ -42,7 +42,7 @@ } public function save() { - if ($this->getDateTo() <= $this->getDateFrom()) { + if ($this->getDateTo() < $this->getDateFrom()) { throw new PhabricatorCalendarEventInvalidEpochException(); } 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 @@ -11,7 +11,6 @@ const TYPE_CANCEL = 'calendar.cancel'; const TYPE_INVITE = 'calendar.invite'; - const MAILTAG_RESCHEDULE = 'calendar-reschedule'; const MAILTAG_CONTENT = 'calendar-content'; const MAILTAG_OTHER = 'calendar-other';