diff --git a/resources/sql/patches/20130801.pastexactions.php b/resources/sql/patches/20130801.pastexactions.php --- a/resources/sql/patches/20130801.pastexactions.php +++ b/resources/sql/patches/20130801.pastexactions.php @@ -1,47 +1,5 @@ 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. diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2160,6 +2160,9 @@ '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 @@ '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 @@ '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 @@ '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 @@ 'PhabricatorController' => 'AphrontController', 'PhabricatorCookies' => 'Phobject', 'PhabricatorCoreConfigOptions' => 'PhabricatorApplicationConfigOptions', + 'PhabricatorCoreCreateTransaction' => 'PhabricatorCoreTransactionType', + 'PhabricatorCoreTransactionType' => 'PhabricatorModularTransactionType', + 'PhabricatorCoreVoidTransaction' => 'PhabricatorModularTransactionType', 'PhabricatorCountdown' => array( 'PhabricatorCountdownDAO', 'PhabricatorPolicyInterface', @@ -7406,6 +7419,8 @@ 'PhabricatorMetaMTASendGridReceiveController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAWorker' => 'PhabricatorWorker', 'PhabricatorMetronomicTriggerClock' => 'PhabricatorTriggerClock', + 'PhabricatorModularTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorModularTransactionType' => 'Phobject', 'PhabricatorMonospacedFontSetting' => 'PhabricatorStringSetting', 'PhabricatorMonospacedTextareasSetting' => 'PhabricatorSelectSetting', 'PhabricatorMotivatorProfilePanel' => 'PhabricatorProfilePanel', @@ -7601,12 +7616,14 @@ '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 @@ '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', diff --git a/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php b/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php --- a/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php +++ b/src/applications/paste/conduit/PasteCreateConduitAPIMethod.php @@ -47,15 +47,15 @@ $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()) diff --git a/src/applications/paste/controller/PhabricatorPasteArchiveController.php b/src/applications/paste/controller/PhabricatorPasteArchiveController.php --- a/src/applications/paste/controller/PhabricatorPasteArchiveController.php +++ b/src/applications/paste/controller/PhabricatorPasteArchiveController.php @@ -20,7 +20,7 @@ return new Aphront404Response(); } - $view_uri = '/P'.$paste->getID(); + $view_uri = $paste->getURI(); if ($request->isFormPost()) { if ($paste->isArchived()) { @@ -32,7 +32,7 @@ $xactions = array(); $xactions[] = id(new PhabricatorPasteTransaction()) - ->setTransactionType(PhabricatorPasteTransaction::TYPE_STATUS) + ->setTransactionType(PhabricatorPasteStatusTransaction::TRANSACTIONTYPE) ->setNewValue($new_status); id(new PhabricatorPasteEditor()) diff --git a/src/applications/paste/editor/PhabricatorPasteEditEngine.php b/src/applications/paste/editor/PhabricatorPasteEditEngine.php --- a/src/applications/paste/editor/PhabricatorPasteEditEngine.php +++ b/src/applications/paste/editor/PhabricatorPasteEditEngine.php @@ -71,7 +71,7 @@ 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 @@ 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 @@ 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 @@ 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.')) diff --git a/src/applications/paste/editor/PhabricatorPasteEditor.php b/src/applications/paste/editor/PhabricatorPasteEditor.php --- a/src/applications/paste/editor/PhabricatorPasteEditor.php +++ b/src/applications/paste/editor/PhabricatorPasteEditor.php @@ -3,8 +3,6 @@ final class PhabricatorPasteEditor extends PhabricatorApplicationTransactionEditor { - private $fileName; - public function getEditorApplicationClass() { return 'PhabricatorPasteApplication'; } @@ -13,29 +11,17 @@ 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 @@ 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( + protected function shouldSendMail( 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; + if ($this->getIsNewObject()) { + return false; } - 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; - } - } return true; } @@ -258,8 +95,4 @@ return true; } - protected function supportsSearch() { - return false; - } - } diff --git a/src/applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php b/src/applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php --- a/src/applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php +++ b/src/applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php @@ -17,15 +17,15 @@ $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()) diff --git a/src/applications/paste/mail/PasteCreateMailReceiver.php b/src/applications/paste/mail/PasteCreateMailReceiver.php --- a/src/applications/paste/mail/PasteCreateMailReceiver.php +++ b/src/applications/paste/mail/PasteCreateMailReceiver.php @@ -24,17 +24,13 @@ $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(); diff --git a/src/applications/paste/storage/PhabricatorPasteTransaction.php b/src/applications/paste/storage/PhabricatorPasteTransaction.php --- a/src/applications/paste/storage/PhabricatorPasteTransaction.php +++ b/src/applications/paste/storage/PhabricatorPasteTransaction.php @@ -1,12 +1,7 @@ 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: diff --git a/src/applications/paste/xaction/PhabricatorPasteContentTransaction.php b/src/applications/paste/xaction/PhabricatorPasteContentTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/paste/xaction/PhabricatorPasteContentTransaction.php @@ -0,0 +1,135 @@ +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); + } + +} diff --git a/src/applications/paste/xaction/PhabricatorPasteLanguageTransaction.php b/src/applications/paste/xaction/PhabricatorPasteLanguageTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/paste/xaction/PhabricatorPasteLanguageTransaction.php @@ -0,0 +1,29 @@ +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()); + } + +} diff --git a/src/applications/paste/xaction/PhabricatorPasteStatusTransaction.php b/src/applications/paste/xaction/PhabricatorPasteStatusTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/paste/xaction/PhabricatorPasteStatusTransaction.php @@ -0,0 +1,62 @@ +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()); + } + } + +} diff --git a/src/applications/paste/xaction/PhabricatorPasteTitleTransaction.php b/src/applications/paste/xaction/PhabricatorPasteTitleTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/paste/xaction/PhabricatorPasteTitleTransaction.php @@ -0,0 +1,33 @@ +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()); + } + +} diff --git a/src/applications/paste/xaction/PhabricatorPasteTransactionType.php b/src/applications/paste/xaction/PhabricatorPasteTransactionType.php new file mode 100644 --- /dev/null +++ b/src/applications/paste/xaction/PhabricatorPasteTransactionType.php @@ -0,0 +1,4 @@ +object->getApplicationTransactionTemplate(); + if ($template instanceof PhabricatorModularTransaction) { + $xtypes = $template->newModularTransactionTypes(); + foreach ($xtypes as $xtype) { + $types[] = $xtype->getTransactionTypeConstant(); + } + } + return $types; } @@ -304,7 +313,15 @@ 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 @@ 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 @@ 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 @@ 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 @@ throw new PhabricatorApplicationTransactionValidationException($errors); } + $this->willApplyTransactions($object, $xactions); + if ($object->getID()) { foreach ($xactions as $xaction) { @@ -2006,6 +2048,12 @@ 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 @@ } 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 @@ $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); + } } diff --git a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php --- a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php +++ b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php @@ -280,6 +280,7 @@ $new = $this->getNewValue(); $phids[] = array($this->getAuthorPHID()); + $phids[] = array($this->getObjectPHID()); switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getTransactionCustomField(); diff --git a/src/applications/transactions/storage/PhabricatorModularTransaction.php b/src/applications/transactions/storage/PhabricatorModularTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/transactions/storage/PhabricatorModularTransaction.php @@ -0,0 +1,138 @@ +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); + } + +} diff --git a/src/applications/transactions/storage/PhabricatorModularTransactionType.php b/src/applications/transactions/storage/PhabricatorModularTransactionType.php new file mode 100644 --- /dev/null +++ b/src/applications/transactions/storage/PhabricatorModularTransactionType.php @@ -0,0 +1,140 @@ +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); + } + +} diff --git a/src/applications/transactions/xaction/PhabricatorCoreCreateTransaction.php b/src/applications/transactions/xaction/PhabricatorCoreCreateTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/transactions/xaction/PhabricatorCoreCreateTransaction.php @@ -0,0 +1,30 @@ +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); + } + +} diff --git a/src/applications/transactions/xaction/PhabricatorCoreTransactionType.php b/src/applications/transactions/xaction/PhabricatorCoreTransactionType.php new file mode 100644 --- /dev/null +++ b/src/applications/transactions/xaction/PhabricatorCoreTransactionType.php @@ -0,0 +1,4 @@ +