mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-18 12:52:42 +01:00
Modularize application transactions in Paste, mostly
Summary: Ref T9789. `Transaction` and `Editor` classes are the last major pieces of infrastructure that haven't been fully modularized. Some of the specific issues are: - `Editor` classes rely on a bunch of `instanceof` stuff in the base class to pick up transaction types like "subscribe", "projects", etc. Instead, applications should be adding these, and third-party applications should be able to add them. - Code is spread across `Transaction` and `Editor` classes somewhat oddly. For example, generating old/new values would probably make more sense at the `Transaction` level, but it currently exists at the `Editor` level. - Both types of classes have a lot of functions based on `switch()` statements, which require a ton of boilerplate and are just generally kind of hard to work with. This creates classes for each type of transaction, and moves almost all of the logic to them. These classes are simpler and more focused than the old stuff was, and can organize related code better. This starts inching toward defining `CoreTransactions` for features shared across applications. It only defines the "Create" transaction so far, but at some point I plan to move all the other shared transactions to Core and let them control which objects they're available for. Test Plan: - Created pastes with web UI and API. - Edited all paste properites. - Archived/activated. - Verified files got reasonable names. - Reviewed timeline and feed. Reviewers: chad Reviewed By: chad Maniphest Tasks: T9789 Differential Revision: https://secure.phabricator.com/D16111
This commit is contained in:
parent
d68b2cc0e4
commit
33ec855449
21 changed files with 747 additions and 468 deletions
|
@ -1,47 +1,5 @@
|
|||
<?php
|
||||
|
||||
$table = new PhabricatorPaste();
|
||||
$x_table = new PhabricatorPasteTransaction();
|
||||
|
||||
$conn_w = $table->establishConnection('w');
|
||||
$conn_w->openTransaction();
|
||||
|
||||
echo pht('Adding transactions for existing paste objects...')."\n";
|
||||
|
||||
$rows = new LiskRawMigrationIterator($conn_w, 'pastebin_paste');
|
||||
foreach ($rows as $row) {
|
||||
|
||||
$id = $row['id'];
|
||||
echo pht('Adding transactions for paste id %d...', $id)."\n";
|
||||
|
||||
$xaction_phid = PhabricatorPHID::generateNewPHID(
|
||||
PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST);
|
||||
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'INSERT INTO %T (phid, authorPHID, objectPHID, viewPolicy, editPolicy,
|
||||
transactionType, oldValue, newValue,
|
||||
contentSource, metadata, dateCreated, dateModified,
|
||||
commentVersion)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %ns, %ns, %s, %s, %d, %d, %d)',
|
||||
$x_table->getTableName(),
|
||||
$xaction_phid,
|
||||
$row['authorPHID'],
|
||||
$row['phid'],
|
||||
'public',
|
||||
$row['authorPHID'],
|
||||
PhabricatorPasteTransaction::TYPE_CONTENT,
|
||||
'null',
|
||||
$row['filePHID'],
|
||||
PhabricatorContentSource::newForSource(
|
||||
PhabricatorOldWorldContentSource::SOURCECONST)->serialize(),
|
||||
'[]',
|
||||
$row['dateCreated'],
|
||||
$row['dateCreated'],
|
||||
0);
|
||||
|
||||
}
|
||||
|
||||
$conn_w->saveTransaction();
|
||||
|
||||
echo pht('Done.')."\n";
|
||||
// Long ago, this migration populated initial "create" transactions for old
|
||||
// pastes from before transactions came into existence. It was removed after
|
||||
// about three years.
|
||||
|
|
|
@ -2160,6 +2160,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorController' => 'applications/base/controller/PhabricatorController.php',
|
||||
'PhabricatorCookies' => 'applications/auth/constants/PhabricatorCookies.php',
|
||||
'PhabricatorCoreConfigOptions' => 'applications/config/option/PhabricatorCoreConfigOptions.php',
|
||||
'PhabricatorCoreCreateTransaction' => 'applications/transactions/xaction/PhabricatorCoreCreateTransaction.php',
|
||||
'PhabricatorCoreTransactionType' => 'applications/transactions/xaction/PhabricatorCoreTransactionType.php',
|
||||
'PhabricatorCoreVoidTransaction' => 'applications/transactions/xaction/PhabricatorCoreVoidTransaction.php',
|
||||
'PhabricatorCountdown' => 'applications/countdown/storage/PhabricatorCountdown.php',
|
||||
'PhabricatorCountdownApplication' => 'applications/countdown/application/PhabricatorCountdownApplication.php',
|
||||
'PhabricatorCountdownController' => 'applications/countdown/controller/PhabricatorCountdownController.php',
|
||||
|
@ -2757,6 +2760,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMetaMTASendGridReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php',
|
||||
'PhabricatorMetaMTAWorker' => 'applications/metamta/PhabricatorMetaMTAWorker.php',
|
||||
'PhabricatorMetronomicTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorMetronomicTriggerClock.php',
|
||||
'PhabricatorModularTransaction' => 'applications/transactions/storage/PhabricatorModularTransaction.php',
|
||||
'PhabricatorModularTransactionType' => 'applications/transactions/storage/PhabricatorModularTransactionType.php',
|
||||
'PhabricatorMonospacedFontSetting' => 'applications/settings/setting/PhabricatorMonospacedFontSetting.php',
|
||||
'PhabricatorMonospacedTextareasSetting' => 'applications/settings/setting/PhabricatorMonospacedTextareasSetting.php',
|
||||
'PhabricatorMotivatorProfilePanel' => 'applications/search/profilepanel/PhabricatorMotivatorProfilePanel.php',
|
||||
|
@ -2916,12 +2921,14 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPasteArchiveController' => 'applications/paste/controller/PhabricatorPasteArchiveController.php',
|
||||
'PhabricatorPasteConfigOptions' => 'applications/paste/config/PhabricatorPasteConfigOptions.php',
|
||||
'PhabricatorPasteContentSearchEngineAttachment' => 'applications/paste/engineextension/PhabricatorPasteContentSearchEngineAttachment.php',
|
||||
'PhabricatorPasteContentTransaction' => 'applications/paste/xaction/PhabricatorPasteContentTransaction.php',
|
||||
'PhabricatorPasteController' => 'applications/paste/controller/PhabricatorPasteController.php',
|
||||
'PhabricatorPasteDAO' => 'applications/paste/storage/PhabricatorPasteDAO.php',
|
||||
'PhabricatorPasteEditController' => 'applications/paste/controller/PhabricatorPasteEditController.php',
|
||||
'PhabricatorPasteEditEngine' => 'applications/paste/editor/PhabricatorPasteEditEngine.php',
|
||||
'PhabricatorPasteEditor' => 'applications/paste/editor/PhabricatorPasteEditor.php',
|
||||
'PhabricatorPasteFilenameContextFreeGrammar' => 'applications/paste/lipsum/PhabricatorPasteFilenameContextFreeGrammar.php',
|
||||
'PhabricatorPasteLanguageTransaction' => 'applications/paste/xaction/PhabricatorPasteLanguageTransaction.php',
|
||||
'PhabricatorPasteListController' => 'applications/paste/controller/PhabricatorPasteListController.php',
|
||||
'PhabricatorPastePastePHIDType' => 'applications/paste/phid/PhabricatorPastePastePHIDType.php',
|
||||
'PhabricatorPasteQuery' => 'applications/paste/query/PhabricatorPasteQuery.php',
|
||||
|
@ -2930,10 +2937,13 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPasteSchemaSpec' => 'applications/paste/storage/PhabricatorPasteSchemaSpec.php',
|
||||
'PhabricatorPasteSearchEngine' => 'applications/paste/query/PhabricatorPasteSearchEngine.php',
|
||||
'PhabricatorPasteSnippet' => 'applications/paste/snippet/PhabricatorPasteSnippet.php',
|
||||
'PhabricatorPasteStatusTransaction' => 'applications/paste/xaction/PhabricatorPasteStatusTransaction.php',
|
||||
'PhabricatorPasteTestDataGenerator' => 'applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php',
|
||||
'PhabricatorPasteTitleTransaction' => 'applications/paste/xaction/PhabricatorPasteTitleTransaction.php',
|
||||
'PhabricatorPasteTransaction' => 'applications/paste/storage/PhabricatorPasteTransaction.php',
|
||||
'PhabricatorPasteTransactionComment' => 'applications/paste/storage/PhabricatorPasteTransactionComment.php',
|
||||
'PhabricatorPasteTransactionQuery' => 'applications/paste/query/PhabricatorPasteTransactionQuery.php',
|
||||
'PhabricatorPasteTransactionType' => 'applications/paste/xaction/PhabricatorPasteTransactionType.php',
|
||||
'PhabricatorPasteViewController' => 'applications/paste/controller/PhabricatorPasteViewController.php',
|
||||
'PhabricatorPathSetupCheck' => 'applications/config/check/PhabricatorPathSetupCheck.php',
|
||||
'PhabricatorPeopleAnyOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleAnyOwnerDatasource.php',
|
||||
|
@ -6729,6 +6739,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorController' => 'AphrontController',
|
||||
'PhabricatorCookies' => 'Phobject',
|
||||
'PhabricatorCoreConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorCoreCreateTransaction' => 'PhabricatorCoreTransactionType',
|
||||
'PhabricatorCoreTransactionType' => 'PhabricatorModularTransactionType',
|
||||
'PhabricatorCoreVoidTransaction' => 'PhabricatorModularTransactionType',
|
||||
'PhabricatorCountdown' => array(
|
||||
'PhabricatorCountdownDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
|
@ -7406,6 +7419,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMetaMTASendGridReceiveController' => 'PhabricatorMetaMTAController',
|
||||
'PhabricatorMetaMTAWorker' => 'PhabricatorWorker',
|
||||
'PhabricatorMetronomicTriggerClock' => 'PhabricatorTriggerClock',
|
||||
'PhabricatorModularTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'PhabricatorModularTransactionType' => 'Phobject',
|
||||
'PhabricatorMonospacedFontSetting' => 'PhabricatorStringSetting',
|
||||
'PhabricatorMonospacedTextareasSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorMotivatorProfilePanel' => 'PhabricatorProfilePanel',
|
||||
|
@ -7601,12 +7616,14 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPasteArchiveController' => 'PhabricatorPasteController',
|
||||
'PhabricatorPasteConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorPasteContentSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||
'PhabricatorPasteContentTransaction' => 'PhabricatorPasteTransactionType',
|
||||
'PhabricatorPasteController' => 'PhabricatorController',
|
||||
'PhabricatorPasteDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorPasteEditController' => 'PhabricatorPasteController',
|
||||
'PhabricatorPasteEditEngine' => 'PhabricatorEditEngine',
|
||||
'PhabricatorPasteEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorPasteFilenameContextFreeGrammar' => 'PhutilContextFreeGrammar',
|
||||
'PhabricatorPasteLanguageTransaction' => 'PhabricatorPasteTransactionType',
|
||||
'PhabricatorPasteListController' => 'PhabricatorPasteController',
|
||||
'PhabricatorPastePastePHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorPasteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
|
@ -7615,10 +7632,13 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPasteSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||
'PhabricatorPasteSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'PhabricatorPasteSnippet' => 'Phobject',
|
||||
'PhabricatorPasteStatusTransaction' => 'PhabricatorPasteTransactionType',
|
||||
'PhabricatorPasteTestDataGenerator' => 'PhabricatorTestDataGenerator',
|
||||
'PhabricatorPasteTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'PhabricatorPasteTitleTransaction' => 'PhabricatorPasteTransactionType',
|
||||
'PhabricatorPasteTransaction' => 'PhabricatorModularTransaction',
|
||||
'PhabricatorPasteTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
||||
'PhabricatorPasteTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorPasteTransactionType' => 'PhabricatorModularTransactionType',
|
||||
'PhabricatorPasteViewController' => 'PhabricatorPasteController',
|
||||
'PhabricatorPathSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorPeopleAnyOwnerDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
|
|
|
@ -47,15 +47,15 @@ final class PasteCreateConduitAPIMethod extends PasteConduitAPIMethod {
|
|||
$xactions = array();
|
||||
|
||||
$xactions[] = id(new PhabricatorPasteTransaction())
|
||||
->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
|
||||
->setTransactionType(PhabricatorPasteContentTransaction::TRANSACTIONTYPE)
|
||||
->setNewValue($content);
|
||||
|
||||
$xactions[] = id(new PhabricatorPasteTransaction())
|
||||
->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
|
||||
->setTransactionType(PhabricatorPasteTitleTransaction::TRANSACTIONTYPE)
|
||||
->setNewValue($title);
|
||||
|
||||
$xactions[] = id(new PhabricatorPasteTransaction())
|
||||
->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE)
|
||||
->setTransactionType(PhabricatorPasteLanguageTransaction::TRANSACTIONTYPE)
|
||||
->setNewValue($language);
|
||||
|
||||
$editor = id(new PhabricatorPasteEditor())
|
||||
|
|
|
@ -20,7 +20,7 @@ final class PhabricatorPasteArchiveController
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$view_uri = '/P'.$paste->getID();
|
||||
$view_uri = $paste->getURI();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
if ($paste->isArchived()) {
|
||||
|
@ -32,7 +32,7 @@ final class PhabricatorPasteArchiveController
|
|||
$xactions = array();
|
||||
|
||||
$xactions[] = id(new PhabricatorPasteTransaction())
|
||||
->setTransactionType(PhabricatorPasteTransaction::TYPE_STATUS)
|
||||
->setTransactionType(PhabricatorPasteStatusTransaction::TRANSACTIONTYPE)
|
||||
->setNewValue($new_status);
|
||||
|
||||
id(new PhabricatorPasteEditor())
|
||||
|
|
|
@ -71,7 +71,7 @@ final class PhabricatorPasteEditEngine
|
|||
id(new PhabricatorTextEditField())
|
||||
->setKey('title')
|
||||
->setLabel(pht('Title'))
|
||||
->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
|
||||
->setTransactionType(PhabricatorPasteTitleTransaction::TRANSACTIONTYPE)
|
||||
->setDescription(pht('The title of the paste.'))
|
||||
->setConduitDescription(pht('Retitle the paste.'))
|
||||
->setConduitTypeDescription(pht('New paste title.'))
|
||||
|
@ -79,7 +79,8 @@ final class PhabricatorPasteEditEngine
|
|||
id(new PhabricatorSelectEditField())
|
||||
->setKey('language')
|
||||
->setLabel(pht('Language'))
|
||||
->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE)
|
||||
->setTransactionType(
|
||||
PhabricatorPasteLanguageTransaction::TRANSACTIONTYPE)
|
||||
->setAliases(array('lang'))
|
||||
->setIsCopyable(true)
|
||||
->setOptions($langs)
|
||||
|
@ -94,7 +95,8 @@ final class PhabricatorPasteEditEngine
|
|||
id(new PhabricatorTextAreaEditField())
|
||||
->setKey('text')
|
||||
->setLabel(pht('Text'))
|
||||
->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
|
||||
->setTransactionType(
|
||||
PhabricatorPasteContentTransaction::TRANSACTIONTYPE)
|
||||
->setMonospaced(true)
|
||||
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
|
||||
->setDescription(pht('The main body text of the paste.'))
|
||||
|
@ -104,7 +106,8 @@ final class PhabricatorPasteEditEngine
|
|||
id(new PhabricatorSelectEditField())
|
||||
->setKey('status')
|
||||
->setLabel(pht('Status'))
|
||||
->setTransactionType(PhabricatorPasteTransaction::TYPE_STATUS)
|
||||
->setTransactionType(
|
||||
PhabricatorPasteStatusTransaction::TRANSACTIONTYPE)
|
||||
->setIsConduitOnly(true)
|
||||
->setOptions(PhabricatorPaste::getStatusNameMap())
|
||||
->setDescription(pht('Active or archived status.'))
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
final class PhabricatorPasteEditor
|
||||
extends PhabricatorApplicationTransactionEditor {
|
||||
|
||||
private $fileName;
|
||||
|
||||
public function getEditorApplicationClass() {
|
||||
return 'PhabricatorPasteApplication';
|
||||
}
|
||||
|
@ -13,29 +11,17 @@ final class PhabricatorPasteEditor
|
|||
return pht('Pastes');
|
||||
}
|
||||
|
||||
public static function initializeFileForPaste(
|
||||
PhabricatorUser $actor,
|
||||
$name,
|
||||
$data) {
|
||||
public function getCreateObjectTitle($author, $object) {
|
||||
return pht('%s created this paste.', $author);
|
||||
}
|
||||
|
||||
return PhabricatorFile::newFromFileData(
|
||||
$data,
|
||||
array(
|
||||
'name' => $name,
|
||||
'mime-type' => 'text/plain; charset=utf-8',
|
||||
'authorPHID' => $actor->getPHID(),
|
||||
'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
|
||||
'editPolicy' => PhabricatorPolicies::POLICY_NOONE,
|
||||
));
|
||||
public function getCreateObjectTitleForFeed($author, $object) {
|
||||
return pht('%s created %s.', $author, $object);
|
||||
}
|
||||
|
||||
public function getTransactionTypes() {
|
||||
$types = parent::getTransactionTypes();
|
||||
|
||||
$types[] = PhabricatorPasteTransaction::TYPE_CONTENT;
|
||||
$types[] = PhabricatorPasteTransaction::TYPE_TITLE;
|
||||
$types[] = PhabricatorPasteTransaction::TYPE_LANGUAGE;
|
||||
$types[] = PhabricatorPasteTransaction::TYPE_STATUS;
|
||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||
|
@ -43,163 +29,14 @@ final class PhabricatorPasteEditor
|
|||
return $types;
|
||||
}
|
||||
|
||||
protected function shouldApplyInitialEffects(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function applyInitialEffects(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
// Find the most user-friendly filename we can by examining the title of
|
||||
// the paste and the pending transactions. We'll use this if we create a
|
||||
// new file to store raw content later.
|
||||
|
||||
$name = $object->getTitle();
|
||||
if (!strlen($name)) {
|
||||
$name = 'paste.raw';
|
||||
}
|
||||
|
||||
$type_title = PhabricatorPasteTransaction::TYPE_TITLE;
|
||||
foreach ($xactions as $xaction) {
|
||||
if ($xaction->getTransactionType() == $type_title) {
|
||||
$name = $xaction->getNewValue();
|
||||
}
|
||||
}
|
||||
|
||||
$this->fileName = $name;
|
||||
}
|
||||
|
||||
protected function validateTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
$type,
|
||||
array $xactions) {
|
||||
|
||||
$errors = parent::validateTransaction($object, $type, $xactions);
|
||||
switch ($type) {
|
||||
case PhabricatorPasteTransaction::TYPE_CONTENT:
|
||||
if (!$object->getFilePHID() && !$xactions) {
|
||||
$error = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Required'),
|
||||
pht('You must provide content to create a paste.'),
|
||||
null);
|
||||
|
||||
$error->setIsMissingFieldError(true);
|
||||
$errors[] = $error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
protected function getCustomTransactionOldValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorPasteTransaction::TYPE_CONTENT:
|
||||
return $object->getFilePHID();
|
||||
case PhabricatorPasteTransaction::TYPE_TITLE:
|
||||
return $object->getTitle();
|
||||
case PhabricatorPasteTransaction::TYPE_LANGUAGE:
|
||||
return $object->getLanguage();
|
||||
case PhabricatorPasteTransaction::TYPE_STATUS:
|
||||
return $object->getStatus();
|
||||
}
|
||||
}
|
||||
|
||||
protected function getCustomTransactionNewValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorPasteTransaction::TYPE_TITLE:
|
||||
case PhabricatorPasteTransaction::TYPE_LANGUAGE:
|
||||
case PhabricatorPasteTransaction::TYPE_STATUS:
|
||||
return $xaction->getNewValue();
|
||||
case PhabricatorPasteTransaction::TYPE_CONTENT:
|
||||
// If this transaction does not really change the paste content, return
|
||||
// the current file PHID so this transaction no-ops.
|
||||
$new_content = $xaction->getNewValue();
|
||||
$old_content = $object->getRawContent();
|
||||
$file_phid = $object->getFilePHID();
|
||||
if (($new_content === $old_content) && $file_phid) {
|
||||
return $file_phid;
|
||||
}
|
||||
|
||||
$file = self::initializeFileForPaste(
|
||||
$this->getActor(),
|
||||
$this->fileName,
|
||||
$xaction->getNewValue());
|
||||
|
||||
return $file->getPHID();
|
||||
}
|
||||
}
|
||||
|
||||
protected function applyCustomInternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorPasteTransaction::TYPE_CONTENT:
|
||||
$object->setFilePHID($xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorPasteTransaction::TYPE_TITLE:
|
||||
$object->setTitle($xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorPasteTransaction::TYPE_LANGUAGE:
|
||||
$object->setLanguage($xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorPasteTransaction::TYPE_STATUS:
|
||||
$object->setStatus($xaction->getNewValue());
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomInternalTransaction($object, $xaction);
|
||||
}
|
||||
|
||||
protected function applyCustomExternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorPasteTransaction::TYPE_CONTENT:
|
||||
case PhabricatorPasteTransaction::TYPE_TITLE:
|
||||
case PhabricatorPasteTransaction::TYPE_LANGUAGE:
|
||||
case PhabricatorPasteTransaction::TYPE_STATUS:
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomExternalTransaction($object, $xaction);
|
||||
}
|
||||
|
||||
protected function extractFilePHIDsFromCustomTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorPasteTransaction::TYPE_CONTENT:
|
||||
return array($xaction->getNewValue());
|
||||
}
|
||||
|
||||
return parent::extractFilePHIDsFromCustomTransaction($object, $xaction);
|
||||
}
|
||||
|
||||
protected function shouldSendMail(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
foreach ($xactions as $xaction) {
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorPasteTransaction::TYPE_CONTENT:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->getIsNewObject()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -258,8 +95,4 @@ final class PhabricatorPasteEditor
|
|||
return true;
|
||||
}
|
||||
|
||||
protected function supportsSearch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,15 +17,15 @@ final class PhabricatorPasteTestDataGenerator
|
|||
$xactions = array();
|
||||
|
||||
$xactions[] = $this->newTransaction(
|
||||
PhabricatorPasteTransaction::TYPE_TITLE,
|
||||
PhabricatorPasteTitleTransaction::TRANSACTIONTYPE,
|
||||
$name);
|
||||
|
||||
$xactions[] = $this->newTransaction(
|
||||
PhabricatorPasteTransaction::TYPE_LANGUAGE,
|
||||
PhabricatorPasteLanguageTransaction::TRANSACTIONTYPE,
|
||||
$language);
|
||||
|
||||
$xactions[] = $this->newTransaction(
|
||||
PhabricatorPasteTransaction::TYPE_CONTENT,
|
||||
PhabricatorPasteContentTransaction::TRANSACTIONTYPE,
|
||||
$content);
|
||||
|
||||
$editor = id(new PhabricatorPasteEditor())
|
||||
|
|
|
@ -24,17 +24,13 @@ final class PasteCreateMailReceiver extends PhabricatorMailReceiver {
|
|||
$xactions = array();
|
||||
|
||||
$xactions[] = id(new PhabricatorPasteTransaction())
|
||||
->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
|
||||
->setTransactionType(PhabricatorPasteContentTransaction::TRANSACTIONTYPE)
|
||||
->setNewValue($mail->getCleanTextBody());
|
||||
|
||||
$xactions[] = id(new PhabricatorPasteTransaction())
|
||||
->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
|
||||
->setTransactionType(PhabricatorPasteTitleTransaction::TRANSACTIONTYPE)
|
||||
->setNewValue($title);
|
||||
|
||||
$xactions[] = id(new PhabricatorPasteTransaction())
|
||||
->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE)
|
||||
->setNewValue(''); // auto-detect
|
||||
|
||||
$paste = PhabricatorPaste::initializeNewPaste($sender);
|
||||
|
||||
$content_source = $mail->newContentSource();
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorPasteTransaction
|
||||
extends PhabricatorApplicationTransaction {
|
||||
|
||||
const TYPE_CONTENT = 'paste.create';
|
||||
const TYPE_TITLE = 'paste.title';
|
||||
const TYPE_LANGUAGE = 'paste.language';
|
||||
const TYPE_STATUS = 'paste.status';
|
||||
extends PhabricatorModularTransaction {
|
||||
|
||||
const MAILTAG_CONTENT = 'paste-content';
|
||||
const MAILTAG_OTHER = 'paste-other';
|
||||
|
@ -24,226 +19,16 @@ final class PhabricatorPasteTransaction
|
|||
return new PhabricatorPasteTransactionComment();
|
||||
}
|
||||
|
||||
public function getRequiredHandlePHIDs() {
|
||||
$phids = parent::getRequiredHandlePHIDs();
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_CONTENT:
|
||||
$phids[] = $this->getObjectPHID();
|
||||
break;
|
||||
}
|
||||
|
||||
return $phids;
|
||||
}
|
||||
|
||||
public function shouldHide() {
|
||||
$old = $this->getOldValue();
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_TITLE:
|
||||
case self::TYPE_LANGUAGE:
|
||||
if ($old === null) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return parent::shouldHide();
|
||||
}
|
||||
|
||||
public function getIcon() {
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_CONTENT:
|
||||
return 'fa-plus';
|
||||
break;
|
||||
case self::TYPE_TITLE:
|
||||
case self::TYPE_LANGUAGE:
|
||||
return 'fa-pencil';
|
||||
break;
|
||||
case self::TYPE_STATUS:
|
||||
$new = $this->getNewValue();
|
||||
switch ($new) {
|
||||
case PhabricatorPaste::STATUS_ACTIVE:
|
||||
return 'fa-check';
|
||||
case PhabricatorPaste::STATUS_ARCHIVED:
|
||||
return 'fa-ban';
|
||||
}
|
||||
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 PhabricatorTransactions::TYPE_CREATE:
|
||||
return pht(
|
||||
'%s created this paste.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
case self::TYPE_CONTENT:
|
||||
if ($old === null) {
|
||||
return pht(
|
||||
'%s created this paste.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
} else {
|
||||
return pht(
|
||||
'%s edited the content of this paste.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
}
|
||||
break;
|
||||
case self::TYPE_TITLE:
|
||||
return pht(
|
||||
'%s updated the paste\'s title to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$new);
|
||||
break;
|
||||
case self::TYPE_LANGUAGE:
|
||||
return pht(
|
||||
"%s updated the paste's language.",
|
||||
$this->renderHandleLink($author_phid));
|
||||
break;
|
||||
case self::TYPE_STATUS:
|
||||
switch ($new) {
|
||||
case PhabricatorPaste::STATUS_ACTIVE:
|
||||
return pht(
|
||||
'%s activated this paste.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
case PhabricatorPaste::STATUS_ARCHIVED:
|
||||
return pht(
|
||||
'%s archived this paste.',
|
||||
$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_CONTENT:
|
||||
if ($old === null) {
|
||||
return pht(
|
||||
'%s created %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
} else {
|
||||
return pht(
|
||||
'%s edited %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
}
|
||||
break;
|
||||
case self::TYPE_TITLE:
|
||||
return pht(
|
||||
'%s updated the title for %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
break;
|
||||
case self::TYPE_LANGUAGE:
|
||||
return pht(
|
||||
'%s updated the language for %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
break;
|
||||
case self::TYPE_STATUS:
|
||||
switch ($new) {
|
||||
case PhabricatorPaste::STATUS_ACTIVE:
|
||||
return pht(
|
||||
'%s activated %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
case PhabricatorPaste::STATUS_ARCHIVED:
|
||||
return pht(
|
||||
'%s archived %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return parent::getTitleForFeed();
|
||||
}
|
||||
|
||||
public function getColor() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_CONTENT:
|
||||
return PhabricatorTransactions::COLOR_GREEN;
|
||||
case self::TYPE_STATUS:
|
||||
switch ($new) {
|
||||
case PhabricatorPaste::STATUS_ACTIVE:
|
||||
return 'green';
|
||||
case PhabricatorPaste::STATUS_ARCHIVED:
|
||||
return 'indigo';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return parent::getColor();
|
||||
}
|
||||
|
||||
|
||||
public function hasChangeDetails() {
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_CONTENT:
|
||||
return ($this->getOldValue() !== null);
|
||||
}
|
||||
|
||||
return parent::hasChangeDetails();
|
||||
}
|
||||
|
||||
public function renderChangeDetails(PhabricatorUser $viewer) {
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_CONTENT:
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
$files = id(new PhabricatorFileQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array_filter(array($old, $new)))
|
||||
->execute();
|
||||
$files = mpull($files, null, 'getPHID');
|
||||
|
||||
$old_text = '';
|
||||
if (idx($files, $old)) {
|
||||
$old_text = $files[$old]->loadFileData();
|
||||
}
|
||||
|
||||
$new_text = '';
|
||||
if (idx($files, $new)) {
|
||||
$new_text = $files[$new]->loadFileData();
|
||||
}
|
||||
|
||||
return $this->renderTextCorpusChangeDetails(
|
||||
$viewer,
|
||||
$old_text,
|
||||
$new_text);
|
||||
}
|
||||
|
||||
return parent::renderChangeDetails($viewer);
|
||||
public function getBaseTransactionClass() {
|
||||
return 'PhabricatorPasteTransactionType';
|
||||
}
|
||||
|
||||
public function getMailTags() {
|
||||
$tags = array();
|
||||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_TITLE:
|
||||
case self::TYPE_CONTENT:
|
||||
case self::TYPE_LANGUAGE:
|
||||
case PhabricatorPasteTitleTransaction::TRANSACTIONTYPE:
|
||||
case PhabricatorPasteContentTransaction::TRANSACTIONTYPE:
|
||||
case PhabricatorPasteLanguageTransaction::TRANSACTIONTYPE:
|
||||
$tags[] = self::MAILTAG_CONTENT;
|
||||
break;
|
||||
case PhabricatorTransactions::TYPE_COMMENT:
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorPasteContentTransaction
|
||||
extends PhabricatorPasteTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'paste.create';
|
||||
|
||||
private $fileName;
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getFilePHID();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setFilePHID($value);
|
||||
}
|
||||
|
||||
public function extractFilePHIDs($object, $value) {
|
||||
return array($value);
|
||||
}
|
||||
|
||||
public function validateTransactions($object, array $xactions) {
|
||||
if ($object->getFilePHID() || $xactions) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$error = $this->newError(
|
||||
pht('Required'),
|
||||
pht('You must provide content to create a paste.'));
|
||||
$error->setIsMissingFieldError(true);
|
||||
|
||||
return array($error);
|
||||
}
|
||||
|
||||
public function willApplyTransactions($object, array $xactions) {
|
||||
// Find the most user-friendly filename we can by examining the title of
|
||||
// the paste and the pending transactions. We'll use this if we create a
|
||||
// new file to store raw content later.
|
||||
|
||||
$name = $object->getTitle();
|
||||
if (!strlen($name)) {
|
||||
$name = 'paste.raw';
|
||||
}
|
||||
|
||||
$type_title = PhabricatorPasteTitleTransaction::TRANSACTIONTYPE;
|
||||
foreach ($xactions as $xaction) {
|
||||
if ($xaction->getTransactionType() == $type_title) {
|
||||
$name = $xaction->getNewValue();
|
||||
}
|
||||
}
|
||||
|
||||
$this->fileName = $name;
|
||||
}
|
||||
|
||||
public function generateNewValue($object, $value) {
|
||||
// If this transaction does not really change the paste content, return
|
||||
// the current file PHID so this transaction no-ops.
|
||||
$old_content = $object->getRawContent();
|
||||
if ($value === $old_content) {
|
||||
$file_phid = $object->getFilePHID();
|
||||
if ($file_phid) {
|
||||
return $file_phid;
|
||||
}
|
||||
}
|
||||
|
||||
$editor = $this->getEditor();
|
||||
$actor = $editor->getActor();
|
||||
|
||||
$file = $this->newFileForPaste($actor, $this->fileName, $value);
|
||||
|
||||
return $file->getPHID();
|
||||
}
|
||||
|
||||
private function newFileForPaste(PhabricatorUser $actor, $name, $data) {
|
||||
return PhabricatorFile::newFromFileData(
|
||||
$data,
|
||||
array(
|
||||
'name' => $name,
|
||||
'mime-type' => 'text/plain; charset=utf-8',
|
||||
'authorPHID' => $actor->getPHID(),
|
||||
'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
|
||||
'editPolicy' => PhabricatorPolicies::POLICY_NOONE,
|
||||
));
|
||||
}
|
||||
|
||||
public function getIcon() {
|
||||
return 'fa-plus';
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return pht(
|
||||
'%s edited the content of this paste.',
|
||||
$this->renderAuthor());
|
||||
}
|
||||
|
||||
public function getTitleForFeed() {
|
||||
return pht(
|
||||
'%s edited %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderObject());
|
||||
}
|
||||
|
||||
public function hasChangeDetailView() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function newChangeDetailView() {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
$files = id(new PhabricatorFileQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($old, $new))
|
||||
->execute();
|
||||
$files = mpull($files, null, 'getPHID');
|
||||
|
||||
$old_text = '';
|
||||
if (idx($files, $old)) {
|
||||
$old_text = $files[$old]->loadFileData();
|
||||
}
|
||||
|
||||
$new_text = '';
|
||||
if (idx($files, $new)) {
|
||||
$new_text = $files[$new]->loadFileData();
|
||||
}
|
||||
|
||||
return id(new PhabricatorApplicationTransactionTextDiffDetailView())
|
||||
->setViewer($viewer)
|
||||
->setOldText($old_text)
|
||||
->setNewText($new_text);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorPasteLanguageTransaction
|
||||
extends PhabricatorPasteTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'paste.language';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getLanguage();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setLanguage($value);
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return pht(
|
||||
"%s updated the paste's language.",
|
||||
$this->renderAuthor());
|
||||
}
|
||||
|
||||
public function getTitleForFeed() {
|
||||
return pht(
|
||||
'%s updated the language for %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderObject());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorPasteStatusTransaction
|
||||
extends PhabricatorPasteTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'paste.status';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getStatus();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setStatus($value);
|
||||
}
|
||||
|
||||
private function isActivate() {
|
||||
return ($this->getNewValue() == PhabricatorPaste::STATUS_ARCHIVED);
|
||||
}
|
||||
|
||||
public function getIcon() {
|
||||
if ($this->isActivate()) {
|
||||
return 'fa-check';
|
||||
} else {
|
||||
return 'fa-ban';
|
||||
}
|
||||
}
|
||||
|
||||
public function getColor() {
|
||||
if ($this->isActivate()) {
|
||||
return 'green';
|
||||
} else {
|
||||
return 'indigo';
|
||||
}
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
if ($this->isActivate()) {
|
||||
return pht(
|
||||
'%s activated this paste.',
|
||||
$this->renderAuthor());
|
||||
} else {
|
||||
return pht(
|
||||
'%s archived this paste.',
|
||||
$this->renderAuthor());
|
||||
}
|
||||
}
|
||||
|
||||
public function getTitleForFeed() {
|
||||
if ($this->isActivate()) {
|
||||
return pht(
|
||||
'%s activated %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderObject());
|
||||
} else {
|
||||
return pht(
|
||||
'%s archived %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderObject());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorPasteTitleTransaction
|
||||
extends PhabricatorPasteTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'paste.title';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getTitle();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setTitle($value);
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return pht(
|
||||
'%s updated the paste\'s title from "%s" to "%s".',
|
||||
$this->renderAuthor(),
|
||||
$this->getOldValue(),
|
||||
$this->getNewValue());
|
||||
}
|
||||
|
||||
public function getTitleForFeed() {
|
||||
return pht(
|
||||
'%s updated the title for %s from "%s" to "%s".',
|
||||
$this->renderAuthor(),
|
||||
$this->renderObject(),
|
||||
$this->getOldValue(),
|
||||
$this->getNewValue());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorPasteTransactionType
|
||||
extends PhabricatorModularTransactionType {}
|
|
@ -68,6 +68,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
private $mailCCPHIDs = array();
|
||||
private $feedNotifyPHIDs = array();
|
||||
private $feedRelatedPHIDs = array();
|
||||
private $modularTypes;
|
||||
|
||||
const STORAGE_ENCODING_BINARY = 'binary';
|
||||
|
||||
|
@ -285,6 +286,14 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
$types[] = PhabricatorTransactions::TYPE_SPACE;
|
||||
}
|
||||
|
||||
$template = $this->object->getApplicationTransactionTemplate();
|
||||
if ($template instanceof PhabricatorModularTransaction) {
|
||||
$xtypes = $template->newModularTransactionTypes();
|
||||
foreach ($xtypes as $xtype) {
|
||||
$types[] = $xtype->getTransactionTypeConstant();
|
||||
}
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
|
@ -304,7 +313,15 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
private function getTransactionOldValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
switch ($xaction->getTransactionType()) {
|
||||
|
||||
$type = $xaction->getTransactionType();
|
||||
|
||||
$xtype = $this->getModularTransactionType($type);
|
||||
if ($xtype) {
|
||||
return $xtype->generateOldValue($object);
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case PhabricatorTransactions::TYPE_CREATE:
|
||||
return null;
|
||||
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
|
||||
|
@ -374,7 +391,15 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
private function getTransactionNewValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
switch ($xaction->getTransactionType()) {
|
||||
|
||||
$type = $xaction->getTransactionType();
|
||||
|
||||
$xtype = $this->getModularTransactionType($type);
|
||||
if ($xtype) {
|
||||
return $xtype->generateNewValue($object, $xaction->getNewValue());
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case PhabricatorTransactions::TYPE_CREATE:
|
||||
return null;
|
||||
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
|
||||
|
@ -496,7 +521,14 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
$type = $xaction->getTransactionType();
|
||||
|
||||
$xtype = $this->getModularTransactionType($type);
|
||||
if ($xtype) {
|
||||
return $xtype->applyInternalEffects($object, $xaction->getNewValue());
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
|
||||
$field = $this->getCustomFieldForTransaction($object, $xaction);
|
||||
return $field->applyApplicationTransactionInternalEffects($xaction);
|
||||
|
@ -520,7 +552,15 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
private function applyExternalEffects(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
switch ($xaction->getTransactionType()) {
|
||||
|
||||
$type = $xaction->getTransactionType();
|
||||
|
||||
$xtype = $this->getModularTransactionType($type);
|
||||
if ($xtype) {
|
||||
return $xtype->applyExternalEffects($object, $xaction->getNewValue());
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
|
||||
$subeditor = id(new PhabricatorSubscriptionsEditor())
|
||||
->setObject($object)
|
||||
|
@ -802,6 +842,8 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
throw new PhabricatorApplicationTransactionValidationException($errors);
|
||||
}
|
||||
|
||||
$this->willApplyTransactions($object, $xactions);
|
||||
|
||||
if ($object->getID()) {
|
||||
foreach ($xactions as $xaction) {
|
||||
|
||||
|
@ -2006,6 +2048,12 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
array $xactions) {
|
||||
|
||||
$errors = array();
|
||||
|
||||
$xtype = $this->getModularTransactionType($type);
|
||||
if ($xtype) {
|
||||
$errors[] = $xtype->validateTransactions($object, $xactions);
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||
$errors[] = $this->validatePolicyTransaction(
|
||||
|
@ -3129,9 +3177,16 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
}
|
||||
|
||||
foreach ($xactions as $xaction) {
|
||||
$phids[] = $this->extractFilePHIDsFromCustomTransaction(
|
||||
$object,
|
||||
$xaction);
|
||||
$type = $xaction->getTransactionType();
|
||||
|
||||
$xtype = $this->getModularTransactionType($type);
|
||||
if ($xtype) {
|
||||
$phids[] = $xtype->extractFilePHIDs($object, $xaction->getNewValue());
|
||||
} else {
|
||||
$phids[] = $this->extractFilePHIDsFromCustomTransaction(
|
||||
$object,
|
||||
$xaction);
|
||||
}
|
||||
}
|
||||
|
||||
$phids = array_unique(array_filter(array_mergev($phids)));
|
||||
|
@ -3692,5 +3747,50 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
$proxy_phids);
|
||||
}
|
||||
|
||||
private function getModularTransactionTypes() {
|
||||
if ($this->modularTypes === null) {
|
||||
$template = $this->object->getApplicationTransactionTemplate();
|
||||
if ($template instanceof PhabricatorModularTransaction) {
|
||||
$xtypes = $template->newModularTransactionTypes();
|
||||
foreach ($xtypes as $key => $xtype) {
|
||||
$xtype = clone $xtype;
|
||||
$xtype->setEditor($this);
|
||||
$xtypes[$key] = $xtype;
|
||||
}
|
||||
} else {
|
||||
$xtypes = array();
|
||||
}
|
||||
|
||||
$this->modularTypes = $xtypes;
|
||||
}
|
||||
|
||||
return $this->modularTypes;
|
||||
}
|
||||
|
||||
private function getModularTransactionType($type) {
|
||||
$types = $this->getModularTransactionTypes();
|
||||
return idx($types, $type);
|
||||
}
|
||||
|
||||
private function willApplyTransactions($object, array $xactions) {
|
||||
foreach ($xactions as $xaction) {
|
||||
$type = $xaction->getTransactionType();
|
||||
|
||||
$xtype = $this->getModularTransactionType($type);
|
||||
if (!$xtype) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$xtype->willApplyTransactions($object, $xactions);
|
||||
}
|
||||
}
|
||||
|
||||
public function getCreateObjectTitle($author, $object) {
|
||||
return pht('%s created this object.', $author);
|
||||
}
|
||||
|
||||
public function getCreateObjectTitleForFeed($author, $object) {
|
||||
return pht('%s created an object: %s.', $author, $object);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -280,6 +280,7 @@ abstract class PhabricatorApplicationTransaction
|
|||
$new = $this->getNewValue();
|
||||
|
||||
$phids[] = array($this->getAuthorPHID());
|
||||
$phids[] = array($this->getObjectPHID());
|
||||
switch ($this->getTransactionType()) {
|
||||
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
|
||||
$field = $this->getTransactionCustomField();
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorModularTransaction
|
||||
extends PhabricatorApplicationTransaction {
|
||||
|
||||
private $implementation;
|
||||
|
||||
abstract public function getBaseTransactionClass();
|
||||
|
||||
final protected function getTransactionImplementation() {
|
||||
if (!$this->implementation) {
|
||||
$this->implementation = $this->newTransactionImplementation();
|
||||
}
|
||||
|
||||
return $this->implementation;
|
||||
}
|
||||
|
||||
public function newModularTransactionTypes() {
|
||||
$base_class = $this->getBaseTransactionClass();
|
||||
|
||||
$types = id(new PhutilClassMapQuery())
|
||||
->setAncestorClass($base_class)
|
||||
->setUniqueMethod('getTransactionTypeConstant')
|
||||
->execute();
|
||||
|
||||
// Add core transaction types.
|
||||
$types += id(new PhutilClassMapQuery())
|
||||
->setAncestorClass('PhabricatorCoreTransactionType')
|
||||
->setUniqueMethod('getTransactionTypeConstant')
|
||||
->execute();
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
private function newTransactionImplementation() {
|
||||
$types = $this->newModularTransactionTypes();
|
||||
|
||||
$key = $this->getTransactionType();
|
||||
|
||||
if (empty($types[$key])) {
|
||||
$type = new PhabricatorCoreVoidTransaction();
|
||||
} else {
|
||||
$type = clone $types[$key];
|
||||
}
|
||||
|
||||
$type->setStorage($this);
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
final public function generateOldValue($object) {
|
||||
return $this->getTransactionImplementation()->generateOldValue($object);
|
||||
}
|
||||
|
||||
final public function generateNewValue($object) {
|
||||
return $this->getTransactionImplementation()
|
||||
->generateNewValue($object, $this->getNewValue());
|
||||
}
|
||||
|
||||
final public function willApplyTransactions($object, array $xactions) {
|
||||
return $this->getTransactionImplementation()
|
||||
->willApplyTransactions($object, $xactions);
|
||||
}
|
||||
|
||||
final public function applyInternalEffects($object) {
|
||||
return $this->getTransactionImplementation()
|
||||
->applyInternalEffects($object);
|
||||
}
|
||||
|
||||
final public function applyExternalEffects($object) {
|
||||
return $this->getTransactionImplementation()
|
||||
->applyExternalEffects($object);
|
||||
}
|
||||
|
||||
final public function shouldHide() {
|
||||
if ($this->getTransactionImplementation()->shouldHide()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::shouldHide();
|
||||
}
|
||||
|
||||
final public function getIcon() {
|
||||
$icon = $this->getTransactionImplementation()->getIcon();
|
||||
if ($icon !== null) {
|
||||
return $icon;
|
||||
}
|
||||
|
||||
return parent::getIcon();
|
||||
}
|
||||
|
||||
final public function getTitle() {
|
||||
$title = $this->getTransactionImplementation()->getTitle();
|
||||
if ($title !== null) {
|
||||
return $title;
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
}
|
||||
|
||||
final public function getTitleForFeed() {
|
||||
$title = $this->getTransactionImplementation()->getTitleForFeed();
|
||||
if ($title !== null) {
|
||||
return $title;
|
||||
}
|
||||
|
||||
return $this->getTitle();
|
||||
}
|
||||
|
||||
final public function getColor() {
|
||||
$color = $this->getTransactionImplementation()->getColor();
|
||||
if ($color !== null) {
|
||||
return $color;
|
||||
}
|
||||
|
||||
return parent::getColor();
|
||||
}
|
||||
|
||||
final public function hasChangeDetails() {
|
||||
if ($this->getTransactionImplementation()->hasChangeDetailView()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::hasChangeDetails();
|
||||
}
|
||||
|
||||
final public function renderChangeDetails(PhabricatorUser $viewer) {
|
||||
$impl = $this->getTransactionImplementation();
|
||||
$impl->setViewer($viewer);
|
||||
$view = $impl->newChangeDetailView();
|
||||
if ($view !== null) {
|
||||
return $view;
|
||||
}
|
||||
|
||||
return parent::renderChangeDetails($viewer);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorModularTransactionType
|
||||
extends Phobject {
|
||||
|
||||
private $storage;
|
||||
private $viewer;
|
||||
private $editor;
|
||||
|
||||
final public function getTransactionTypeConstant() {
|
||||
return $this->getPhobjectClassConstant('TRANSACTIONTYPE');
|
||||
}
|
||||
|
||||
public function generateOldValue($object) {
|
||||
throw new PhutilMethodNotImplementedException();
|
||||
}
|
||||
|
||||
public function generateNewValue($object, $value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function validateTransactions($object, array $xactions) {
|
||||
return array();
|
||||
}
|
||||
|
||||
public function willApplyTransactions($object, array $xactions) {
|
||||
return;
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
return;
|
||||
}
|
||||
|
||||
public function applyExternalEffects($object, $value) {
|
||||
return;
|
||||
}
|
||||
|
||||
public function extractFilePHIDs($object, $value) {
|
||||
return array();
|
||||
}
|
||||
|
||||
public function shouldHide() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getTitleForFeed() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getColor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function hasChangeDetailView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function newChangeDetailView() {
|
||||
throw new PhutilMethodNotImplementedException();
|
||||
}
|
||||
|
||||
final public function setStorage(
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
$this->storage = $xaction;
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function getStorage() {
|
||||
return $this->storage;
|
||||
}
|
||||
|
||||
final public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
final protected function getViewer() {
|
||||
return $this->viewer;
|
||||
}
|
||||
|
||||
final public function setEditor(
|
||||
PhabricatorApplicationTransactionEditor $editor) {
|
||||
$this->editor = $editor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
final protected function getEditor() {
|
||||
if (!$this->editor) {
|
||||
throw new PhutilInvalidStateException('setEditor');
|
||||
}
|
||||
return $this->editor;
|
||||
}
|
||||
|
||||
final protected function getAuthorPHID() {
|
||||
return $this->getStorage()->getAuthorPHID();
|
||||
}
|
||||
|
||||
final protected function getObjectPHID() {
|
||||
return $this->getStorage()->getObjectPHID();
|
||||
}
|
||||
|
||||
final protected function getObject() {
|
||||
return $this->getStorage()->getObject();
|
||||
}
|
||||
|
||||
final protected function getOldValue() {
|
||||
return $this->getStorage()->getOldValue();
|
||||
}
|
||||
|
||||
final protected function getNewValue() {
|
||||
return $this->getStorage()->getNewValue();
|
||||
}
|
||||
|
||||
final protected function renderAuthor() {
|
||||
$author_phid = $this->getAuthorPHID();
|
||||
return $this->getStorage()->renderHandleLink($author_phid);
|
||||
}
|
||||
|
||||
final protected function renderObject() {
|
||||
$object_phid = $this->getObjectPHID();
|
||||
return $this->getStorage()->renderHandleLink($object_phid);
|
||||
}
|
||||
|
||||
final protected function newError($title, $message, $xaction = null) {
|
||||
return new PhabricatorApplicationTransactionValidationError(
|
||||
$this->getTransactionTypeConstant(),
|
||||
$title,
|
||||
$message,
|
||||
$xaction);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCoreCreateTransaction
|
||||
extends PhabricatorCoreTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'core:create';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
$editor = $this->getObject()->getApplicationTransactionEditor();
|
||||
|
||||
$author = $this->renderAuthor();
|
||||
$object = $this->renderObject();
|
||||
|
||||
return $editor->getCreateObjectTitle($author, $object);
|
||||
}
|
||||
|
||||
public function getTitleForFeed() {
|
||||
$editor = $this->getObject()->getApplicationTransactionEditor();
|
||||
|
||||
$author = $this->renderAuthor();
|
||||
$object = $this->renderObject();
|
||||
|
||||
return $editor->getCreateObjectTitleForFeed($author, $object);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorCoreTransactionType
|
||||
extends PhabricatorModularTransactionType {}
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorCoreVoidTransaction
|
||||
extends PhabricatorModularTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'core.void';
|
||||
|
||||
}
|
Loading…
Reference in a new issue