1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-29 10:12:41 +01:00

T5464, ApplicationTransactions for calendar events

Summary: Closes T5464, Implement ApplicationTransactions in Calendar.

Test Plan: Create a calendar event, update calendar event, detail view of event should show update history.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: johnny-bit, Korvin, epriestley

Maniphest Tasks: T5464

Differential Revision: https://secure.phabricator.com/D12586
This commit is contained in:
lkassianik 2015-04-28 06:26:48 -07:00
parent 9a996bcd2c
commit 65329204a5
10 changed files with 465 additions and 39 deletions

View file

@ -0,0 +1,19 @@
CREATE TABLE {$NAMESPACE}_calendar.calendar_eventtransaction (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
phid VARBINARY(64) NOT NULL,
authorPHID VARBINARY(64) NOT NULL,
objectPHID VARBINARY(64) NOT NULL,
viewPolicy VARBINARY(64) NOT NULL,
editPolicy VARBINARY(64) NOT NULL,
commentPHID VARBINARY(64) DEFAULT NULL,
commentVersion INT UNSIGNED NOT NULL,
transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
UNIQUE KEY `key_phid` (`phid`),
KEY `key_object` (`objectPHID`)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,16 @@
CREATE TABLE {$NAMESPACE}_calendar.calendar_eventtransaction_comment (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
phid VARBINARY(64) NOT NULL,
transactionPHID VARBINARY(64) DEFAULT NULL,
authorPHID VARBINARY(64) NOT NULL,
viewPolicy VARBINARY(64) NOT NULL,
editPolicy VARBINARY(64) NOT NULL,
commentVersion INT UNSIGNED NOT NULL,
content LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
isDeleted TINYINT(1) NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
UNIQUE KEY `key_phid` (`phid`),
UNIQUE KEY `key_version` (`transactionPHID`,`commentVersion`)
) ENGINE=InnoDB COLLATE {$COLLATE_TEXT}

View file

@ -1484,11 +1484,15 @@ phutil_register_library_map(array(
'PhabricatorCalendarEvent' => 'applications/calendar/storage/PhabricatorCalendarEvent.php',
'PhabricatorCalendarEventDeleteController' => 'applications/calendar/controller/PhabricatorCalendarEventDeleteController.php',
'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php',
'PhabricatorCalendarEventEditor' => 'applications/calendar/editor/PhabricatorCalendarEventEditor.php',
'PhabricatorCalendarEventInvalidEpochException' => 'applications/calendar/exception/PhabricatorCalendarEventInvalidEpochException.php',
'PhabricatorCalendarEventListController' => 'applications/calendar/controller/PhabricatorCalendarEventListController.php',
'PhabricatorCalendarEventPHIDType' => 'applications/calendar/phid/PhabricatorCalendarEventPHIDType.php',
'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php',
'PhabricatorCalendarEventSearchEngine' => 'applications/calendar/query/PhabricatorCalendarEventSearchEngine.php',
'PhabricatorCalendarEventTransaction' => 'applications/calendar/storage/PhabricatorCalendarEventTransaction.php',
'PhabricatorCalendarEventTransactionComment' => 'applications/calendar/storage/PhabricatorCalendarEventTransactionComment.php',
'PhabricatorCalendarEventTransactionQuery' => 'applications/calendar/query/PhabricatorCalendarEventTransactionQuery.php',
'PhabricatorCalendarEventViewController' => 'applications/calendar/controller/PhabricatorCalendarEventViewController.php',
'PhabricatorCalendarHoliday' => 'applications/calendar/storage/PhabricatorCalendarHoliday.php',
'PhabricatorCalendarHolidayTestCase' => 'applications/calendar/storage/__tests__/PhabricatorCalendarHolidayTestCase.php',
@ -4802,14 +4806,19 @@ phutil_register_library_map(array(
'PhabricatorCalendarDAO',
'PhabricatorPolicyInterface',
'PhabricatorMarkupInterface',
'PhabricatorApplicationTransactionInterface',
),
'PhabricatorCalendarEventDeleteController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorCalendarEventInvalidEpochException' => 'Exception',
'PhabricatorCalendarEventListController' => 'PhabricatorCalendarController',
'PhabricatorCalendarEventPHIDType' => 'PhabricatorPHIDType',
'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorCalendarEventSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorCalendarEventTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorCalendarEventTransactionComment' => 'PhabricatorApplicationTransactionComment',
'PhabricatorCalendarEventTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorCalendarEventViewController' => 'PhabricatorCalendarController',
'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO',
'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase',

View file

@ -30,13 +30,13 @@ final class PhabricatorCalendarEventEditController
->setInitialTime(AphrontFormDateControl::TIME_END_OF_DAY);
if ($this->isCreate()) {
$status = new PhabricatorCalendarEvent();
$end_value = $end_time->readValueFromRequest($request);
$start_value = $start_time->readValueFromRequest($request);
$status = PhabricatorCalendarEvent::initializeNewCalendarEvent($user);
$end_value = $end_time->readValueFromRequest($request);
$start_value = $start_time->readValueFromRequest($request);
$submit_label = pht('Create');
$filter = 'status/create/';
$page_title = pht('Create Event');
$redirect = 'created';
$filter = 'status/create/';
$page_title = pht('Create Event');
$redirect = 'created';
} else {
$status = id(new PhabricatorCalendarEventQuery())
->setViewer($user)
@ -61,6 +61,7 @@ final class PhabricatorCalendarEventEditController
$errors = array();
if ($request->isFormPost()) {
$xactions = array();
$type = $request->getInt('status');
$start_value = $start_time->readValueFromRequest($request);
$end_value = $end_time->readValueFromRequest($request);
@ -73,39 +74,33 @@ final class PhabricatorCalendarEventEditController
$errors[] = pht('Invalid end time; reset to default.');
}
if (!$errors) {
try {
$status
->setUserPHID($user->getPHID())
->setStatus($type)
->setDateFrom($start_value)
->setDateTo($end_value)
->setDescription($description)
->save();
} catch (PhabricatorCalendarEventInvalidEpochException $e) {
$errors[] = pht('Start must be before end.');
}
}
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_START_DATE)
->setNewValue($start_value);
if (!$errors) {
$uri = new PhutilURI($this->getApplicationURI());
$uri->setQueryParams(
array(
'month' => phabricator_format_local_time($status->getDateFrom(),
$user,
'm'),
'year' => phabricator_format_local_time($status->getDateFrom(),
$user,
'Y'),
$redirect => true,
));
if ($request->isAjax()) {
$response = id(new AphrontAjaxResponse())
->setContent(array('redirect_uri' => $uri));
} else {
$response = id(new AphrontRedirectResponse())
->setURI($uri);
}
return $response;
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_END_DATE)
->setNewValue($end_value);
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_STATUS)
->setNewValue($type);
$xactions[] = id(new PhabricatorCalendarEventTransaction())
->setTransactionType(
PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION)
->setNewValue($description);
$editor = id(new PhabricatorCalendarEventEditor())
->setActor($user)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true);
$xactions = $editor->applyTransactions($status, $xactions);
return id(new AphrontRedirectResponse())->setURI('/E'.$status->getID());
}
}

View file

@ -29,6 +29,10 @@ final class PhabricatorCalendarEventViewController
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($title, '/E'.$event->getID());
$timeline = $this->buildTransactionTimeline(
$event,
new PhabricatorCalendarEventTransactionQuery());
$header = $this->buildHeaderView($event);
$actions = $this->buildActionView($event);
$properties = $this->buildPropertyView($event);
@ -42,6 +46,7 @@ final class PhabricatorCalendarEventViewController
array(
$crumbs,
$box,
$timeline,
),
array(
'title' => $title,

View file

@ -0,0 +1,108 @@
<?php
final class PhabricatorCalendarEventEditor
extends PhabricatorApplicationTransactionEditor {
public function getEditorApplicationClass() {
return 'PhabricatorCalendarApplication';
}
public function getEditorObjectsDescription() {
return pht('Calendar');
}
public function getTransactionTypes() {
$types = parent::getTransactionTypes();
$types[] = PhabricatorCalendarEventTransaction::TYPE_START_DATE;
$types[] = PhabricatorCalendarEventTransaction::TYPE_END_DATE;
$types[] = PhabricatorCalendarEventTransaction::TYPE_STATUS;
$types[] = PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION;
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
return $types;
}
protected function getCustomTransactionOldValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorCalendarEventTransaction::TYPE_START_DATE:
return $object->getDateFrom();
case PhabricatorCalendarEventTransaction::TYPE_END_DATE:
return $object->getDateTo();
case PhabricatorCalendarEventTransaction::TYPE_STATUS:
$status = $object->getStatus();
if ($status === null) {
return null;
}
return (int)$status;
case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION:
return $object->getDescription();
}
return parent::getCustomTransactionOldValue($object, $xaction);
}
protected function getCustomTransactionNewValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorCalendarEventTransaction::TYPE_START_DATE:
case PhabricatorCalendarEventTransaction::TYPE_END_DATE:
case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION:
return $xaction->getNewValue();
case PhabricatorCalendarEventTransaction::TYPE_STATUS:
return (int)$xaction->getNewValue();
}
return parent::getCustomTransactionNewValue($object, $xaction);
}
protected function applyCustomInternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorCalendarEventTransaction::TYPE_START_DATE:
$object->setDateFrom($xaction->getNewValue());
return;
case PhabricatorCalendarEventTransaction::TYPE_END_DATE:
$object->setDateTo($xaction->getNewValue());
return;
case PhabricatorCalendarEventTransaction::TYPE_STATUS:
$object->setStatus($xaction->getNewValue());
return;
case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION:
$object->setDescription($xaction->getNewValue());
return;
case PhabricatorTransactions::TYPE_VIEW_POLICY:
case PhabricatorTransactions::TYPE_EDIT_POLICY:
case PhabricatorTransactions::TYPE_EDGE:
return;
}
return parent::applyCustomInternalTransaction($object, $xaction);
}
protected function applyCustomExternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorCalendarEventTransaction::TYPE_START_DATE:
case PhabricatorCalendarEventTransaction::TYPE_END_DATE:
case PhabricatorCalendarEventTransaction::TYPE_STATUS:
case PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION:
case PhabricatorTransactions::TYPE_VIEW_POLICY:
case PhabricatorTransactions::TYPE_EDIT_POLICY:
case PhabricatorTransactions::TYPE_EDGE:
return;
}
return parent::applyCustomExternalTransaction($object, $xaction);
}
}

View file

@ -0,0 +1,10 @@
<?php
final class PhabricatorCalendarEventTransactionQuery
extends PhabricatorApplicationTransactionQuery {
public function getTemplateApplicationTransaction() {
return new PhabricatorCalendarEventTransaction();
}
}

View file

@ -2,7 +2,8 @@
final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
implements PhabricatorPolicyInterface,
PhabricatorMarkupInterface {
PhabricatorMarkupInterface,
PhabricatorApplicationTransactionInterface {
protected $userPHID;
protected $dateFrom;
@ -13,6 +14,16 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
const STATUS_AWAY = 1;
const STATUS_SPORADIC = 2;
public static function initializeNewCalendarEvent(PhabricatorUser $actor) {
$app = id(new PhabricatorApplicationQuery())
->setViewer($actor)
->withClasses(array('PhabricatorCalendarApplication'))
->executeOne();
return id(new PhabricatorCalendarEvent())
->setUserPHID($actor->getPHID());
}
private static $statusTexts = array(
self::STATUS_AWAY => 'away',
self::STATUS_SPORADIC => 'sporadic',
@ -86,6 +97,17 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
return mpull($statuses, null, 'getUserPHID');
}
public static function getNameForStatus($value) {
switch ($value) {
case self::STATUS_AWAY:
return pht('Away');
case self::STATUS_SPORADIC:
return pht('Sporadic');
default:
return pht('Unknown');
}
}
/**
* Validates data and throws exceptions for non-sensical status
* windows
@ -173,4 +195,26 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
return null;
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
public function getApplicationTransactionEditor() {
return new PhabricatorCalendarEventEditor();
}
public function getApplicationTransactionObject() {
return $this;
}
public function getApplicationTransactionTemplate() {
return new PhabricatorCalendarEventTransaction();
}
public function willRenderTimeline(
PhabricatorApplicationTransactionView $timeline,
AphrontRequest $request) {
return $timeline;
}
}

View file

@ -0,0 +1,210 @@
<?php
final class PhabricatorCalendarEventTransaction
extends PhabricatorApplicationTransaction {
const TYPE_START_DATE = 'calendar.startdate';
const TYPE_END_DATE = 'calendar.enddate';
const TYPE_STATUS = 'calendar.status';
const TYPE_DESCRIPTION = 'calendar.description';
const MAILTAG_CONTENT = 'calendar-content';
const MAILTAG_OTHER = 'calendar-other';
public function getApplicationName() {
return 'calendar';
}
public function getApplicationTransactionType() {
return PhabricatorCalendarEventPHIDType::TYPECONST;
}
public function getApplicationTransactionCommentObject() {
return new PhabricatorCalendarEventTransactionComment();
}
public function getRequiredHandlePHIDs() {
$phids = parent::getRequiredHandlePHIDs();
switch ($this->getTransactionType()) {
case self::TYPE_START_DATE:
case self::TYPE_END_DATE:
case self::TYPE_STATUS:
case self::TYPE_DESCRIPTION:
$phids[] = $this->getObjectPHID();
break;
}
return $phids;
}
public function shouldHide() {
$old = $this->getOldValue();
switch ($this->getTransactionType()) {
case self::TYPE_START_DATE:
case self::TYPE_END_DATE:
case self::TYPE_STATUS:
case self::TYPE_DESCRIPTION:
return ($old === null);
}
return parent::shouldHide();
}
public function getIcon() {
switch ($this->getTransactionType()) {
case self::TYPE_START_DATE:
case self::TYPE_END_DATE:
case self::TYPE_STATUS:
case self::TYPE_DESCRIPTION:
return 'fa-pencil';
break;
}
return parent::getIcon();
}
public function getTitle() {
$author_phid = $this->getAuthorPHID();
$object_phid = $this->getObjectPHID();
$old = $this->getOldValue();
$new = $this->getNewValue();
$type = $this->getTransactionType();
switch ($type) {
case self::TYPE_START_DATE:
if ($old) {
return pht(
'%s edited the start date of this event.',
$this->renderHandleLink($author_phid));
}
break;
case self::TYPE_END_DATE:
if ($old) {
return pht(
'%s edited the end date of this event.',
$this->renderHandleLink($author_phid));
}
break;
case self::TYPE_STATUS:
$old_name = PhabricatorCalendarEvent::getNameForStatus($old);
$new_name = PhabricatorCalendarEvent::getNameForStatus($new);
return pht(
'%s updated the event status from %s to %s.',
$this->renderHandleLink($author_phid),
$old_name,
$new_name);
break;
case self::TYPE_DESCRIPTION:
return pht(
"%s updated the event's description.",
$this->renderHandleLink($author_phid));
break;
}
return parent::getTitle();
}
public function getTitleForFeed() {
$author_phid = $this->getAuthorPHID();
$object_phid = $this->getObjectPHID();
$old = $this->getOldValue();
$new = $this->getNewValue();
$type = $this->getTransactionType();
switch ($type) {
case self::TYPE_START_DATE:
if ($old) {
return pht(
'%s edited the start date of this event from %s to %s.',
$this->renderHandleLink($author_phid),
$old,
$new);
}
break;
case self::TYPE_END_DATE:
if ($old) {
return pht(
'%s edited the end date of this event from %s to %s.',
$this->renderHandleLink($author_phid),
$old,
$new);
}
break;
case self::TYPE_STATUS:
return pht(
'%s updated the event status from %s to %s.',
$this->renderHandleLink($author_phid),
$old,
$new);
break;
case self::TYPE_DESCRIPTION:
return pht(
"%s updated the event's description.",
$this->renderHandleLink($author_phid));
break;
}
return parent::getTitleForFeed();
}
public function getColor() {
$old = $this->getOldValue();
$new = $this->getNewValue();
switch ($this->getTransactionType()) {
case self::TYPE_START_DATE:
case self::TYPE_END_DATE:
case self::TYPE_STATUS:
case self::TYPE_DESCRIPTION:
return PhabricatorTransactions::COLOR_GREEN;
}
return parent::getColor();
}
public function hasChangeDetails() {
switch ($this->getTransactionType()) {
case self::TYPE_DESCRIPTION:
return ($this->getOldValue() !== null);
}
return parent::hasChangeDetails();
}
public function renderChangeDetails(PhabricatorUser $viewer) {
switch ($this->getTransactionType()) {
case self::TYPE_DESCRIPTION:
$old = $this->getOldValue();
$new = $this->getNewValue();
return $this->renderTextCorpusChangeDetails(
$viewer,
$old,
$new);
}
return parent::renderChangeDetails($viewer);
}
public function getMailTags() {
$tags = array();
switch ($this->getTransactionType()) {
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;
}
return $tags;
}
}

View file

@ -0,0 +1,10 @@
<?php
final class PhabricatorCalendarEventTransactionComment
extends PhabricatorApplicationTransactionComment {
public function getApplicationTransactionObject() {
return new PhabricatorCalendarEventTransaction();
}
}