Index: src/__phutil_library_map__.php =================================================================== --- src/__phutil_library_map__.php +++ src/__phutil_library_map__.php @@ -2188,6 +2188,7 @@ 'PhragmentPHIDTypeFragmentVersion' => 'applications/phragment/phid/PhragmentPHIDTypeFragmentVersion.php', 'PhragmentPatchController' => 'applications/phragment/controller/PhragmentPatchController.php', 'PhragmentPatchUtil' => 'applications/phragment/util/PhragmentPatchUtil.php', + 'PhragmentRevertController' => 'applications/phragment/controller/PhragmentRevertController.php', 'PhragmentUpdateController' => 'applications/phragment/controller/PhragmentUpdateController.php', 'PhragmentVersionController' => 'applications/phragment/controller/PhragmentVersionController.php', 'PhragmentZIPController' => 'applications/phragment/controller/PhragmentZIPController.php', @@ -4790,6 +4791,7 @@ 'PhragmentPHIDTypeFragmentVersion' => 'PhabricatorPHIDType', 'PhragmentPatchController' => 'PhragmentController', 'PhragmentPatchUtil' => 'Phobject', + 'PhragmentRevertController' => 'PhragmentController', 'PhragmentUpdateController' => 'PhragmentController', 'PhragmentVersionController' => 'PhragmentController', 'PhragmentZIPController' => 'PhragmentController', Index: src/applications/phragment/application/PhabricatorApplicationPhragment.php =================================================================== --- src/applications/phragment/application/PhabricatorApplicationPhragment.php +++ src/applications/phragment/application/PhabricatorApplicationPhragment.php @@ -41,6 +41,7 @@ 'zip/(?P.*)' => 'PhragmentZIPController', 'version/(?P[0-9]*)/' => 'PhragmentVersionController', 'patch/(?P[0-9x]*)/(?P[0-9]*)/' => 'PhragmentPatchController', + 'revert/(?P[0-9]*)/(?P.*)' => 'PhragmentRevertController', ), ); } Index: src/applications/phragment/controller/PhragmentHistoryController.php =================================================================== --- src/applications/phragment/controller/PhragmentHistoryController.php +++ src/applications/phragment/controller/PhragmentHistoryController.php @@ -44,6 +44,7 @@ ->execute(); $files = mpull($files, null, 'getPHID'); + $first = true; foreach ($versions as $version) { $item = id(new PHUIObjectItemView()); $item->setHeader('Version '.$version->getSequence()); @@ -57,6 +58,16 @@ $item->addAttribute('Deletion'); } + if (!$first) { + $item->addAction(id(new PHUIListItemView()) + ->setIcon('undo') + ->setRenderNameAsTooltip(true) + ->setWorkflow(true) + ->setName(pht("Revert to Here")) + ->setHref($this->getApplicationURI( + "revert/".$version->getID()."/".$current->getPath()))); + } + $disabled = !isset($files[$version->getFilePHID()]); $action = id(new PHUIListItemView()) ->setIcon('download') @@ -68,6 +79,8 @@ } $item->addAction($action); $list->addItem($item); + + $first = false; } return $this->buildApplicationPage( Index: src/applications/phragment/controller/PhragmentRevertController.php =================================================================== --- /dev/null +++ src/applications/phragment/controller/PhragmentRevertController.php @@ -0,0 +1,87 @@ +dblob = $data['dblob']; + $this->id = $data['id']; + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $fragment = id(new PhragmentFragmentQuery()) + ->setViewer($viewer) + ->withPaths(array($this->dblob)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if ($fragment === null) { + return new Aphront404Response(); + } + + $version = id(new PhragmentFragmentVersionQuery()) + ->setViewer($viewer) + ->withFragmentPHIDs(array($fragment->getPHID())) + ->withIDs(array($this->id)) + ->executeOne(); + if ($version === null) { + return new Aphront404Response(); + } + + if ($request->isDialogFormPost()) { + $file_phid = $version->getFilePHID(); + + $file = null; + if ($file_phid !== null) { + $file = id(new PhabricatorFileQuery()) + ->setViewer($viewer) + ->withPHIDs(array($file_phid)) + ->executeOne(); + if ($file === null) { + throw new Exception( + "The file associated with this version was not found."); + } + } + + if ($file === null) { + $fragment->deleteFile($viewer); + } else { + $fragment->updateFromFile($viewer, $file); + } + + return id(new AphrontRedirectResponse()) + ->setURI($this->getApplicationURI('/history/'.$this->dblob)); + } + + return $this->createDialog($fragment, $version); + } + + function createDialog( + PhragmentFragment $fragment, + PhragmentFragmentVersion $version) { + + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $dialog = id(new AphrontDialogView()) + ->setTitle(pht('Really revert this fragment?')) + ->setUser($request->getUser()) + ->addSubmitButton(pht('Revert')) + ->addCancelButton(pht('Cancel')) + ->appendParagraph(pht( + "Reverting this fragment to version %d will create a new version of ". + "the fragment. It will not delete any version history.", + $version->getSequence(), + $version->getSequence())); + return id(new AphrontDialogResponse())->setDialog($dialog); + } + +}