From 37a5c4b11a30c35fdd2e5b0506994e035326e06f Mon Sep 17 00:00:00 2001 From: Bob Trahan Date: Fri, 2 Aug 2013 12:56:58 -0700 Subject: [PATCH] Paste - add transactions Summary: Ref T3650. This adds a create transaction, transactions for metadata (title, langauge, view policy), and comments. Editor is used on all create /edit paths. Test Plan: made some pastes via web and email - yay. edited pastes - yay. verified txns showed up on pastes and in feed correctly. Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T3516, T3650 Differential Revision: https://secure.phabricator.com/D6645 --- .../sql/patches/20130801.pastexactions.php | 46 ++++++ .../sql/patches/20130801.pastexactions.sql | 43 ++++++ src/__phutil_library_map__.php | 10 ++ .../PhabricatorApplicationMacro.php | 2 +- .../PhabricatorApplicationPaste.php | 4 + .../PhabricatorPasteCommentController.php | 73 +++++++++ .../controller/PhabricatorPasteController.php | 3 + .../PhabricatorPasteEditController.php | 71 ++++++--- .../PhabricatorPasteListController.php | 3 + .../PhabricatorPasteViewController.php | 49 +++++++ .../paste/editor/PhabricatorPasteEditor.php | 126 ++++++++++++++++ .../paste/mail/PasteCreateMailReceiver.php | 39 +++-- .../phid/PhabricatorPastePHIDTypePaste.php | 2 +- .../paste/query/PhabricatorPasteQuery.php | 3 + .../query/PhabricatorPasteSearchEngine.php | 3 + .../PhabricatorPasteTransactionQuery.php | 13 ++ .../paste/storage/PhabricatorPaste.php | 3 + .../storage/PhabricatorPasteTransaction.php | 138 ++++++++++++++++++ .../PhabricatorPasteTransactionComment.php | 20 +++ .../patch/PhabricatorBuiltinPatchList.php | 8 + 20 files changed, 620 insertions(+), 39 deletions(-) create mode 100644 resources/sql/patches/20130801.pastexactions.php create mode 100644 resources/sql/patches/20130801.pastexactions.sql create mode 100644 src/applications/paste/controller/PhabricatorPasteCommentController.php create mode 100644 src/applications/paste/editor/PhabricatorPasteEditor.php create mode 100644 src/applications/paste/query/PhabricatorPasteTransactionQuery.php create mode 100644 src/applications/paste/storage/PhabricatorPasteTransaction.php create mode 100644 src/applications/paste/storage/PhabricatorPasteTransactionComment.php diff --git a/resources/sql/patches/20130801.pastexactions.php b/resources/sql/patches/20130801.pastexactions.php new file mode 100644 index 0000000000..8d7efb4aaa --- /dev/null +++ b/resources/sql/patches/20130801.pastexactions.php @@ -0,0 +1,46 @@ +establishConnection('w'); +$conn_w->openTransaction(); + +echo "Adding transactions for existing paste objects...\n"; + +$rows = new LiskRawMigrationIterator($conn_w, 'pastebin_paste'); +foreach ($rows as $row) { + + $id = $row['id']; + echo "Adding transactions for paste id {$id}...\n"; + + $xaction_phid = PhabricatorPHID::generateNewPHID( + PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST); + + queryfx( + $conn_w, + 'INSERT INTO %T (phid, authorPHID, objectPHID, viewPolicy, editPolicy, + transactionType, oldValue, newValue, + contentSource, metadata, dateCreated, dateModified) + VALUES (%s, %s, %s, %s, %s, %s, %ns, %ns, %s, %s, %d, %d)', + $x_table->getTableName(), + $xaction_phid, + $row['authorPHID'], + $row['phid'], + 'public', + $row['authorPHID'], + PhabricatorPasteTransaction::TYPE_CREATE, + 'null', + $row['filePHID'], + PhabricatorContentSource::newForSource( + PhabricatorContentSource::SOURCE_LEGACY, + array())->serialize(), + '[]', + $row['dateCreated'], + $row['dateCreated']); + +} + +$conn_w->saveTransaction(); + +echo "Done.\n"; diff --git a/resources/sql/patches/20130801.pastexactions.sql b/resources/sql/patches/20130801.pastexactions.sql new file mode 100644 index 0000000000..23f8744b30 --- /dev/null +++ b/resources/sql/patches/20130801.pastexactions.sql @@ -0,0 +1,43 @@ +CREATE TABLE {$NAMESPACE}_pastebin.pastebin_pastetransaction ( + id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + phid VARCHAR(64) NOT NULL COLLATE utf8_bin, + authorPHID VARCHAR(64) NOT NULL COLLATE utf8_bin, + objectPHID VARCHAR(64) NOT NULL COLLATE utf8_bin, + viewPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin, + editPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin, + commentPHID VARCHAR(64) COLLATE utf8_bin, + commentVersion INT UNSIGNED NOT NULL, + transactionType VARCHAR(32) NOT NULL COLLATE utf8_bin, + oldValue LONGTEXT NOT NULL COLLATE utf8_bin, + newValue LONGTEXT NOT NULL COLLATE utf8_bin, + contentSource LONGTEXT NOT NULL COLLATE utf8_bin, + metadata LONGTEXT NOT NULL COLLATE utf8_bin, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + + UNIQUE KEY `key_phid` (phid), + KEY `key_object` (objectPHID) + +) ENGINE=InnoDB, COLLATE utf8_general_ci; + +CREATE TABLE {$NAMESPACE}_pastebin.pastebin_pastetransaction_comment ( + id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + phid VARCHAR(64) NOT NULL COLLATE utf8_bin, + transactionPHID VARCHAR(64) COLLATE utf8_bin, + authorPHID VARCHAR(64) NOT NULL COLLATE utf8_bin, + viewPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin, + editPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin, + commentVersion INT UNSIGNED NOT NULL, + content LONGTEXT NOT NULL COLLATE utf8_bin, + contentSource LONGTEXT NOT NULL COLLATE utf8_bin, + isDeleted BOOL NOT NULL, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + + lineNumber INT UNSIGNED, + lineLength INT UNSIGNED, + + UNIQUE KEY `key_phid` (phid), + UNIQUE KEY `key_version` (transactionPHID, commentVersion) + +) ENGINE=InnoDB, COLLATE utf8_general_ci; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 32d0dde37d..e0f995b679 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1364,16 +1364,21 @@ phutil_register_library_map(array( 'PhabricatorPHPMailerConfigOptions' => 'applications/config/option/PhabricatorPHPMailerConfigOptions.php', 'PhabricatorPagedFormExample' => 'applications/uiexample/examples/PhabricatorPagedFormExample.php', 'PhabricatorPaste' => 'applications/paste/storage/PhabricatorPaste.php', + 'PhabricatorPasteCommentController' => 'applications/paste/controller/PhabricatorPasteCommentController.php', 'PhabricatorPasteConfigOptions' => 'applications/paste/config/PhabricatorPasteConfigOptions.php', 'PhabricatorPasteController' => 'applications/paste/controller/PhabricatorPasteController.php', 'PhabricatorPasteDAO' => 'applications/paste/storage/PhabricatorPasteDAO.php', 'PhabricatorPasteEditController' => 'applications/paste/controller/PhabricatorPasteEditController.php', + 'PhabricatorPasteEditor' => 'applications/paste/editor/PhabricatorPasteEditor.php', 'PhabricatorPasteListController' => 'applications/paste/controller/PhabricatorPasteListController.php', 'PhabricatorPastePHIDTypePaste' => 'applications/paste/phid/PhabricatorPastePHIDTypePaste.php', 'PhabricatorPasteQuery' => 'applications/paste/query/PhabricatorPasteQuery.php', 'PhabricatorPasteRemarkupRule' => 'applications/paste/remarkup/PhabricatorPasteRemarkupRule.php', 'PhabricatorPasteSearchEngine' => 'applications/paste/query/PhabricatorPasteSearchEngine.php', 'PhabricatorPasteTestDataGenerator' => 'applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php', + 'PhabricatorPasteTransaction' => 'applications/paste/storage/PhabricatorPasteTransaction.php', + 'PhabricatorPasteTransactionComment' => 'applications/paste/storage/PhabricatorPasteTransactionComment.php', + 'PhabricatorPasteTransactionQuery' => 'applications/paste/query/PhabricatorPasteTransactionQuery.php', 'PhabricatorPasteViewController' => 'applications/paste/controller/PhabricatorPasteViewController.php', 'PhabricatorPeopleController' => 'applications/people/controller/PhabricatorPeopleController.php', 'PhabricatorPeopleEditController' => 'applications/people/controller/PhabricatorPeopleEditController.php', @@ -3406,10 +3411,12 @@ phutil_register_library_map(array( 1 => 'PhabricatorTokenReceiverInterface', 2 => 'PhabricatorPolicyInterface', ), + 'PhabricatorPasteCommentController' => 'PhabricatorPasteController', 'PhabricatorPasteConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPasteController' => 'PhabricatorController', 'PhabricatorPasteDAO' => 'PhabricatorLiskDAO', 'PhabricatorPasteEditController' => 'PhabricatorPasteController', + 'PhabricatorPasteEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorPasteListController' => array( 0 => 'PhabricatorPasteController', @@ -3420,6 +3427,9 @@ phutil_register_library_map(array( 'PhabricatorPasteRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PhabricatorPasteSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPasteTestDataGenerator' => 'PhabricatorTestDataGenerator', + 'PhabricatorPasteTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorPasteTransactionComment' => 'PhabricatorApplicationTransactionComment', + 'PhabricatorPasteTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorPasteViewController' => 'PhabricatorPasteController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleEditController' => 'PhabricatorPeopleController', diff --git a/src/applications/macro/application/PhabricatorApplicationMacro.php b/src/applications/macro/application/PhabricatorApplicationMacro.php index 2a4db531fb..fa148687d3 100644 --- a/src/applications/macro/application/PhabricatorApplicationMacro.php +++ b/src/applications/macro/application/PhabricatorApplicationMacro.php @@ -21,7 +21,7 @@ final class PhabricatorApplicationMacro extends PhabricatorApplication { public function getApplicationGroup() { return self::GROUP_UTILITIES; } - + public function getQuickCreateURI() { return $this->getBaseURI().'create/'; } diff --git a/src/applications/paste/application/PhabricatorApplicationPaste.php b/src/applications/paste/application/PhabricatorApplicationPaste.php index f09024da0c..d1181566bc 100644 --- a/src/applications/paste/application/PhabricatorApplicationPaste.php +++ b/src/applications/paste/application/PhabricatorApplicationPaste.php @@ -1,5 +1,8 @@ [^/]+)/)?' => 'PhabricatorPasteListController', 'create/' => 'PhabricatorPasteEditController', 'edit/(?P[1-9]\d*)/' => 'PhabricatorPasteEditController', + 'comment/(?P[1-9]\d*)/' => 'PhabricatorPasteCommentController', ), ); } diff --git a/src/applications/paste/controller/PhabricatorPasteCommentController.php b/src/applications/paste/controller/PhabricatorPasteCommentController.php new file mode 100644 index 0000000000..4590d6f70c --- /dev/null +++ b/src/applications/paste/controller/PhabricatorPasteCommentController.php @@ -0,0 +1,73 @@ +id = idx($data, 'id'); + } + + public function processRequest() { + $request = $this->getRequest(); + $user = $request->getUser(); + + if (!$request->isFormPost()) { + return new Aphront400Response(); + } + + $paste = id(new PhabricatorPasteQuery()) + ->setViewer($user) + ->withIDs(array($this->id)) + ->executeOne(); + if (!$paste) { + return new Aphront404Response(); + } + + $is_preview = $request->isPreviewRequest(); + $draft = PhabricatorDraft::buildFromRequest($request); + + $view_uri = $paste->getURI(); + + $xactions = array(); + $xactions[] = id(new PhabricatorPasteTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) + ->attachComment( + id(new PhabricatorPasteTransactionComment()) + ->setContent($request->getStr('comment'))); + + $editor = id(new PhabricatorPasteEditor()) + ->setActor($user) + ->setContinueOnNoEffect($request->isContinueRequest()) + ->setContentSourceFromRequest($request) + ->setIsPreview($is_preview); + + try { + $xactions = $editor->applyTransactions($paste, $xactions); + } catch (PhabricatorApplicationTransactionNoEffectException $ex) { + return id(new PhabricatorApplicationTransactionNoEffectResponse()) + ->setCancelURI($view_uri) + ->setException($ex); + } + + if ($draft) { + $draft->replaceOrDelete(); + } + + if ($request->isAjax()) { + return id(new PhabricatorApplicationTransactionResponse()) + ->setViewer($user) + ->setTransactions($xactions) + ->setIsPreview($is_preview) + ->setAnchorOffset($request->getStr('anchor')); + } else { + return id(new AphrontRedirectResponse()) + ->setURI($view_uri); + } + } + +} diff --git a/src/applications/paste/controller/PhabricatorPasteController.php b/src/applications/paste/controller/PhabricatorPasteController.php index 63a4ef3862..034d77196a 100644 --- a/src/applications/paste/controller/PhabricatorPasteController.php +++ b/src/applications/paste/controller/PhabricatorPasteController.php @@ -1,5 +1,8 @@ getFullName()); + $v_language = $parent->getLanguage(); + $v_text = $parent->getRawContent(); + } else { + $v_title = $paste->getTitle(); + $v_language = $paste->getLanguage(); + $v_text = ''; + } + $v_policy = $paste->getViewPolicy(); + if ($request->isFormPost()) { + $xactions = array(); if ($is_create) { - $text = $request->getStr('text'); - if (!strlen($text)) { + $v_text = $request->getStr('text'); + if (!strlen($v_text)) { $e_text = pht('Required'); $errors[] = pht('The paste may not be blank.'); } else { $e_text = null; } - } + } - $paste->setTitle($request->getStr('title')); - $paste->setLanguage($request->getStr('language')); - $paste->setViewPolicy($request->getStr('can_view')); + $v_title = $request->getStr('title'); + $v_language = $request->getStr('language'); + $v_policy = $request->getStr('can_view'); // NOTE: The author is the only editor and can always view the paste, // so it's impossible for them to choose an invalid policy. if (!$errors) { if ($is_create) { - $paste_file = PhabricatorFile::newFromFileData( - $text, - array( - 'name' => $paste->getTitle(), - 'mime-type' => 'text/plain; charset=utf-8', - 'authorPHID' => $user->getPHID(), - )); - $paste->setFilePHID($paste_file->getPHID()); + $xactions[] = id(new PhabricatorPasteTransaction()) + ->setTransactionType(PhabricatorPasteTransaction::TYPE_CREATE) + ->setNewValue(array( + 'title' => $v_title, + 'text' => $v_text)); } - $paste->save(); + $xactions[] = id(new PhabricatorPasteTransaction()) + ->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE) + ->setNewValue($v_title); + $xactions[] = id(new PhabricatorPasteTransaction()) + ->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE) + ->setNewValue($v_language); + $xactions[] = id(new PhabricatorPasteTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) + ->setNewValue($v_policy); + $editor = id(new PhabricatorPasteEditor()) + ->setActor($user) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true); + $xactions = $editor->applyTransactions($paste, $xactions); return id(new AphrontRedirectResponse())->setURI($paste->getURI()); - } - } else { - if ($is_create && $parent) { - $paste->setTitle(pht('Fork of %s', $parent->getFullName())); - $paste->setLanguage($parent->getLanguage()); - $text = $parent->getRawContent(); + } else { + // make sure we update policy so its correctly populated to what + // the user chose + $paste->setViewPolicy($v_policy); } } @@ -120,13 +143,13 @@ final class PhabricatorPasteEditController extends PhabricatorPasteController { ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Title')) - ->setValue($paste->getTitle()) + ->setValue($v_title) ->setName('title')) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Language')) ->setName('language') - ->setValue($paste->getLanguage()) + ->setValue($v_language) ->setOptions($langs)); $policies = id(new PhabricatorPolicyQuery()) @@ -148,7 +171,7 @@ final class PhabricatorPasteEditController extends PhabricatorPasteController { id(new AphrontFormTextAreaControl()) ->setLabel(pht('Text')) ->setError($e_text) - ->setValue($text) + ->setValue($v_text) ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL) ->setCustomClass('PhabricatorMonospaced') ->setName('text')); diff --git a/src/applications/paste/controller/PhabricatorPasteListController.php b/src/applications/paste/controller/PhabricatorPasteListController.php index 14c53a42fb..18d9d4121f 100644 --- a/src/applications/paste/controller/PhabricatorPasteListController.php +++ b/src/applications/paste/controller/PhabricatorPasteListController.php @@ -1,5 +1,8 @@ setName('P'.$paste->getID()) ->setHref('/P'.$paste->getID())); + $xactions = id(new PhabricatorPasteTransactionQuery()) + ->setViewer($request->getUser()) + ->withObjectPHIDs(array($paste->getPHID())) + ->execute(); + + $engine = id(new PhabricatorMarkupEngine()) + ->setViewer($user); + foreach ($xactions as $xaction) { + if ($xaction->getComment()) { + $engine->addObject( + $xaction->getComment(), + PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT); + } + } + $engine->process(); + + $timeline = id(new PhabricatorApplicationTransactionView()) + ->setUser($user) + ->setObjectPHID($paste->getPHID()) + ->setTransactions($xactions) + ->setMarkupEngine($engine); + + $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); + + $add_comment_header = id(new PhabricatorHeaderView()) + ->setHeader( + $is_serious + ? pht('Add Comment') + : pht('Debate Paste Accuracy')); + + $submit_button_name = $is_serious + ? pht('Add Comment') + : pht('Pity the Fool'); + + $draft = PhabricatorDraft::newFromUserAndKey($user, $paste->getPHID()); + + $add_comment_form = id(new PhabricatorApplicationTransactionCommentView()) + ->setUser($user) + ->setObjectPHID($paste->getPHID()) + ->setDraft($draft) + ->setAction($this->getApplicationURI('/comment/'.$paste->getID().'/')) + ->setSubmitButtonName($submit_button_name); + return $this->buildApplicationPage( array( $crumbs, @@ -65,6 +111,9 @@ final class PhabricatorPasteViewController extends PhabricatorPasteController { $actions, $properties, $source_code, + $timeline, + $add_comment_header, + $add_comment_form ), array( 'title' => $paste->getFullName(), diff --git a/src/applications/paste/editor/PhabricatorPasteEditor.php b/src/applications/paste/editor/PhabricatorPasteEditor.php new file mode 100644 index 0000000000..f7039dded3 --- /dev/null +++ b/src/applications/paste/editor/PhabricatorPasteEditor.php @@ -0,0 +1,126 @@ +getTransactionType()) { + case PhabricatorPasteTransaction::TYPE_CREATE: + return null; + case PhabricatorPasteTransaction::TYPE_TITLE: + return $object->getTitle(); + case PhabricatorPasteTransaction::TYPE_LANGUAGE: + return $object->getLanguage(); + } + } + + protected function getCustomTransactionNewValue( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + switch ($xaction->getTransactionType()) { + case PhabricatorPasteTransaction::TYPE_CREATE: + // this was set via applyInitialEffects + return $object->getFilePHID(); + case PhabricatorPasteTransaction::TYPE_TITLE: + case PhabricatorPasteTransaction::TYPE_LANGUAGE: + return $xaction->getNewValue(); + } + } + + protected function applyCustomInternalTransaction( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + switch ($xaction->getTransactionType()) { + case PhabricatorPasteTransaction::TYPE_TITLE: + $object->setTitle($xaction->getNewValue()); + break; + case PhabricatorPasteTransaction::TYPE_LANGUAGE: + $object->setLanguage($xaction->getNewValue()); + break; + } + } + + protected function applyCustomExternalTransaction( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + } + + + protected function shouldApplyInitialEffects( + PhabricatorLiskDAO $object, + array $xactions) { + + foreach ($xactions as $xaction) { + if ($xaction->getTransactionType() == + PhabricatorPasteTransaction::TYPE_CREATE) { + return true; + } + } + return false; + } + + protected function applyInitialEffects( + PhabricatorLiskDAO $object, + array $xactions) { + + foreach ($xactions as $xaction) { + switch ($xaction->getTransactionType()) { + case PhabricatorPasteTransaction::TYPE_CREATE: + $data = $xaction->getNewValue(); + $paste_file = PhabricatorFile::newFromFileData( + $data['text'], + array( + 'name' => $data['title'], + 'mime-type' => 'text/plain; charset=utf-8', + 'authorPHID' => $this->getActor()->getPHID(), + )); + $object->setFilePHID($paste_file->getPHID()); + break; + } + } + } + + protected function supportsMail() { + return false; + } + + protected function getMailTo(PhabricatorLiskDAO $object) { + return array( + $object->getAuthorPHID(), + $this->requireActor()->getPHID(), + ); + } + + protected function getMailCC(PhabricatorLiskDAO $object) { + return array(); + } + + protected function supportsFeed() { + return true; + } + + protected function supportsSearch() { + return false; + } + +} diff --git a/src/applications/paste/mail/PasteCreateMailReceiver.php b/src/applications/paste/mail/PasteCreateMailReceiver.php index ef8b0236e5..b55a554575 100644 --- a/src/applications/paste/mail/PasteCreateMailReceiver.php +++ b/src/applications/paste/mail/PasteCreateMailReceiver.php @@ -35,21 +35,34 @@ final class PasteCreateMailReceiver if (!$title) { $title = pht('Pasted via email.'); } - $paste_file = PhabricatorFile::newFromFileData( - $mail->getCleanTextBody(), - array( - 'name' => $title, - 'mime-type' => 'text/plain; charset=utf-8', - 'authorPHID' => $sender->getPHID(), - )); + $xactions = array(); + $xactions[] = id(new PhabricatorPasteTransaction()) + ->setTransactionType(PhabricatorPasteTransaction::TYPE_CREATE) + ->setNewValue(array( + 'title' => $title, + 'text' => $mail->getCleanTextBody())); + $xactions[] = id(new PhabricatorPasteTransaction()) + ->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE) + ->setNewValue($title); + $xactions[] = id(new PhabricatorPasteTransaction()) + ->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE) + ->setNewValue(''); // auto-detect + $xactions[] = id(new PhabricatorPasteTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) + ->setNewValue(PhabricatorPolicies::POLICY_USER); $paste = id(new PhabricatorPaste()) - ->setAuthorPHID($sender->getPHID()) - ->setTitle($title) - ->setFilePHID($paste_file->getPHID()) - ->setLanguage('') // auto-detect - ->setViewPolicy(PhabricatorPolicies::POLICY_USER) - ->save(); + ->setAuthorPHID($sender->getPHID()); + $content_source = PhabricatorContentSource::newForSource( + PhabricatorContentSource::SOURCE_EMAIL, + array( + 'id' => $mail->getID(), + )); + $editor = id(new PhabricatorPasteEditor()) + ->setActor($sender) + ->setContentSource($content_source) + ->setContinueOnNoEffect(true); + $xactions = $editor->applyTransactions($paste, $xactions); $mail->setRelatedPHID($paste->getPHID()); diff --git a/src/applications/paste/phid/PhabricatorPastePHIDTypePaste.php b/src/applications/paste/phid/PhabricatorPastePHIDTypePaste.php index 49bd60afda..8e068f23cb 100644 --- a/src/applications/paste/phid/PhabricatorPastePHIDTypePaste.php +++ b/src/applications/paste/phid/PhabricatorPastePHIDTypePaste.php @@ -38,7 +38,7 @@ final class PhabricatorPastePHIDTypePaste extends PhabricatorPHIDType { $name = $paste->getFullName(); $handle->setName("P{$id}"); - $handle->setFullName("P{$id}: {$name}"); + $handle->setFullName($name); $handle->setURI("/P{$id}"); } } diff --git a/src/applications/paste/query/PhabricatorPasteQuery.php b/src/applications/paste/query/PhabricatorPasteQuery.php index d0aaac75a9..5b3c08be73 100644 --- a/src/applications/paste/query/PhabricatorPasteQuery.php +++ b/src/applications/paste/query/PhabricatorPasteQuery.php @@ -1,5 +1,8 @@ getTransactionType()) { + case self::TYPE_CREATE: + $phids[] = $this->getObjectPHID(); + break; + } + + return $phids; + } + + public function shouldHide() { + $old = $this->getOldValue(); + switch ($this->getTransactionType()) { + case self::TYPE_TITLE: + case self::TYPE_LANGUAGE: + return $old === null; + } + return parent::shouldHide(); + } + + public function getIcon() { + switch ($this->getTransactionType()) { + case self::TYPE_CREATE: + return 'create'; + break; + case self::TYPE_TITLE: + case self::TYPE_LANGUAGE: + return 'edit'; + 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 PhabricatorPasteTransaction::TYPE_CREATE: + return pht( + '%s created "%s".', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + break; + case PhabricatorPasteTransaction::TYPE_TITLE: + return pht( + '%s updated the paste\'s title to "%s".', + $this->renderHandleLink($author_phid), + $new); + break; + case PhabricatorPasteTransaction::TYPE_LANGUAGE: + return pht( + "%s updated the paste's language.", + $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 PhabricatorPasteTransaction::TYPE_CREATE: + return pht( + '%s created %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + break; + case PhabricatorPasteTransaction::TYPE_TITLE: + return pht( + '%s updated the title for %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + break; + case PhabricatorPasteTransaction::TYPE_LANGUAGE: + return pht( + '%s update the language for %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 PhabricatorPasteTransaction::TYPE_CREATE: + return PhabricatorTransactions::COLOR_GREEN; + } + + return parent::getColor(); + } +} diff --git a/src/applications/paste/storage/PhabricatorPasteTransactionComment.php b/src/applications/paste/storage/PhabricatorPasteTransactionComment.php new file mode 100644 index 0000000000..86655e060e --- /dev/null +++ b/src/applications/paste/storage/PhabricatorPasteTransactionComment.php @@ -0,0 +1,20 @@ +getTransactionPHID() != null); + } +} diff --git a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php index d74e42f241..dc38ef7443 100644 --- a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php +++ b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php @@ -1499,6 +1499,14 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList { 'type' => 'php', 'name' => $this->getPatchPath('20130728.ponderxcomment.php'), ), + '20130801.pastexactions.sql' => array( + 'type' => 'sql', + 'name' => $this->getPatchPath('20130801.pastexactions.sql'), + ), + '20130801.pastexactions.php' => array( + 'type' => 'php', + 'name' => $this->getPatchPath('20130801.pastexactions.php'), + ), ); } }