mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-04 20:01:00 +01: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:
parent
7aac1effac
commit
46a1b816ed
6 changed files with 148 additions and 14 deletions
|
@ -1498,6 +1498,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarEventCommentController' => 'applications/calendar/controller/PhabricatorCalendarEventCommentController.php',
|
'PhabricatorCalendarEventCommentController' => 'applications/calendar/controller/PhabricatorCalendarEventCommentController.php',
|
||||||
'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php',
|
'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php',
|
||||||
'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php',
|
'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php',
|
||||||
|
'PhabricatorCalendarEventEmailCommand' => 'applications/calendar/command/PhabricatorCalendarEventEmailCommand.php',
|
||||||
'PhabricatorCalendarEventInvalidEpochException' => 'applications/calendar/exception/PhabricatorCalendarEventInvalidEpochException.php',
|
'PhabricatorCalendarEventInvalidEpochException' => 'applications/calendar/exception/PhabricatorCalendarEventInvalidEpochException.php',
|
||||||
'PhabricatorCalendarEventInvitee' => 'applications/calendar/storage/PhabricatorCalendarEventInvitee.php',
|
'PhabricatorCalendarEventInvitee' => 'applications/calendar/storage/PhabricatorCalendarEventInvitee.php',
|
||||||
'PhabricatorCalendarEventInviteeQuery' => 'applications/calendar/query/PhabricatorCalendarEventInviteeQuery.php',
|
'PhabricatorCalendarEventInviteeQuery' => 'applications/calendar/query/PhabricatorCalendarEventInviteeQuery.php',
|
||||||
|
@ -1506,6 +1507,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarEventMailReceiver' => 'applications/calendar/mail/PhabricatorCalendarEventMailReceiver.php',
|
'PhabricatorCalendarEventMailReceiver' => 'applications/calendar/mail/PhabricatorCalendarEventMailReceiver.php',
|
||||||
'PhabricatorCalendarEventPHIDType' => 'applications/calendar/phid/PhabricatorCalendarEventPHIDType.php',
|
'PhabricatorCalendarEventPHIDType' => 'applications/calendar/phid/PhabricatorCalendarEventPHIDType.php',
|
||||||
'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php',
|
'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php',
|
||||||
|
'PhabricatorCalendarEventRSVPEmailCommand' => 'applications/calendar/command/PhabricatorCalendarEventRSVPEmailCommand.php',
|
||||||
'PhabricatorCalendarEventSearchEngine' => 'applications/calendar/query/PhabricatorCalendarEventSearchEngine.php',
|
'PhabricatorCalendarEventSearchEngine' => 'applications/calendar/query/PhabricatorCalendarEventSearchEngine.php',
|
||||||
'PhabricatorCalendarEventSearchIndexer' => 'applications/calendar/search/PhabricatorCalendarEventSearchIndexer.php',
|
'PhabricatorCalendarEventSearchIndexer' => 'applications/calendar/search/PhabricatorCalendarEventSearchIndexer.php',
|
||||||
'PhabricatorCalendarEventTransaction' => 'applications/calendar/storage/PhabricatorCalendarEventTransaction.php',
|
'PhabricatorCalendarEventTransaction' => 'applications/calendar/storage/PhabricatorCalendarEventTransaction.php',
|
||||||
|
@ -4848,6 +4850,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarEventCommentController' => 'PhabricatorCalendarController',
|
'PhabricatorCalendarEventCommentController' => 'PhabricatorCalendarController',
|
||||||
'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController',
|
'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController',
|
||||||
'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor',
|
'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
|
'PhabricatorCalendarEventEmailCommand' => 'MetaMTAEmailTransactionCommand',
|
||||||
'PhabricatorCalendarEventInvalidEpochException' => 'Exception',
|
'PhabricatorCalendarEventInvalidEpochException' => 'Exception',
|
||||||
'PhabricatorCalendarEventInvitee' => array(
|
'PhabricatorCalendarEventInvitee' => array(
|
||||||
'PhabricatorCalendarDAO',
|
'PhabricatorCalendarDAO',
|
||||||
|
@ -4859,6 +4862,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCalendarEventMailReceiver' => 'PhabricatorObjectMailReceiver',
|
'PhabricatorCalendarEventMailReceiver' => 'PhabricatorObjectMailReceiver',
|
||||||
'PhabricatorCalendarEventPHIDType' => 'PhabricatorPHIDType',
|
'PhabricatorCalendarEventPHIDType' => 'PhabricatorPHIDType',
|
||||||
'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'PhabricatorCalendarEventRSVPEmailCommand' => 'PhabricatorCalendarEventEmailCommand',
|
||||||
'PhabricatorCalendarEventSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhabricatorCalendarEventSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
'PhabricatorCalendarEventSearchIndexer' => 'PhabricatorSearchDocumentIndexer',
|
'PhabricatorCalendarEventSearchIndexer' => 'PhabricatorSearchDocumentIndexer',
|
||||||
'PhabricatorCalendarEventTransaction' => 'PhabricatorApplicationTransaction',
|
'PhabricatorCalendarEventTransaction' => 'PhabricatorApplicationTransaction',
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorCalendarEventEmailCommand
|
||||||
|
extends MetaMTAEmailTransactionCommand {
|
||||||
|
|
||||||
|
public function isCommandSupportedForObject(
|
||||||
|
PhabricatorApplicationTransactionInterface $object) {
|
||||||
|
return ($object instanceof PhabricatorCalendarEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -147,16 +147,8 @@ final class PhabricatorCalendarEventEditor
|
||||||
case PhabricatorCalendarEventTransaction::TYPE_INVITE:
|
case PhabricatorCalendarEventTransaction::TYPE_INVITE:
|
||||||
$map = $xaction->getNewValue();
|
$map = $xaction->getNewValue();
|
||||||
$phids = array_keys($map);
|
$phids = array_keys($map);
|
||||||
$invitees = array();
|
$invitees = $object->getInvitees();
|
||||||
|
$invitees = mpull($invitees, null, 'getInviteePHID');
|
||||||
if ($map) {
|
|
||||||
$invitees = id(new PhabricatorCalendarEventInviteeQuery())
|
|
||||||
->setViewer($this->getActor())
|
|
||||||
->withEventPHIDs(array($object->getPHID()))
|
|
||||||
->withInviteePHIDs($phids)
|
|
||||||
->execute();
|
|
||||||
$invitees = mpull($invitees, null, 'getInviteePHID');
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($phids as $phid) {
|
foreach ($phids as $phid) {
|
||||||
$invitee = idx($invitees, $phid);
|
$invitee = idx($invitees, $phid);
|
||||||
|
@ -165,10 +157,12 @@ final class PhabricatorCalendarEventEditor
|
||||||
->setEventPHID($object->getPHID())
|
->setEventPHID($object->getPHID())
|
||||||
->setInviteePHID($phid)
|
->setInviteePHID($phid)
|
||||||
->setInviterPHID($this->getActingAsPHID());
|
->setInviterPHID($this->getActingAsPHID());
|
||||||
|
$invitees[] = $invitee;
|
||||||
}
|
}
|
||||||
$invitee->setStatus($map[$phid])
|
$invitee->setStatus($map[$phid])
|
||||||
->save();
|
->save();
|
||||||
}
|
}
|
||||||
|
$object->attachInvitees($invitees);
|
||||||
return;
|
return;
|
||||||
case PhabricatorTransactions::TYPE_COMMENT:
|
case PhabricatorTransactions::TYPE_COMMENT:
|
||||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||||
|
@ -254,14 +248,16 @@ final class PhabricatorCalendarEventEditor
|
||||||
$phids[] = $this->getActingAsPHID();
|
$phids[] = $this->getActingAsPHID();
|
||||||
|
|
||||||
$invitees = $object->getInvitees();
|
$invitees = $object->getInvitees();
|
||||||
foreach ($invitees as $phid => $status) {
|
foreach ($invitees as $invitee) {
|
||||||
|
$status = $invitee->getStatus();
|
||||||
if ($status === PhabricatorCalendarEventInvitee::STATUS_ATTENDING
|
if ($status === PhabricatorCalendarEventInvitee::STATUS_ATTENDING
|
||||||
|| $status === PhabricatorCalendarEventInvitee::STATUS_INVITED) {
|
|| $status === PhabricatorCalendarEventInvitee::STATUS_INVITED) {
|
||||||
$phids[] = $phid;
|
$phids[] = $invitee->getInviteePHID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$phids = array_unique($phids);
|
$phids = array_unique($phids);
|
||||||
|
|
||||||
return $phids;
|
return $phids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save() {
|
public function save() {
|
||||||
if ($this->getDateTo() <= $this->getDateFrom()) {
|
if ($this->getDateTo() < $this->getDateFrom()) {
|
||||||
throw new PhabricatorCalendarEventInvalidEpochException();
|
throw new PhabricatorCalendarEventInvalidEpochException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ final class PhabricatorCalendarEventTransaction
|
||||||
const TYPE_CANCEL = 'calendar.cancel';
|
const TYPE_CANCEL = 'calendar.cancel';
|
||||||
const TYPE_INVITE = 'calendar.invite';
|
const TYPE_INVITE = 'calendar.invite';
|
||||||
|
|
||||||
|
|
||||||
const MAILTAG_RESCHEDULE = 'calendar-reschedule';
|
const MAILTAG_RESCHEDULE = 'calendar-reschedule';
|
||||||
const MAILTAG_CONTENT = 'calendar-content';
|
const MAILTAG_CONTENT = 'calendar-content';
|
||||||
const MAILTAG_OTHER = 'calendar-other';
|
const MAILTAG_OTHER = 'calendar-other';
|
||||||
|
|
Loading…
Reference in a new issue