diff --git a/resources/sql/patches/063.pasteforks.sql b/resources/sql/patches/063.pasteforks.sql new file mode 100644 index 0000000000..d2fb7430bc --- /dev/null +++ b/resources/sql/patches/063.pasteforks.sql @@ -0,0 +1,3 @@ +ALTER TABLE phabricator_pastebin.pastebin_paste + ADD COLUMN parentPHID VARCHAR(64) BINARY, + ADD KEY (parentPHID); \ No newline at end of file diff --git a/src/applications/paste/controller/create/PhabricatorPasteCreateController.php b/src/applications/paste/controller/create/PhabricatorPasteCreateController.php index 5fb13d950c..27aa6ef28a 100644 --- a/src/applications/paste/controller/create/PhabricatorPasteCreateController.php +++ b/src/applications/paste/controller/create/PhabricatorPasteCreateController.php @@ -27,19 +27,16 @@ class PhabricatorPasteCreateController extends PhabricatorPasteController { $error_view = null; $e_text = true; + $fork = $request->getInt('fork'); + $paste_text = null; + $paste_parent = null; + if ($request->isFormPost()) { $errors = array(); $title = $request->getStr('title'); - $language = $request->getStr('language'); - if ($language == 'infer') { - // If it's infer, store an empty string. Otherwise, store the - // language name. We do this so we can refer to 'infer' elsewhere - // in the code (such as default value) while retaining backwards - // compatibility with old posts with no language stored. - $language = ''; - } + $paste_language = $request->getStr('language'); $text = $request->getStr('text'); @@ -50,10 +47,26 @@ class PhabricatorPasteCreateController extends PhabricatorPasteController { $e_text = null; } + $parent = id(new PhabricatorPaste())->loadOneWhere( + 'phid = %s', + $request->getStr('parent')); + + if ($parent) { + $paste->setParentPHID($parent->getPHID()); + } + $paste->setTitle($title); - $paste->setLanguage($language); if (!$errors) { + if ($paste_language == 'infer') { + // If it's infer, store an empty string. Otherwise, store the + // language name. We do this so we can refer to 'infer' elsewhere + // in the code (such as default value) while retaining backwards + // compatibility with old posts with no language stored. + $paste_language = ''; + } + $paste->setLanguage($paste_language); + $paste_file = PhabricatorFile::newFromFileData( $text, array( @@ -73,31 +86,26 @@ class PhabricatorPasteCreateController extends PhabricatorPasteController { $error_view->setTitle('A problem has occurred!'); } } else { - $copy = $request->getInt('copy'); - if ($copy) { - $copy_paste = id(new PhabricatorPaste())->load($copy); - if ($copy_paste) { - $title = nonempty($copy_paste->getTitle(), 'P'.$copy_paste->getID()); - $paste->setTitle('Copy of '.$title); - $copy_file = id(new PhabricatorFile())->loadOneWhere( + if ($fork) { + $fork_paste = id(new PhabricatorPaste())->load($fork); + if ($fork_paste) { + $paste->setTitle('Fork of '.$fork_paste->getID().': '. + $fork_paste->getTitle()); + $fork_file = id(new PhabricatorFile())->loadOneWhere( 'phid = %s', - $copy_paste->getFilePHID()); - $paste_text = $copy_file->loadFileData(); + $fork_paste->getFilePHID()); + $paste_text = $fork_file->loadFileData(); + $paste_language = nonempty($fork_paste->getLanguage(), 'infer'); + $paste_parent = $fork_paste->getPHID(); } + } else { + $paste_language = PhabricatorEnv::getEnvConfig( + 'pygments.dropdown-default'); } } $form = new AphrontFormView(); - // If we're coming back from an error and the language was already defined, - // use that. Otherwise, ask the config for the default. - if ($paste->getLanguage()) { - $language_default = $paste->getLanguage(); - } else { - $language_default = PhabricatorEnv::getEnvConfig( - 'pygments.dropdown-default'); - } - $available_languages = PhabricatorEnv::getEnvConfig( 'pygments.dropdown-choices'); asort($available_languages); @@ -105,12 +113,13 @@ class PhabricatorPasteCreateController extends PhabricatorPasteController { $language_select = id(new AphrontFormSelectControl()) ->setLabel('Language') ->setName('language') - ->setValue($language_default) + ->setValue($paste_language) ->setOptions($available_languages); $form ->setUser($user) ->setAction($request->getRequestURI()->getPath()) + ->addHiddenInput('parent', $paste_parent) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Title') @@ -127,7 +136,7 @@ class PhabricatorPasteCreateController extends PhabricatorPasteController { ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton('/paste/') - ->setValue('Create Paste')); + ->setValue('Create Paste')); $panel = new AphrontPanelView(); $panel->setWidth(AphrontPanelView::WIDTH_FORM); diff --git a/src/applications/paste/controller/view/PhabricatorPasteViewController.php b/src/applications/paste/controller/view/PhabricatorPasteViewController.php index 90816f9de7..a02e0b30af 100644 --- a/src/applications/paste/controller/view/PhabricatorPasteViewController.php +++ b/src/applications/paste/controller/view/PhabricatorPasteViewController.php @@ -42,7 +42,6 @@ class PhabricatorPasteViewController extends PhabricatorPasteController { } $corpus = $this->buildCorpus($paste, $file); - $panel = new AphrontPanelView(); if (strlen($paste->getTitle())) { @@ -58,10 +57,10 @@ class PhabricatorPasteViewController extends PhabricatorPasteController { phutil_render_tag( 'a', array( - 'href' => '/paste/?copy='.$paste->getID(), + 'href' => '/paste/?fork='.$paste->getID(), 'class' => 'green button', ), - 'Copy This')); + 'Fork This')); $raw_uri = PhabricatorFileURI::getViewURIForPHID($paste->getFilePHID()); $panel->addButton( @@ -75,6 +74,37 @@ class PhabricatorPasteViewController extends PhabricatorPasteController { $panel->appendChild($corpus); + $forks_of_this_paste = id(new PhabricatorPaste())->loadAllWhere( + 'parentPHID = %s', + $paste->getPHID()); + + if ($forks_of_this_paste) { + $forks = array(); + foreach ($forks_of_this_paste as $fork) { + $forks[] = array( + $fork->getID(), + phutil_render_tag( + 'a', + array( + 'href' => '/P'.$fork->getID(), + ), + phutil_escape_html($fork->getTitle()) + ) + ); + } + + $forks_table = new AphrontTableView($forks); + $forks_table->setHeaders( + array( + 'Paste ID', + 'Title', + ) + ); + + $panel->setHeader("Forks of this Paste"); + $panel->appendChild($forks_table); + } + return $this->buildStandardPageResponse( $panel, array( diff --git a/src/applications/paste/controller/view/__init__.php b/src/applications/paste/controller/view/__init__.php index 527fc99e51..a148c94e13 100644 --- a/src/applications/paste/controller/view/__init__.php +++ b/src/applications/paste/controller/view/__init__.php @@ -14,6 +14,7 @@ phutil_require_module('phabricator', 'applications/markup/syntax'); phutil_require_module('phabricator', 'applications/paste/controller/base'); phutil_require_module('phabricator', 'applications/paste/storage/paste'); phutil_require_module('phabricator', 'infrastructure/celerity/api'); +phutil_require_module('phabricator', 'view/control/table'); phutil_require_module('phabricator', 'view/layout/panel'); phutil_require_module('phutil', 'markup'); diff --git a/src/applications/paste/storage/paste/PhabricatorPaste.php b/src/applications/paste/storage/paste/PhabricatorPaste.php index 4edeea81ea..c7a75f0669 100644 --- a/src/applications/paste/storage/paste/PhabricatorPaste.php +++ b/src/applications/paste/storage/paste/PhabricatorPaste.php @@ -23,6 +23,7 @@ class PhabricatorPaste extends PhabricatorPasteDAO { protected $authorPHID; protected $filePHID; protected $language; + protected $parentPHID; public function getConfiguration() { return array(