mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-18 19:40:55 +01:00
Calendar events should now auto-invite the creator
Summary: Closes T7935, Calendar events should now auto-invite the creator. Test Plan: Create event, save, event should now show creator as an invitee. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: Korvin, epriestley Maniphest Tasks: T7935 Differential Revision: https://secure.phabricator.com/D12613
This commit is contained in:
parent
f3a2d2b020
commit
d4176606f9
10 changed files with 314 additions and 2 deletions
11
resources/sql/autopatches/20150429.calendar.1.invitee.sql
Normal file
11
resources/sql/autopatches/20150429.calendar.1.invitee.sql
Normal file
|
@ -0,0 +1,11 @@
|
|||
CREATE TABLE {$NAMESPACE}_calendar.`calendar_eventinvitee` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`eventPHID` varbinary(64) NOT NULL,
|
||||
`inviteePHID` varbinary(64) NOT NULL,
|
||||
`inviterPHID` varbinary(64) NOT NULL,
|
||||
`status` VARCHAR(64) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||
`dateCreated` int(10) unsigned NOT NULL,
|
||||
`dateModified` int(10) unsigned NOT NULL,
|
||||
UNIQUE KEY `key_event` (`eventPHID`, `inviteePHID`),
|
||||
KEY `key_invitee` (`inviteePHID`)
|
||||
) ENGINE=InnoDB COLLATE {$COLLATE_TEXT};
|
|
@ -1486,6 +1486,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php',
|
||||
'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php',
|
||||
'PhabricatorCalendarEventInvalidEpochException' => 'applications/calendar/exception/PhabricatorCalendarEventInvalidEpochException.php',
|
||||
'PhabricatorCalendarEventInvitee' => 'applications/calendar/storage/PhabricatorCalendarEventInvitee.php',
|
||||
'PhabricatorCalendarEventInviteeQuery' => 'applications/calendar/query/PhabricatorCalendarEventInviteeQuery.php',
|
||||
'PhabricatorCalendarEventListController' => 'applications/calendar/controller/PhabricatorCalendarEventListController.php',
|
||||
'PhabricatorCalendarEventPHIDType' => 'applications/calendar/phid/PhabricatorCalendarEventPHIDType.php',
|
||||
'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php',
|
||||
|
@ -4817,6 +4819,11 @@ phutil_register_library_map(array(
|
|||
'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorCalendarEventInvalidEpochException' => 'Exception',
|
||||
'PhabricatorCalendarEventInvitee' => array(
|
||||
'PhabricatorCalendarDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhabricatorCalendarEventInviteeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorCalendarEventListController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarEventPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
|
|
|
@ -16,8 +16,10 @@ final class PhabricatorCalendarEventEditController
|
|||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$user_phid = $user->getPHID();
|
||||
$error_name = true;
|
||||
$validation_exception = null;
|
||||
$invitees = null;
|
||||
|
||||
$start_time = id(new AphrontFormDateControl())
|
||||
->setUser($user)
|
||||
|
@ -40,6 +42,9 @@ final class PhabricatorCalendarEventEditController
|
|||
$page_title = pht('Create Event');
|
||||
$redirect = 'created';
|
||||
$subscribers = array();
|
||||
$invitees = array(
|
||||
$user_phid => PhabricatorCalendarEventInvitee::STATUS_ATTENDING,
|
||||
);
|
||||
} else {
|
||||
$event = id(new PhabricatorCalendarEventQuery())
|
||||
->setViewer($user)
|
||||
|
@ -112,6 +117,14 @@ final class PhabricatorCalendarEventEditController
|
|||
PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION)
|
||||
->setNewValue($description);
|
||||
|
||||
if ($invitees) {
|
||||
$xactions[] = id(new PhabricatorCalendarEventTransaction())
|
||||
->setTransactionType(
|
||||
PhabricatorCalendarEventTransaction::TYPE_INVITE)
|
||||
->setNewValue($invitees);
|
||||
}
|
||||
|
||||
|
||||
$editor = id(new PhabricatorCalendarEventEditor())
|
||||
->setActor($user)
|
||||
->setContentSourceFromRequest($request)
|
||||
|
@ -160,7 +173,6 @@ final class PhabricatorCalendarEventEditController
|
|||
->setUser($user)
|
||||
->setDatasource(new PhabricatorMetaMTAMailableDatasource());
|
||||
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->appendChild($name)
|
||||
|
|
|
@ -127,6 +127,20 @@ final class PhabricatorCalendarEventViewController
|
|||
pht('Ends'),
|
||||
phabricator_datetime($event->getDateTo(), $viewer));
|
||||
|
||||
$invitees = $event->getInvitees();
|
||||
$invitee_list = new PHUIStatusListView();
|
||||
foreach ($invitees as $invitee) {
|
||||
$item = new PHUIStatusItemView();
|
||||
$invitee_phid = $invitee->getInviteePHID();
|
||||
$target = $viewer->renderHandle($invitee_phid);
|
||||
$item->setTarget($target);
|
||||
$invitee_list->addItem($item);
|
||||
}
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Invitees'),
|
||||
$invitee_list);
|
||||
|
||||
$properties->invokeWillRenderEvent();
|
||||
|
||||
$properties->addSectionHeader(
|
||||
|
|
|
@ -20,6 +20,7 @@ final class PhabricatorCalendarEventEditor
|
|||
$types[] = PhabricatorCalendarEventTransaction::TYPE_STATUS;
|
||||
$types[] = PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION;
|
||||
$types[] = PhabricatorCalendarEventTransaction::TYPE_CANCEL;
|
||||
$types[] = PhabricatorCalendarEventTransaction::TYPE_INVITE;
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||
|
@ -47,6 +48,30 @@ final class PhabricatorCalendarEventEditor
|
|||
return $object->getDescription();
|
||||
case PhabricatorCalendarEventTransaction::TYPE_CANCEL:
|
||||
return $object->getIsCancelled();
|
||||
case PhabricatorCalendarEventTransaction::TYPE_INVITE:
|
||||
$map = $xaction->getNewValue();
|
||||
$phids = array_keys($map);
|
||||
$invitees = array();
|
||||
|
||||
if ($map && !$this->getIsNewObject()) {
|
||||
$invitees = id(new PhabricatorCalendarEventInviteeQuery())
|
||||
->setViewer($this->getActor())
|
||||
->withEventPHIDs(array($object->getPHID()))
|
||||
->withInviteePHIDs($phids)
|
||||
->execute();
|
||||
$invitees = mpull($invitees, null, 'getInviteePHID');
|
||||
}
|
||||
|
||||
$old = array();
|
||||
foreach ($phids as $phid) {
|
||||
$invitee = idx($invitees, $phid);
|
||||
if ($invitee) {
|
||||
$old[$phid] = $invitee->getStatus();
|
||||
} else {
|
||||
$old[$phid] = PhabricatorCalendarEventInvitee::STATUS_UNINVITED;
|
||||
}
|
||||
}
|
||||
return $old;
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionOldValue($object, $xaction);
|
||||
|
@ -55,13 +80,13 @@ final class PhabricatorCalendarEventEditor
|
|||
protected function getCustomTransactionNewValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
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_INVITE:
|
||||
return $xaction->getNewValue();
|
||||
case PhabricatorCalendarEventTransaction::TYPE_STATUS:
|
||||
return (int)$xaction->getNewValue();
|
||||
|
@ -93,6 +118,7 @@ final class PhabricatorCalendarEventEditor
|
|||
case PhabricatorCalendarEventTransaction::TYPE_CANCEL:
|
||||
$object->setIsCancelled((int)$xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorCalendarEventTransaction::TYPE_INVITE:
|
||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
||||
case PhabricatorTransactions::TYPE_EDGE:
|
||||
|
@ -114,6 +140,33 @@ final class PhabricatorCalendarEventEditor
|
|||
case PhabricatorCalendarEventTransaction::TYPE_STATUS:
|
||||
case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION:
|
||||
case PhabricatorCalendarEventTransaction::TYPE_CANCEL:
|
||||
return;
|
||||
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');
|
||||
}
|
||||
|
||||
foreach ($phids as $phid) {
|
||||
$invitee = idx($invitees, $phid);
|
||||
if (!$invitee) {
|
||||
$invitee = id(new PhabricatorCalendarEventInvitee())
|
||||
->setEventPHID($object->getPHID())
|
||||
->setInviteePHID($phid)
|
||||
->setInviterPHID($this->getActingAsPHID());
|
||||
}
|
||||
$invitee->setStatus($map[$phid])
|
||||
->save();
|
||||
}
|
||||
return;
|
||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
||||
case PhabricatorTransactions::TYPE_EDGE:
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCalendarEventInviteeQuery
|
||||
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||
|
||||
private $ids;
|
||||
private $eventPHIDs;
|
||||
private $inviteePHIDs;
|
||||
private $inviterPHIDs;
|
||||
private $statuses;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withEventPHIDs(array $phids) {
|
||||
$this->eventPHIDs = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withInviteePHIDs(array $phids) {
|
||||
$this->inviteePHIDs = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withInviterPHIDs(array $phids) {
|
||||
$this->inviterPHIDs = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withStatuses(array $statuses) {
|
||||
$this->statuses = $statuses;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new PhabricatorCalendarEventInvitee();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
||||
$data = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT * FROM %T %Q %Q %Q',
|
||||
$table->getTableName(),
|
||||
$this->buildWhereClause($conn_r),
|
||||
$this->buildOrderClause($conn_r),
|
||||
$this->buildLimitClause($conn_r));
|
||||
|
||||
return $table->loadAllFromArray($data);
|
||||
}
|
||||
|
||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||
$where = array();
|
||||
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->eventPHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'eventPHID IN (%Ls)',
|
||||
$this->eventPHIDs);
|
||||
}
|
||||
|
||||
if ($this->inviteePHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'inviteePHID IN (%Ls)',
|
||||
$this->inviteePHIDs);
|
||||
}
|
||||
|
||||
if ($this->inviterPHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'inviterPHID IN (%Ls)',
|
||||
$this->inviterPHIDs);
|
||||
}
|
||||
|
||||
if ($this->statuses) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'status = %d',
|
||||
$this->statuses);
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn_r);
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
return 'PhabricatorCalendarApplication';
|
||||
}
|
||||
|
||||
}
|
|
@ -121,4 +121,26 @@ final class PhabricatorCalendarEventQuery
|
|||
return 'PhabricatorCalendarApplication';
|
||||
}
|
||||
|
||||
|
||||
protected function willFilterPage(array $events) {
|
||||
$phids = array();
|
||||
|
||||
foreach ($events as $event) {
|
||||
$phids[] = $event->getPHID();
|
||||
}
|
||||
|
||||
$invitees = id(new PhabricatorCalendarEventInviteeQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withEventPHIDs($phids)
|
||||
->execute();
|
||||
$invitees = mgroup($invitees, 'getEventPHID');
|
||||
|
||||
foreach ($events as $event) {
|
||||
$event_invitees = idx($invitees, $event->getPHID(), array());
|
||||
$event->attachInvitees($event_invitees);
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
protected $description;
|
||||
protected $isCancelled;
|
||||
|
||||
private $invitees = self::ATTACHABLE;
|
||||
|
||||
const STATUS_AWAY = 1;
|
||||
const STATUS_SPORADIC = 2;
|
||||
|
||||
|
@ -118,6 +120,15 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||
return mpull($statuses, null, 'getUserPHID');
|
||||
}
|
||||
|
||||
public function getInvitees() {
|
||||
return $this->assertAttached($this->invitees);
|
||||
}
|
||||
|
||||
public function attachInvitees(array $invitees) {
|
||||
$this->invitees = $invitees;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates data and throws exceptions for non-sensical status
|
||||
* windows
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCalendarEventInvitee extends PhabricatorCalendarDAO
|
||||
implements PhabricatorPolicyInterface {
|
||||
|
||||
protected $eventPHID;
|
||||
protected $inviteePHID;
|
||||
protected $inviterPHID;
|
||||
protected $status;
|
||||
|
||||
const STATUS_INVITED = 'invited';
|
||||
const STATUS_ATTENDING = 'attending';
|
||||
const STATUS_DECLINED = 'declined';
|
||||
const STATUS_UNINVITED = 'uninvited';
|
||||
|
||||
public static function initializeNewCalendarEventInvitee(
|
||||
PhabricatorUser $actor, $event) {
|
||||
return id(new PhabricatorCalendarEventInvitee())
|
||||
->setInviterPHID($actor->getPHID())
|
||||
->setStatus(self::STATUS_INVITED)
|
||||
->setEventPHID($event->getPHID());
|
||||
}
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'status' => 'text64',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_event' => array(
|
||||
'columns' => array('eventPHID', 'inviteePHID'),
|
||||
'unique' => true,
|
||||
),
|
||||
'key_invitee' => array(
|
||||
'columns' => array('inviteePHID'),
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
||||
public function getCapabilities() {
|
||||
return array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
);
|
||||
}
|
||||
|
||||
public function getPolicy($capability) {
|
||||
switch ($capability) {
|
||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||
return PhabricatorPolicies::getMostOpenPolicy();
|
||||
}
|
||||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function describeAutomaticCapability($capability) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ final class PhabricatorCalendarEventTransaction
|
|||
const TYPE_STATUS = 'calendar.status';
|
||||
const TYPE_DESCRIPTION = 'calendar.description';
|
||||
const TYPE_CANCEL = 'calendar.cancel';
|
||||
const TYPE_INVITE = 'calendar.invite';
|
||||
|
||||
const MAILTAG_CONTENT = 'calendar-content';
|
||||
const MAILTAG_OTHER = 'calendar-other';
|
||||
|
@ -35,6 +36,7 @@ final class PhabricatorCalendarEventTransaction
|
|||
case self::TYPE_STATUS:
|
||||
case self::TYPE_DESCRIPTION:
|
||||
case self::TYPE_CANCEL:
|
||||
case self::TYPE_INVITE:
|
||||
$phids[] = $this->getObjectPHID();
|
||||
break;
|
||||
}
|
||||
|
@ -50,6 +52,7 @@ final class PhabricatorCalendarEventTransaction
|
|||
case self::TYPE_STATUS:
|
||||
case self::TYPE_DESCRIPTION:
|
||||
case self::TYPE_CANCEL:
|
||||
case self::TYPE_INVITE:
|
||||
return ($old === null);
|
||||
}
|
||||
return parent::shouldHide();
|
||||
|
@ -63,6 +66,7 @@ final class PhabricatorCalendarEventTransaction
|
|||
case self::TYPE_STATUS:
|
||||
case self::TYPE_DESCRIPTION:
|
||||
case self::TYPE_CANCEL:
|
||||
case self::TYPE_INVITE:
|
||||
return 'fa-pencil';
|
||||
break;
|
||||
}
|
||||
|
@ -131,6 +135,11 @@ final class PhabricatorCalendarEventTransaction
|
|||
$this->renderHandleLink($author_phid));
|
||||
break;
|
||||
}
|
||||
case self::TYPE_INVITE:
|
||||
return pht(
|
||||
"%s updated the event's invitee list.",
|
||||
$this->renderHandleLink($author_phid));
|
||||
break;
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
|
@ -216,6 +225,12 @@ final class PhabricatorCalendarEventTransaction
|
|||
$this->renderHandleLink($object_phid));
|
||||
break;
|
||||
}
|
||||
case self::TYPE_INVITE:
|
||||
return pht(
|
||||
'%s updated the invitee list of %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
break;
|
||||
}
|
||||
|
||||
return parent::getTitleForFeed();
|
||||
|
@ -232,6 +247,7 @@ final class PhabricatorCalendarEventTransaction
|
|||
case self::TYPE_STATUS:
|
||||
case self::TYPE_DESCRIPTION:
|
||||
case self::TYPE_CANCEL:
|
||||
case self::TYPE_INVITE:
|
||||
return PhabricatorTransactions::COLOR_GREEN;
|
||||
}
|
||||
|
||||
|
@ -284,6 +300,9 @@ final class PhabricatorCalendarEventTransaction
|
|||
case self::TYPE_CANCEL:
|
||||
$tags[] = self::MAILTAG_CONTENT;
|
||||
break;
|
||||
case self::TYPE_INVITE:
|
||||
$tags[] = self::MAILTAG_CONTENT;
|
||||
break;
|
||||
}
|
||||
return $tags;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue