mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-18 19:40:55 +01:00
Calendar event transaction emails without reply handling
Summary: Ref T7957, Calendar event transaction emails without reply handling. Test Plan: Create event, invitees should get email. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: Korvin, epriestley Maniphest Tasks: T7957 Differential Revision: https://secure.phabricator.com/D12645
This commit is contained in:
parent
59416a13e7
commit
aa68cc8830
9 changed files with 187 additions and 31 deletions
2
resources/sql/autopatches/20150501.calendar.1.reply.sql
Normal file
2
resources/sql/autopatches/20150501.calendar.1.reply.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_calendar.calendar_event
|
||||
ADD mailKey binary(20) NOT NULL;
|
21
resources/sql/autopatches/20150501.calendar.2.reply.php
Normal file
21
resources/sql/autopatches/20150501.calendar.2.reply.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
echo "Adding mailkeys to events.\n";
|
||||
|
||||
$table = new PhabricatorCalendarEvent();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
$iterator = new LiskMigrationIterator($table);
|
||||
foreach ($iterator as $event) {
|
||||
$id = $event->getID();
|
||||
|
||||
echo "Populating event {$id}...\n";
|
||||
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'UPDATE %T SET mailKey = %s WHERE id = %d',
|
||||
$table->getTableName(),
|
||||
Filesystem::readRandomCharacters(20),
|
||||
$id);
|
||||
}
|
||||
|
||||
echo "Done.\n";
|
|
@ -1502,6 +1502,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCalendarEventInviteeQuery' => 'applications/calendar/query/PhabricatorCalendarEventInviteeQuery.php',
|
||||
'PhabricatorCalendarEventJoinController' => 'applications/calendar/controller/PhabricatorCalendarEventJoinController.php',
|
||||
'PhabricatorCalendarEventListController' => 'applications/calendar/controller/PhabricatorCalendarEventListController.php',
|
||||
'PhabricatorCalendarEventMailReceiver' => 'applications/calendar/mail/PhabricatorCalendarEventMailReceiver.php',
|
||||
'PhabricatorCalendarEventPHIDType' => 'applications/calendar/phid/PhabricatorCalendarEventPHIDType.php',
|
||||
'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php',
|
||||
'PhabricatorCalendarEventSearchEngine' => 'applications/calendar/query/PhabricatorCalendarEventSearchEngine.php',
|
||||
|
@ -1513,6 +1514,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCalendarHoliday' => 'applications/calendar/storage/PhabricatorCalendarHoliday.php',
|
||||
'PhabricatorCalendarHolidayTestCase' => 'applications/calendar/storage/__tests__/PhabricatorCalendarHolidayTestCase.php',
|
||||
'PhabricatorCalendarRemarkupRule' => 'applications/calendar/remarkup/PhabricatorCalendarRemarkupRule.php',
|
||||
'PhabricatorCalendarReplyHandler' => 'applications/calendar/mail/PhabricatorCalendarReplyHandler.php',
|
||||
'PhabricatorCalendarSchemaSpec' => 'applications/calendar/storage/PhabricatorCalendarSchemaSpec.php',
|
||||
'PhabricatorCalendarViewController' => 'applications/calendar/controller/PhabricatorCalendarViewController.php',
|
||||
'PhabricatorCampfireProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php',
|
||||
|
@ -4852,6 +4854,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCalendarEventInviteeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorCalendarEventJoinController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventListController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventMailReceiver' => 'PhabricatorObjectMailReceiver',
|
||||
'PhabricatorCalendarEventPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorCalendarEventSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
|
@ -4863,6 +4866,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO',
|
||||
'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorCalendarRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
||||
'PhabricatorCalendarReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
|
||||
'PhabricatorCalendarSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||
'PhabricatorCalendarViewController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCampfireProtocolAdapter' => 'PhabricatorBotBaseStreamingProtocolAdapter',
|
||||
|
|
|
@ -74,4 +74,18 @@ final class PhabricatorCalendarApplication extends PhabricatorApplication {
|
|||
return $items;
|
||||
}
|
||||
|
||||
public function getMailCommandObjects() {
|
||||
return array(
|
||||
'event' => array(
|
||||
'name' => pht('Email Commands: Events'),
|
||||
'header' => pht('Interacting with Calendar Events'),
|
||||
'object' => new PhabricatorCalendarEvent(),
|
||||
'summary' => pht(
|
||||
'This page documents the commands you can use to interact with '.
|
||||
'events in Calendar. These commands work when creating new tasks '.
|
||||
'via email and when replying to existing tasks.'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -209,10 +209,6 @@ final class PhabricatorCalendarEventEditor
|
|||
return $errors;
|
||||
}
|
||||
|
||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||
return array($object->getUserPHID());
|
||||
}
|
||||
|
||||
protected function shouldPublishFeedStory(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
@ -222,4 +218,88 @@ final class PhabricatorCalendarEventEditor
|
|||
protected function supportsSearch() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function shouldSendMail(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
$xactions = mfilter($xactions, 'shouldHide', true);
|
||||
return $xactions;
|
||||
}
|
||||
|
||||
protected function getMailSubjectPrefix() {
|
||||
return pht('[Calendar]');
|
||||
}
|
||||
|
||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||
$phids = array();
|
||||
|
||||
if ($object->getUserPHID()) {
|
||||
$phids[] = $object->getUserPHID();
|
||||
}
|
||||
$phids[] = $this->getActingAsPHID();
|
||||
|
||||
$invitees = $object->getInvitees();
|
||||
foreach ($invitees as $phid => $status) {
|
||||
if ($status === PhabricatorCalendarEventInvitee::STATUS_ATTENDING
|
||||
|| $status === PhabricatorCalendarEventInvitee::STATUS_INVITED) {
|
||||
$phids[] = $phid;
|
||||
}
|
||||
}
|
||||
|
||||
$phids = array_unique($phids);
|
||||
return $phids;
|
||||
}
|
||||
|
||||
public function getMailTagsMap() {
|
||||
return array(
|
||||
PhabricatorCalendarEventTransaction::MAILTAG_CONTENT =>
|
||||
pht(
|
||||
"An event's name, status, invite list, ".
|
||||
"and description changes."),
|
||||
PhabricatorCalendarEventTransaction::MAILTAG_RESCHEDULE =>
|
||||
pht(
|
||||
"An event's start and end date ".
|
||||
"and cancellation status changes."),
|
||||
PhabricatorCalendarEventTransaction::MAILTAG_OTHER =>
|
||||
pht('Other event activity not listed above occurs.'),
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
|
||||
return id(new PhabricatorCalendarReplyHandler())
|
||||
->setMailReceiver($object);
|
||||
}
|
||||
|
||||
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||
$id = $object->getID();
|
||||
$name = $object->getName();
|
||||
|
||||
return id(new PhabricatorMetaMTAMail())
|
||||
->setSubject("E{$id}: {$name}")
|
||||
->addHeader('Thread-Topic', "E{$id}: ".$object->getName());
|
||||
}
|
||||
|
||||
protected function buildMailBody(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
$description = $object->getDescription();
|
||||
$body = parent::buildMailBody($object, $xactions);
|
||||
|
||||
if (strlen($description)) {
|
||||
$body->addTextSection(
|
||||
pht('EVENT DESCRIPTION'),
|
||||
$object->getDescription());
|
||||
}
|
||||
|
||||
$body->addLinkSection(
|
||||
pht('EVENT DETAIL'),
|
||||
PhabricatorEnv::getProductionURI('/E'.$object->getID()));
|
||||
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCalendarEventMailReceiver
|
||||
extends PhabricatorObjectMailReceiver {
|
||||
|
||||
public function isEnabled() {
|
||||
$app_class = 'PhabricatorCalendarApplication';
|
||||
return PhabricatorApplication::isClassInstalled($app_class);
|
||||
}
|
||||
|
||||
protected function getObjectPattern() {
|
||||
return 'E[1-9]\d*';
|
||||
}
|
||||
|
||||
protected function loadObject($pattern, PhabricatorUser $viewer) {
|
||||
$id = (int)trim($pattern, 'E');
|
||||
|
||||
return id(new PhabricatorCalendarEventQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->executeOne();
|
||||
}
|
||||
|
||||
protected function getTransactionReplyHandler() {
|
||||
return new PhabricatorCalendarReplyHandler();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCalendarReplyHandler
|
||||
extends PhabricatorApplicationTransactionReplyHandler {
|
||||
|
||||
public function validateMailReceiver($mail_receiver) {
|
||||
if (!($mail_receiver instanceof PhabricatorCalendarEvent)) {
|
||||
throw new Exception('Mail receiver is not a PhabricatorCalendarEvent!');
|
||||
}
|
||||
}
|
||||
|
||||
public function getObjectPrefix() {
|
||||
return 'E';
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
protected $status;
|
||||
protected $description;
|
||||
protected $isCancelled;
|
||||
protected $mailKey;
|
||||
|
||||
protected $viewPolicy;
|
||||
protected $editPolicy;
|
||||
|
@ -40,6 +41,17 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
->attachInvitees(array());
|
||||
}
|
||||
|
||||
public function save() {
|
||||
if ($this->getDateTo() <= $this->getDateFrom()) {
|
||||
throw new PhabricatorCalendarEventInvalidEpochException();
|
||||
}
|
||||
|
||||
if (!$this->mailKey) {
|
||||
$this->mailKey = Filesystem::readRandomCharacters(20);
|
||||
}
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
private static $statusTexts = array(
|
||||
self::STATUS_AWAY => 'away',
|
||||
self::STATUS_SPORADIC => 'sporadic',
|
||||
|
@ -76,6 +88,7 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
'status' => 'uint32',
|
||||
'description' => 'text',
|
||||
'isCancelled' => 'bool',
|
||||
'mailKey' => 'bytes20',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'userPHID_dateFrom' => array(
|
||||
|
@ -156,19 +169,6 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
return $is_attending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates data and throws exceptions for non-sensical status
|
||||
* windows
|
||||
*/
|
||||
public function save() {
|
||||
|
||||
if ($this->getDateTo() <= $this->getDateFrom()) {
|
||||
throw new PhabricatorCalendarEventInvalidEpochException();
|
||||
}
|
||||
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
/* -( Markup Interface )--------------------------------------------------- */
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ 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';
|
||||
|
||||
|
@ -442,25 +444,15 @@ final class PhabricatorCalendarEventTransaction
|
|||
$tags = array();
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_NAME:
|
||||
case self::TYPE_STATUS:
|
||||
case self::TYPE_DESCRIPTION:
|
||||
case self::TYPE_INVITE:
|
||||
$tags[] = self::MAILTAG_CONTENT;
|
||||
break;
|
||||
case self::TYPE_START_DATE:
|
||||
$tags[] = self::MAILTAG_CONTENT;
|
||||
break;
|
||||
case self::TYPE_END_DATE:
|
||||
$tags[] = self::MAILTAG_CONTENT;
|
||||
break;
|
||||
case self::TYPE_STATUS:
|
||||
$tags[] = self::MAILTAG_OTHER;
|
||||
break;
|
||||
case self::TYPE_DESCRIPTION:
|
||||
$tags[] = self::MAILTAG_CONTENT;
|
||||
break;
|
||||
case self::TYPE_CANCEL:
|
||||
$tags[] = self::MAILTAG_CONTENT;
|
||||
break;
|
||||
case self::TYPE_INVITE:
|
||||
$tags[] = self::MAILTAG_CONTENT;
|
||||
$tags[] = self::MAILTAG_RESCHEDULE;
|
||||
break;
|
||||
}
|
||||
return $tags;
|
||||
|
|
Loading…
Reference in a new issue