1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-09-20 09:18:48 +02:00

Users should be able to rsvp to event via email

Summary: Closes T7957, Users should be able to rsvp to event via email.

Test Plan: Create event, open invitee email, reply to email w/ !rsvp yes, refresh event, invitee should show as attending.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: Korvin, epriestley

Maniphest Tasks: T7957

Differential Revision: https://secure.phabricator.com/D12651
This commit is contained in:
lkassianik 2015-05-01 19:01:29 -07:00
parent 7aac1effac
commit 46a1b816ed
6 changed files with 148 additions and 14 deletions

View file

@ -1498,6 +1498,7 @@ phutil_register_library_map(array(
'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 @@ phutil_register_library_map(array(
'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 @@ phutil_register_library_map(array(
'PhabricatorCalendarEventCommentController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorCalendarEventEmailCommand' => 'MetaMTAEmailTransactionCommand',
'PhabricatorCalendarEventInvalidEpochException' => 'Exception',
'PhabricatorCalendarEventInvitee' => array(
'PhabricatorCalendarDAO',
@ -4859,6 +4862,7 @@ phutil_register_library_map(array(
'PhabricatorCalendarEventMailReceiver' => 'PhabricatorObjectMailReceiver',
'PhabricatorCalendarEventPHIDType' => 'PhabricatorPHIDType',
'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorCalendarEventRSVPEmailCommand' => 'PhabricatorCalendarEventEmailCommand',
'PhabricatorCalendarEventSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorCalendarEventSearchIndexer' => 'PhabricatorSearchDocumentIndexer',
'PhabricatorCalendarEventTransaction' => 'PhabricatorApplicationTransaction',

View file

@ -0,0 +1,11 @@
<?php
abstract class PhabricatorCalendarEventEmailCommand
extends MetaMTAEmailTransactionCommand {
public function isCommandSupportedForObject(
PhabricatorApplicationTransactionInterface $object) {
return ($object instanceof PhabricatorCalendarEvent);
}
}

View file

@ -0,0 +1,124 @@
<?php
final class PhabricatorCalendarEventRSVPEmailCommand
extends PhabricatorCalendarEventEmailCommand {
public function getCommand() {
return 'rsvp';
}
public function getCommandSyntax() {
return '**!rsvp** //rsvp//';
}
public function getCommandSummary() {
return pht('RSVP to event.');
}
public function getCommandDescription() {
$status_attending = PhabricatorCalendarEventInvitee::STATUS_ATTENDING;
$status_declined = PhabricatorCalendarEventInvitee::STATUS_DECLINED;
$yes_values = implode(', ', $this->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',
);
}
}

View file

@ -147,16 +147,8 @@ final class PhabricatorCalendarEventEditor
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 @@ final class PhabricatorCalendarEventEditor
->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 @@ final class PhabricatorCalendarEventEditor
$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;
}

View file

@ -42,7 +42,7 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
}
public function save() {
if ($this->getDateTo() <= $this->getDateFrom()) {
if ($this->getDateTo() < $this->getDateFrom()) {
throw new PhabricatorCalendarEventInvalidEpochException();
}

View file

@ -11,7 +11,6 @@ final class PhabricatorCalendarEventTransaction
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';