@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Implement "Revert to Version" functionality in Phragment

Summary:
This functionality allows users to revert a fragment to a previous version from the history page.

Reverting a version actually creates a new version pointing at the same file as the version being "reverted" to. In this sense it acts pretty much like Git and other distributed VCS where once you have published a commit the only way to undo your changes is to create a new commit that reverts those changes.

Test Plan: Reverted a fragment to a version before it was deleted, then reverted it to when it was deleted and saw the new versions have the correct file PHIDs (including null for the deletion).

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley

CC: Korvin, epriestley, aran

Maniphest Tasks: T4205

Differential Revision: https://secure.phabricator.com/D7738

+103
+2
src/__phutil_library_map__.php
··· 2188 2188 'PhragmentPHIDTypeFragmentVersion' => 'applications/phragment/phid/PhragmentPHIDTypeFragmentVersion.php', 2189 2189 'PhragmentPatchController' => 'applications/phragment/controller/PhragmentPatchController.php', 2190 2190 'PhragmentPatchUtil' => 'applications/phragment/util/PhragmentPatchUtil.php', 2191 + 'PhragmentRevertController' => 'applications/phragment/controller/PhragmentRevertController.php', 2191 2192 'PhragmentUpdateController' => 'applications/phragment/controller/PhragmentUpdateController.php', 2192 2193 'PhragmentVersionController' => 'applications/phragment/controller/PhragmentVersionController.php', 2193 2194 'PhragmentZIPController' => 'applications/phragment/controller/PhragmentZIPController.php', ··· 4790 4791 'PhragmentPHIDTypeFragmentVersion' => 'PhabricatorPHIDType', 4791 4792 'PhragmentPatchController' => 'PhragmentController', 4792 4793 'PhragmentPatchUtil' => 'Phobject', 4794 + 'PhragmentRevertController' => 'PhragmentController', 4793 4795 'PhragmentUpdateController' => 'PhragmentController', 4794 4796 'PhragmentVersionController' => 'PhragmentController', 4795 4797 'PhragmentZIPController' => 'PhragmentController',
+1
src/applications/phragment/application/PhabricatorApplicationPhragment.php
··· 41 41 'zip/(?P<dblob>.*)' => 'PhragmentZIPController', 42 42 'version/(?P<id>[0-9]*)/' => 'PhragmentVersionController', 43 43 'patch/(?P<aid>[0-9x]*)/(?P<bid>[0-9]*)/' => 'PhragmentPatchController', 44 + 'revert/(?P<id>[0-9]*)/(?P<dblob>.*)' => 'PhragmentRevertController', 44 45 ), 45 46 ); 46 47 }
+13
src/applications/phragment/controller/PhragmentHistoryController.php
··· 44 44 ->execute(); 45 45 $files = mpull($files, null, 'getPHID'); 46 46 47 + $first = true; 47 48 foreach ($versions as $version) { 48 49 $item = id(new PHUIObjectItemView()); 49 50 $item->setHeader('Version '.$version->getSequence()); ··· 57 58 $item->addAttribute('Deletion'); 58 59 } 59 60 61 + if (!$first) { 62 + $item->addAction(id(new PHUIListItemView()) 63 + ->setIcon('undo') 64 + ->setRenderNameAsTooltip(true) 65 + ->setWorkflow(true) 66 + ->setName(pht("Revert to Here")) 67 + ->setHref($this->getApplicationURI( 68 + "revert/".$version->getID()."/".$current->getPath()))); 69 + } 70 + 60 71 $disabled = !isset($files[$version->getFilePHID()]); 61 72 $action = id(new PHUIListItemView()) 62 73 ->setIcon('download') ··· 68 79 } 69 80 $item->addAction($action); 70 81 $list->addItem($item); 82 + 83 + $first = false; 71 84 } 72 85 73 86 return $this->buildApplicationPage(
+87
src/applications/phragment/controller/PhragmentRevertController.php
··· 1 + <?php 2 + 3 + final class PhragmentRevertController extends PhragmentController { 4 + 5 + private $dblob; 6 + private $id; 7 + 8 + public function willProcessRequest(array $data) { 9 + $this->dblob = $data['dblob']; 10 + $this->id = $data['id']; 11 + } 12 + 13 + public function processRequest() { 14 + $request = $this->getRequest(); 15 + $viewer = $request->getUser(); 16 + 17 + $fragment = id(new PhragmentFragmentQuery()) 18 + ->setViewer($viewer) 19 + ->withPaths(array($this->dblob)) 20 + ->requireCapabilities( 21 + array( 22 + PhabricatorPolicyCapability::CAN_VIEW, 23 + PhabricatorPolicyCapability::CAN_EDIT, 24 + )) 25 + ->executeOne(); 26 + if ($fragment === null) { 27 + return new Aphront404Response(); 28 + } 29 + 30 + $version = id(new PhragmentFragmentVersionQuery()) 31 + ->setViewer($viewer) 32 + ->withFragmentPHIDs(array($fragment->getPHID())) 33 + ->withIDs(array($this->id)) 34 + ->executeOne(); 35 + if ($version === null) { 36 + return new Aphront404Response(); 37 + } 38 + 39 + if ($request->isDialogFormPost()) { 40 + $file_phid = $version->getFilePHID(); 41 + 42 + $file = null; 43 + if ($file_phid !== null) { 44 + $file = id(new PhabricatorFileQuery()) 45 + ->setViewer($viewer) 46 + ->withPHIDs(array($file_phid)) 47 + ->executeOne(); 48 + if ($file === null) { 49 + throw new Exception( 50 + "The file associated with this version was not found."); 51 + } 52 + } 53 + 54 + if ($file === null) { 55 + $fragment->deleteFile($viewer); 56 + } else { 57 + $fragment->updateFromFile($viewer, $file); 58 + } 59 + 60 + return id(new AphrontRedirectResponse()) 61 + ->setURI($this->getApplicationURI('/history/'.$this->dblob)); 62 + } 63 + 64 + return $this->createDialog($fragment, $version); 65 + } 66 + 67 + function createDialog( 68 + PhragmentFragment $fragment, 69 + PhragmentFragmentVersion $version) { 70 + 71 + $request = $this->getRequest(); 72 + $viewer = $request->getUser(); 73 + 74 + $dialog = id(new AphrontDialogView()) 75 + ->setTitle(pht('Really revert this fragment?')) 76 + ->setUser($request->getUser()) 77 + ->addSubmitButton(pht('Revert')) 78 + ->addCancelButton(pht('Cancel')) 79 + ->appendParagraph(pht( 80 + "Reverting this fragment to version %d will create a new version of ". 81 + "the fragment. It will not delete any version history.", 82 + $version->getSequence(), 83 + $version->getSequence())); 84 + return id(new AphrontDialogResponse())->setDialog($dialog); 85 + } 86 + 87 + }