mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 16:22:43 +01:00
Implement snapshots in Phragment
Summary: Ref T4212. This implements snapshots in Phragment, which allows you to take a snapshot of a fragment at a given point in time, and download a ZIP of the snapshot as it was in this state. There's also functionality for deleting and promoting snapshots. You can promote a snapshot to either the latest version or any other snapshot of the fragment. Test Plan: Clicked around, took some snapshots, promoted them to different points and deleted snapshots. Also downloaded ZIPs of the snapshots and saw the right versions coming through for all the files downloaded. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley CC: Korvin, epriestley, aran Maniphest Tasks: T4205, T4212 Differential Revision: https://secure.phabricator.com/D7741
This commit is contained in:
parent
e165787725
commit
8bb6e807f0
20 changed files with 1151 additions and 9 deletions
21
resources/sql/patches/20131208.phragmentsnapshot.sql
Normal file
21
resources/sql/patches/20131208.phragmentsnapshot.sql
Normal file
|
@ -0,0 +1,21 @@
|
|||
CREATE TABLE {$NAMESPACE}_phragment.phragment_snapshot (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
phid VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
primaryFragmentPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
name VARCHAR(192) NOT NULL COLLATE utf8_bin,
|
||||
description LONGTEXT NULL COLLATE utf8_bin,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL,
|
||||
UNIQUE KEY `key_phid` (phid),
|
||||
UNIQUE KEY `key_name` (primaryFragmentPHID, name)
|
||||
) ENGINE=InnoDB, COLLATE utf8_general_ci;
|
||||
|
||||
CREATE TABLE {$NAMESPACE}_phragment.phragment_snapshotchild (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
snapshotPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
fragmentPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
fragmentVersionPHID VARCHAR(64) NULL COLLATE utf8_bin,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL,
|
||||
UNIQUE KEY `key_child` (snapshotPHID, fragmentPHID, fragmentVersionPHID)
|
||||
) ENGINE=InnoDB, COLLATE utf8_general_ci;
|
|
@ -2186,9 +2186,18 @@ phutil_register_library_map(array(
|
|||
'PhragmentHistoryController' => 'applications/phragment/controller/PhragmentHistoryController.php',
|
||||
'PhragmentPHIDTypeFragment' => 'applications/phragment/phid/PhragmentPHIDTypeFragment.php',
|
||||
'PhragmentPHIDTypeFragmentVersion' => 'applications/phragment/phid/PhragmentPHIDTypeFragmentVersion.php',
|
||||
'PhragmentPHIDTypeSnapshot' => 'applications/phragment/phid/PhragmentPHIDTypeSnapshot.php',
|
||||
'PhragmentPatchController' => 'applications/phragment/controller/PhragmentPatchController.php',
|
||||
'PhragmentPatchUtil' => 'applications/phragment/util/PhragmentPatchUtil.php',
|
||||
'PhragmentRevertController' => 'applications/phragment/controller/PhragmentRevertController.php',
|
||||
'PhragmentSnapshot' => 'applications/phragment/storage/PhragmentSnapshot.php',
|
||||
'PhragmentSnapshotChild' => 'applications/phragment/storage/PhragmentSnapshotChild.php',
|
||||
'PhragmentSnapshotChildQuery' => 'applications/phragment/query/PhragmentSnapshotChildQuery.php',
|
||||
'PhragmentSnapshotCreateController' => 'applications/phragment/controller/PhragmentSnapshotCreateController.php',
|
||||
'PhragmentSnapshotDeleteController' => 'applications/phragment/controller/PhragmentSnapshotDeleteController.php',
|
||||
'PhragmentSnapshotPromoteController' => 'applications/phragment/controller/PhragmentSnapshotPromoteController.php',
|
||||
'PhragmentSnapshotQuery' => 'applications/phragment/query/PhragmentSnapshotQuery.php',
|
||||
'PhragmentSnapshotViewController' => 'applications/phragment/controller/PhragmentSnapshotViewController.php',
|
||||
'PhragmentUpdateController' => 'applications/phragment/controller/PhragmentUpdateController.php',
|
||||
'PhragmentVersionController' => 'applications/phragment/controller/PhragmentVersionController.php',
|
||||
'PhragmentZIPController' => 'applications/phragment/controller/PhragmentZIPController.php',
|
||||
|
@ -4789,9 +4798,26 @@ phutil_register_library_map(array(
|
|||
'PhragmentHistoryController' => 'PhragmentController',
|
||||
'PhragmentPHIDTypeFragment' => 'PhabricatorPHIDType',
|
||||
'PhragmentPHIDTypeFragmentVersion' => 'PhabricatorPHIDType',
|
||||
'PhragmentPHIDTypeSnapshot' => 'PhabricatorPHIDType',
|
||||
'PhragmentPatchController' => 'PhragmentController',
|
||||
'PhragmentPatchUtil' => 'Phobject',
|
||||
'PhragmentRevertController' => 'PhragmentController',
|
||||
'PhragmentSnapshot' =>
|
||||
array(
|
||||
0 => 'PhragmentDAO',
|
||||
1 => 'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhragmentSnapshotChild' =>
|
||||
array(
|
||||
0 => 'PhragmentDAO',
|
||||
1 => 'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhragmentSnapshotChildQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhragmentSnapshotCreateController' => 'PhragmentController',
|
||||
'PhragmentSnapshotDeleteController' => 'PhragmentController',
|
||||
'PhragmentSnapshotPromoteController' => 'PhragmentController',
|
||||
'PhragmentSnapshotQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhragmentSnapshotViewController' => 'PhragmentController',
|
||||
'PhragmentUpdateController' => 'PhragmentController',
|
||||
'PhragmentVersionController' => 'PhragmentController',
|
||||
'PhragmentZIPController' => 'PhragmentController',
|
||||
|
|
|
@ -39,9 +39,19 @@ final class PhabricatorApplicationPhragment extends PhabricatorApplication {
|
|||
'update/(?P<dblob>.*)' => 'PhragmentUpdateController',
|
||||
'history/(?P<dblob>.*)' => 'PhragmentHistoryController',
|
||||
'zip/(?P<dblob>.*)' => 'PhragmentZIPController',
|
||||
'zip@(?P<snapshot>[^/]+)/(?P<dblob>.*)' => 'PhragmentZIPController',
|
||||
'version/(?P<id>[0-9]*)/' => 'PhragmentVersionController',
|
||||
'patch/(?P<aid>[0-9x]*)/(?P<bid>[0-9]*)/' => 'PhragmentPatchController',
|
||||
'revert/(?P<id>[0-9]*)/(?P<dblob>.*)' => 'PhragmentRevertController',
|
||||
'snapshot/' => array(
|
||||
'create/(?P<dblob>.*)' => 'PhragmentSnapshotCreateController',
|
||||
'view/(?P<id>[0-9]*)/' => 'PhragmentSnapshotViewController',
|
||||
'delete/(?P<id>[0-9]*)/' => 'PhragmentSnapshotDeleteController',
|
||||
'promote/' => array(
|
||||
'latest/(?P<dblob>.*)' => 'PhragmentSnapshotPromoteController',
|
||||
'(?P<id>[0-9]*)/' => 'PhragmentSnapshotPromoteController',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ final class PhragmentBrowseController extends PhragmentController {
|
|||
foreach ($fragments as $fragment) {
|
||||
$item = id(new PHUIObjectItemView());
|
||||
$item->setHeader($fragment->getName());
|
||||
$item->setHref($this->getApplicationURI('/browse/'.$fragment->getPath()));
|
||||
$item->setHref($fragment->getURI());
|
||||
if (!$fragment->isDirectory()) {
|
||||
$item->addAttribute(pht(
|
||||
'Last Updated %s',
|
||||
|
|
|
@ -64,6 +64,16 @@ abstract class PhragmentController extends PhabricatorController {
|
|||
$phids = array();
|
||||
$phids[] = $fragment->getLatestVersionPHID();
|
||||
|
||||
$snapshot_phids = array();
|
||||
$snapshots = id(new PhragmentSnapshotQuery())
|
||||
->setViewer($viewer)
|
||||
->withPrimaryFragmentPHIDs(array($fragment->getPHID()))
|
||||
->execute();
|
||||
foreach ($snapshots as $snapshot) {
|
||||
$phids[] = $snapshot->getPHID();
|
||||
$snapshot_phids[] = $snapshot->getPHID();
|
||||
}
|
||||
|
||||
$this->loadHandles($phids);
|
||||
|
||||
$file = null;
|
||||
|
@ -127,6 +137,21 @@ abstract class PhragmentController extends PhabricatorController {
|
|||
->setHref($this->getApplicationURI("history/".$fragment->getPath()))
|
||||
->setIcon('history'));
|
||||
}
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Create Snapshot'))
|
||||
->setHref($this->getApplicationURI(
|
||||
"snapshot/create/".$fragment->getPath()))
|
||||
->setDisabled(false) // TODO: Policy
|
||||
->setIcon('snapshot'));
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Promote Snapshot to Here'))
|
||||
->setHref($this->getApplicationURI(
|
||||
"snapshot/promote/latest/".$fragment->getPath()))
|
||||
->setWorkflow(true)
|
||||
->setDisabled(false) // TODO: Policy
|
||||
->setIcon('promote'));
|
||||
|
||||
$properties = id(new PHUIPropertyListView())
|
||||
->setUser($viewer)
|
||||
|
@ -152,6 +177,12 @@ abstract class PhragmentController extends PhabricatorController {
|
|||
pht('Directory'));
|
||||
}
|
||||
|
||||
if (count($snapshot_phids) > 0) {
|
||||
$properties->addProperty(
|
||||
pht('Snapshots'),
|
||||
$this->renderHandlesForPHIDs($snapshot_phids));
|
||||
}
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->addPropertyList($properties);
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
|
||||
final class PhragmentSnapshotCreateController extends PhragmentController {
|
||||
|
||||
private $dblob;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->dblob = idx($data, "dblob", "");
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$parents = $this->loadParentFragments($this->dblob);
|
||||
if ($parents === null) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$fragment = nonempty(last($parents), null);
|
||||
if ($fragment === null) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$children = id(new PhragmentFragmentQuery())
|
||||
->setViewer($viewer)
|
||||
->needLatestVersion(true)
|
||||
->withLeadingPath($fragment->getPath().'/')
|
||||
->execute();
|
||||
|
||||
$error_view = null;
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$errors = array();
|
||||
|
||||
$v_name = $request->getStr('name');
|
||||
if (strlen($v_name) === 0) {
|
||||
$errors[] = pht('You must specify a name.');
|
||||
}
|
||||
if (strpos($v_name, '/') !== false) {
|
||||
$errors[] = pht('Snapshot names can not contain "/".');
|
||||
}
|
||||
|
||||
if (!count($errors)) {
|
||||
$snapshot = null;
|
||||
|
||||
try {
|
||||
// Create the snapshot.
|
||||
$snapshot = id(new PhragmentSnapshot())
|
||||
->setPrimaryFragmentPHID($fragment->getPHID())
|
||||
->setName($v_name)
|
||||
->save();
|
||||
} catch (AphrontQueryDuplicateKeyException $e) {
|
||||
$errors[] = pht('A snapshot with this name already exists.');
|
||||
}
|
||||
|
||||
if (!count($errors)) {
|
||||
// Add the primary fragment.
|
||||
id(new PhragmentSnapshotChild())
|
||||
->setSnapshotPHID($snapshot->getPHID())
|
||||
->setFragmentPHID($fragment->getPHID())
|
||||
->setFragmentVersionPHID($fragment->getLatestVersionPHID())
|
||||
->save();
|
||||
|
||||
// Add all of the child fragments.
|
||||
foreach ($children as $child) {
|
||||
id(new PhragmentSnapshotChild())
|
||||
->setSnapshotPHID($snapshot->getPHID())
|
||||
->setFragmentPHID($child->getPHID())
|
||||
->setFragmentVersionPHID($child->getLatestVersionPHID())
|
||||
->save();
|
||||
}
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/phragment/snapshot/view/'.$snapshot->getID());
|
||||
}
|
||||
}
|
||||
|
||||
$error_view = id(new AphrontErrorView())
|
||||
->setErrors($errors)
|
||||
->setTitle(pht('Errors while creating snapshot'));
|
||||
}
|
||||
|
||||
$fragment_sequence = "-";
|
||||
if ($fragment->getLatestVersion() !== null) {
|
||||
$fragment_sequence = $fragment->getLatestVersion()->getSequence();
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
$rows[] = phutil_tag(
|
||||
'tr',
|
||||
array(),
|
||||
array(
|
||||
phutil_tag('th', array(), 'Fragment'),
|
||||
phutil_tag('th', array(), 'Version')));
|
||||
$rows[] = phutil_tag(
|
||||
'tr',
|
||||
array(),
|
||||
array(
|
||||
phutil_tag('td', array(), $fragment->getPath()),
|
||||
phutil_tag('td', array(), $fragment_sequence)));
|
||||
foreach ($children as $child) {
|
||||
$sequence = "-";
|
||||
if ($child->getLatestVersion() !== null) {
|
||||
$sequence = $child->getLatestVersion()->getSequence();
|
||||
}
|
||||
$rows[] = phutil_tag(
|
||||
'tr',
|
||||
array(),
|
||||
array(
|
||||
phutil_tag('td', array(), $child->getPath()),
|
||||
phutil_tag('td', array(), $sequence)));
|
||||
}
|
||||
|
||||
$table = phutil_tag(
|
||||
'table',
|
||||
array('class' => 'remarkup-table'),
|
||||
$rows);
|
||||
|
||||
$container = phutil_tag(
|
||||
'div',
|
||||
array('class' => 'phabricator-remarkup'),
|
||||
array(
|
||||
phutil_tag(
|
||||
'p',
|
||||
array(),
|
||||
pht(
|
||||
"The snapshot will contain the following fragments at ".
|
||||
"the specified versions: ")),
|
||||
$table));
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Fragment Path'))
|
||||
->setDisabled(true)
|
||||
->setValue('/'.$fragment->getPath()))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Snapshot Name'))
|
||||
->setName('name'))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Create Snapshot'))
|
||||
->addCancelButton(
|
||||
$this->getApplicationURI('browse/'.$fragment->getPath())))
|
||||
->appendChild(
|
||||
id(new PHUIFormDividerControl()))
|
||||
->appendInstructions($container);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbsWithPath($parents);
|
||||
$crumbs->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setName(pht('Create Snapshot')));
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Create Snapshot of %s', $fragment->getName()))
|
||||
->setFormError($error_view)
|
||||
->setForm($form);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$box),
|
||||
array(
|
||||
'title' => pht('Create Fragment'),
|
||||
'device' => true));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
final class PhragmentSnapshotDeleteController extends PhragmentController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$snapshot = id(new PhragmentSnapshotQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->id))
|
||||
->executeOne();
|
||||
if ($snapshot === null) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if ($request->isDialogFormPost()) {
|
||||
$fragment_uri = $snapshot->getPrimaryFragment()->getURI();
|
||||
|
||||
$snapshot->delete();
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($fragment_uri);
|
||||
}
|
||||
|
||||
return $this->createDialog();
|
||||
}
|
||||
|
||||
function createDialog() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setTitle(pht('Really delete this snapshot?'))
|
||||
->setUser($request->getUser())
|
||||
->addSubmitButton(pht('Delete'))
|
||||
->addCancelButton(pht('Cancel'))
|
||||
->appendParagraph(pht(
|
||||
"Deleting this snapshot is a permanent operation. You can not ".
|
||||
"recover the state of the snapshot."));
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
|
||||
final class PhragmentSnapshotPromoteController extends PhragmentController {
|
||||
|
||||
private $dblob;
|
||||
private $id;
|
||||
private $targetSnapshot;
|
||||
private $targetFragment;
|
||||
private $snapshots;
|
||||
private $options;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->dblob = idx($data, 'dblob', null);
|
||||
$this->id = idx($data, 'id', null);
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
// When the user is promoting a snapshot to the latest version, the
|
||||
// identifier is a fragment path.
|
||||
if ($this->dblob !== null) {
|
||||
$this->targetFragment = id(new PhragmentFragmentQuery())
|
||||
->setViewer($viewer)
|
||||
->withPaths(array($this->dblob))
|
||||
->executeOne();
|
||||
if ($this->targetFragment === null) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$this->snapshots = id(new PhragmentSnapshotQuery())
|
||||
->setViewer($viewer)
|
||||
->withPrimaryFragmentPHIDs(array($this->targetFragment->getPHID()))
|
||||
->execute();
|
||||
}
|
||||
|
||||
// When the user is promoting a snapshot to another snapshot, the
|
||||
// identifier is another snapshot ID.
|
||||
if ($this->id !== null) {
|
||||
$this->targetSnapshot = id(new PhragmentSnapshotQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->id))
|
||||
->executeOne();
|
||||
if ($this->targetSnapshot === null) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$this->snapshots = id(new PhragmentSnapshotQuery())
|
||||
->setViewer($viewer)
|
||||
->withPrimaryFragmentPHIDs(array(
|
||||
$this->targetSnapshot->getPrimaryFragmentPHID()))
|
||||
->execute();
|
||||
}
|
||||
|
||||
// If there's no identifier, just 404.
|
||||
if ($this->snapshots === null) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
// Work out what options the user has.
|
||||
$this->options = mpull(
|
||||
$this->snapshots,
|
||||
'getName',
|
||||
'getID');
|
||||
if ($this->id !== null) {
|
||||
unset($this->options[$this->id]);
|
||||
}
|
||||
|
||||
// If there's no options, show a dialog telling the
|
||||
// user there are no snapshots to promote.
|
||||
if (count($this->options) === 0) {
|
||||
return id(new AphrontDialogResponse())->setDialog(
|
||||
id(new AphrontDialogView())
|
||||
->setTitle(pht('No snapshots to promote'))
|
||||
->appendParagraph(pht(
|
||||
"There are no snapshots available to promote."))
|
||||
->setUser($request->getUser())
|
||||
->addCancelButton(pht('Cancel')));
|
||||
}
|
||||
|
||||
// Handle snapshot promotion.
|
||||
if ($request->isDialogFormPost()) {
|
||||
$snapshot = id(new PhragmentSnapshotQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($request->getStr('snapshot')))
|
||||
->executeOne();
|
||||
if ($snapshot === null) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$snapshot->openTransaction();
|
||||
// Delete all existing child entries.
|
||||
$children = id(new PhragmentSnapshotChildQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withSnapshotPHIDs(array($snapshot->getPHID()))
|
||||
->execute();
|
||||
foreach ($children as $child) {
|
||||
$child->delete();
|
||||
}
|
||||
|
||||
if ($this->id === null) {
|
||||
// The user is promoting the snapshot to the latest version.
|
||||
$children = id(new PhragmentFragmentQuery())
|
||||
->setViewer($viewer)
|
||||
->needLatestVersion(true)
|
||||
->withLeadingPath($this->targetFragment->getPath().'/')
|
||||
->execute();
|
||||
|
||||
// Add the primary fragment.
|
||||
id(new PhragmentSnapshotChild())
|
||||
->setSnapshotPHID($snapshot->getPHID())
|
||||
->setFragmentPHID($this->targetFragment->getPHID())
|
||||
->setFragmentVersionPHID(
|
||||
$this->targetFragment->getLatestVersionPHID())
|
||||
->save();
|
||||
|
||||
// Add all of the child fragments.
|
||||
foreach ($children as $child) {
|
||||
id(new PhragmentSnapshotChild())
|
||||
->setSnapshotPHID($snapshot->getPHID())
|
||||
->setFragmentPHID($child->getPHID())
|
||||
->setFragmentVersionPHID($child->getLatestVersionPHID())
|
||||
->save();
|
||||
}
|
||||
} else {
|
||||
// The user is promoting the snapshot to another snapshot. We just
|
||||
// copy the other snapshot's child entries and change the snapshot
|
||||
// PHID to make it identical.
|
||||
$children = id(new PhragmentSnapshotChildQuery())
|
||||
->setViewer($viewer)
|
||||
->withSnapshotPHIDs(array($this->targetSnapshot->getPHID()))
|
||||
->execute();
|
||||
foreach ($children as $child) {
|
||||
id(new PhragmentSnapshotChild())
|
||||
->setSnapshotPHID($snapshot->getPHID())
|
||||
->setFragmentPHID($child->getFragmentPHID())
|
||||
->setFragmentVersionPHID($child->getFragmentVersionPHID())
|
||||
->save();
|
||||
}
|
||||
}
|
||||
$snapshot->saveTransaction();
|
||||
|
||||
return id(new AphrontRedirectResponse());
|
||||
}
|
||||
|
||||
return $this->createDialog();
|
||||
}
|
||||
|
||||
function createDialog() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setTitle(pht('Promote which snapshot?'))
|
||||
->setUser($request->getUser())
|
||||
->addSubmitButton(pht('Promote'))
|
||||
->addCancelButton(pht('Cancel'));
|
||||
|
||||
if ($this->id === null) {
|
||||
// The user is promoting a snapshot to the latest version.
|
||||
$dialog->appendParagraph(pht(
|
||||
"Select the snapshot you want to promote to the latest version:"));
|
||||
} else {
|
||||
// The user is promoting a snapshot to another snapshot.
|
||||
$dialog->appendParagraph(pht(
|
||||
"Select the snapshot you want to promote to '%s':",
|
||||
$this->targetSnapshot->getName()));
|
||||
}
|
||||
|
||||
$dialog->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setUser($viewer)
|
||||
->setName('snapshot')
|
||||
->setOptions($this->options));
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
|
||||
final class PhragmentSnapshotViewController extends PhragmentController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = idx($data, "id", "");
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$snapshot = id(new PhragmentSnapshotQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->id))
|
||||
->executeOne();
|
||||
if ($snapshot === null) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$box = $this->createSnapshotView($snapshot);
|
||||
|
||||
$fragment = id(new PhragmentFragmentQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($snapshot->getPrimaryFragmentPHID()))
|
||||
->executeOne();
|
||||
if ($fragment === null) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$parents = $this->loadParentFragments($fragment->getPath());
|
||||
if ($parents === null) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbsWithPath($parents);
|
||||
$crumbs->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setName(pht('"%s" Snapshot', $snapshot->getName())));
|
||||
|
||||
$children = id(new PhragmentSnapshotChildQuery())
|
||||
->setViewer($viewer)
|
||||
->needFragments(true)
|
||||
->needFragmentVersions(true)
|
||||
->withSnapshotPHIDs(array($snapshot->getPHID()))
|
||||
->execute();
|
||||
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
->setUser($viewer);
|
||||
|
||||
foreach ($children as $child) {
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($child->getFragment()->getPath());
|
||||
|
||||
if ($child->getFragmentVersion() !== null) {
|
||||
$item
|
||||
->setHref($child->getFragmentVersion()->getURI())
|
||||
->addAttribute(pht(
|
||||
'Version %s',
|
||||
$child->getFragmentVersion()->getSequence()));
|
||||
} else {
|
||||
$item
|
||||
->setHref($child->getFragment()->getURI())
|
||||
->addAttribute(pht('Directory'));
|
||||
}
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$box,
|
||||
$list),
|
||||
array(
|
||||
'title' => pht('View Snapshot'),
|
||||
'device' => true));
|
||||
}
|
||||
|
||||
protected function createSnapshotView($snapshot) {
|
||||
if ($snapshot === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$phids = array();
|
||||
$phids[] = $snapshot->getPrimaryFragmentPHID();
|
||||
|
||||
$this->loadHandles($phids);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('"%s" Snapshot', $snapshot->getName()))
|
||||
->setPolicyObject($snapshot)
|
||||
->setUser($viewer);
|
||||
|
||||
$zip_uri = $this->getApplicationURI(
|
||||
"zip@".$snapshot->getName().
|
||||
"/".$snapshot->getPrimaryFragment()->getPath());
|
||||
|
||||
$actions = id(new PhabricatorActionListView())
|
||||
->setUser($viewer)
|
||||
->setObject($snapshot)
|
||||
->setObjectURI($snapshot->getURI());
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Download Snapshot as ZIP'))
|
||||
->setHref($zip_uri)
|
||||
->setDisabled(false) // TODO: Policy
|
||||
->setIcon('zip'));
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Delete Snapshot'))
|
||||
->setHref($this->getApplicationURI(
|
||||
"snapshot/delete/".$snapshot->getID()."/"))
|
||||
->setWorkflow(true)
|
||||
->setDisabled(false) // TODO: Policy
|
||||
->setIcon('delete'));
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Promote Another Snapshot to Here'))
|
||||
->setHref($this->getApplicationURI(
|
||||
"snapshot/promote/".$snapshot->getID()."/"))
|
||||
->setWorkflow(true)
|
||||
->setDisabled(false) // TODO: Policy
|
||||
->setIcon('promote'));
|
||||
|
||||
$properties = id(new PHUIPropertyListView())
|
||||
->setUser($viewer)
|
||||
->setObject($snapshot)
|
||||
->setActionList($actions);
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Name'),
|
||||
$snapshot->getName());
|
||||
$properties->addProperty(
|
||||
pht('Fragment'),
|
||||
$this->renderHandlesForPHIDs(array($snapshot->getPrimaryFragmentPHID())));
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->addPropertyList($properties);
|
||||
}
|
||||
}
|
|
@ -3,9 +3,13 @@
|
|||
final class PhragmentZIPController extends PhragmentController {
|
||||
|
||||
private $dblob;
|
||||
private $snapshot;
|
||||
|
||||
private $snapshotCache;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->dblob = idx($data, "dblob", "");
|
||||
$this->snapshot = idx($data, "snapshot", null);
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
|
@ -18,6 +22,27 @@ final class PhragmentZIPController extends PhragmentController {
|
|||
}
|
||||
$fragment = idx($parents, count($parents) - 1, null);
|
||||
|
||||
if ($this->snapshot !== null) {
|
||||
$snapshot = id(new PhragmentSnapshotQuery())
|
||||
->setViewer($viewer)
|
||||
->withPrimaryFragmentPHIDs(array($fragment->getPHID()))
|
||||
->withNames(array($this->snapshot))
|
||||
->executeOne();
|
||||
if ($snapshot === null) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$cache = id(new PhragmentSnapshotChildQuery())
|
||||
->setViewer($viewer)
|
||||
->needFragmentVersions(true)
|
||||
->withSnapshotPHIDs(array($snapshot->getPHID()))
|
||||
->execute();
|
||||
$this->snapshotCache = mpull(
|
||||
$cache,
|
||||
'getFragmentVersion',
|
||||
'getFragmentPHID');
|
||||
}
|
||||
|
||||
$temp = new TempFile();
|
||||
|
||||
$zip = null;
|
||||
|
@ -95,10 +120,10 @@ final class PhragmentZIPController extends PhragmentController {
|
|||
|
||||
if (count($children) === 0) {
|
||||
$path = substr($current->getPath(), strlen($base_path) + 1);
|
||||
if ($current->getLatestVersion() === null) {
|
||||
if ($this->getVersion($current) === null) {
|
||||
return array();
|
||||
}
|
||||
return array($path => $current->getLatestVersion()->getFilePHID());
|
||||
return array($path => $this->getVersion($current)->getFilePHID());
|
||||
} else {
|
||||
$mappings = array();
|
||||
foreach ($children as $child) {
|
||||
|
@ -111,4 +136,12 @@ final class PhragmentZIPController extends PhragmentController {
|
|||
}
|
||||
}
|
||||
|
||||
private function getVersion($fragment) {
|
||||
if ($this->snapshot === null) {
|
||||
return $fragment->getLatestVersion();
|
||||
} else {
|
||||
return idx($this->snapshotCache, $fragment->getPHID(), null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,7 +34,10 @@ final class PhragmentPHIDTypeFragment
|
|||
foreach ($handles as $phid => $handle) {
|
||||
$fragment = $objects[$phid];
|
||||
|
||||
$handle->setName($fragment->getID());
|
||||
$handle->setName(pht(
|
||||
"Fragment %s: %s",
|
||||
$fragment->getID(),
|
||||
$fragment->getName()));
|
||||
$handle->setURI($fragment->getURI());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,10 @@ final class PhragmentPHIDTypeFragmentVersion
|
|||
foreach ($handles as $phid => $handle) {
|
||||
$version = $objects[$phid];
|
||||
|
||||
$handle->setName($version->getSequence());
|
||||
$handle->setName(pht(
|
||||
"Fragment Version %d: %s",
|
||||
$version->getSequence(),
|
||||
$version->getFragment()->getName()));
|
||||
$handle->setURI($version->getURI());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
final class PhragmentPHIDTypeSnapshot
|
||||
extends PhabricatorPHIDType {
|
||||
|
||||
const TYPECONST = 'PHRS';
|
||||
|
||||
public function getTypeConstant() {
|
||||
return self::TYPECONST;
|
||||
}
|
||||
|
||||
public function getTypeName() {
|
||||
return pht('Snapshot');
|
||||
}
|
||||
|
||||
public function newObject() {
|
||||
return new PhragmentSnapshot();
|
||||
}
|
||||
|
||||
protected function buildQueryForObjects(
|
||||
PhabricatorObjectQuery $query,
|
||||
array $phids) {
|
||||
|
||||
return id(new PhragmentSnapshotQuery())
|
||||
->withPHIDs($phids);
|
||||
}
|
||||
|
||||
public function loadHandles(
|
||||
PhabricatorHandleQuery $query,
|
||||
array $handles,
|
||||
array $objects) {
|
||||
|
||||
$viewer = $query->getViewer();
|
||||
foreach ($handles as $phid => $handle) {
|
||||
$snapshot = $objects[$phid];
|
||||
|
||||
$handle->setName(pht(
|
||||
'Snapshot: %s',
|
||||
$snapshot->getName()));
|
||||
$handle->setURI($snapshot->getURI());
|
||||
}
|
||||
}
|
||||
|
||||
public function canLoadNamedObject($name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -8,7 +8,7 @@ final class PhragmentFragmentQuery
|
|||
private $paths;
|
||||
private $leadingPath;
|
||||
private $depths;
|
||||
private $needsLatestVersion;
|
||||
private $needLatestVersion;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -36,7 +36,7 @@ final class PhragmentFragmentQuery
|
|||
}
|
||||
|
||||
public function needLatestVersion($need_latest_version) {
|
||||
$this->needsLatestVersion = $need_latest_version;
|
||||
$this->needLatestVersion = $need_latest_version;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ final class PhragmentFragmentQuery
|
|||
}
|
||||
|
||||
protected function didFilterPage(array $page) {
|
||||
if ($this->needsLatestVersion) {
|
||||
if ($this->needLatestVersion) {
|
||||
$versions = array();
|
||||
|
||||
$version_phids = array_filter(mpull($page, 'getLatestVersionPHID'));
|
||||
|
|
174
src/applications/phragment/query/PhragmentSnapshotChildQuery.php
Normal file
174
src/applications/phragment/query/PhragmentSnapshotChildQuery.php
Normal file
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
|
||||
final class PhragmentSnapshotChildQuery
|
||||
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||
|
||||
private $ids;
|
||||
private $snapshotPHIDs;
|
||||
private $fragmentPHIDs;
|
||||
private $fragmentVersionPHIDs;
|
||||
private $needFragments;
|
||||
private $needFragmentVersions;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withSnapshotPHIDs(array $snapshot_phids) {
|
||||
$this->snapshotPHIDs = $snapshot_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withFragmentPHIDs(array $fragment_phids) {
|
||||
$this->fragmentPHIDs = $fragment_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withFragmentVersionPHIDs(array $fragment_version_phids) {
|
||||
$this->fragmentVersionPHIDs = $fragment_version_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function needFragments($need_fragments) {
|
||||
$this->needFragments = $need_fragments;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function needFragmentVersions($need_fragment_versions) {
|
||||
$this->needFragmentVersions = $need_fragment_versions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function loadPage() {
|
||||
$table = new PhragmentSnapshotChild();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
||||
$data = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT * FROM %T %Q %Q %Q',
|
||||
$table->getTableName(),
|
||||
$this->buildWhereClause($conn_r),
|
||||
$this->buildOrderClause($conn_r),
|
||||
$this->buildLimitClause($conn_r));
|
||||
|
||||
return $table->loadAllFromArray($data);
|
||||
}
|
||||
|
||||
protected function buildWhereClause($conn_r) {
|
||||
$where = array();
|
||||
|
||||
if ($this->ids) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->snapshotPHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'snapshotPHID IN (%Ls)',
|
||||
$this->snapshotPHIDs);
|
||||
}
|
||||
|
||||
if ($this->fragmentPHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'fragmentPHID IN (%Ls)',
|
||||
$this->fragmentPHIDs);
|
||||
}
|
||||
|
||||
if ($this->fragmentVersionPHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'fragmentVersionPHID IN (%Ls)',
|
||||
$this->fragmentVersionPHIDs);
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn_r);
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
}
|
||||
|
||||
protected function willFilterPage(array $page) {
|
||||
$snapshots = array();
|
||||
|
||||
$snapshot_phids = array_filter(mpull($page, 'getSnapshotPHID'));
|
||||
if ($snapshot_phids) {
|
||||
$snapshots = id(new PhabricatorObjectQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs($snapshot_phids)
|
||||
->setParentQuery($this)
|
||||
->execute();
|
||||
$snapshots = mpull($snapshots, null, 'getPHID');
|
||||
}
|
||||
|
||||
foreach ($page as $key => $child) {
|
||||
$snapshot_phid = $child->getSnapshotPHID();
|
||||
if (empty($snapshots[$snapshot_phid])) {
|
||||
unset($page[$key]);
|
||||
continue;
|
||||
}
|
||||
$child->attachSnapshot($snapshots[$snapshot_phid]);
|
||||
}
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
protected function didFilterPage(array $page) {
|
||||
if ($this->needFragments) {
|
||||
$fragments = array();
|
||||
|
||||
$fragment_phids = array_filter(mpull($page, 'getFragmentPHID'));
|
||||
if ($fragment_phids) {
|
||||
$fragments = id(new PhabricatorObjectQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs($fragment_phids)
|
||||
->setParentQuery($this)
|
||||
->execute();
|
||||
$fragments = mpull($fragments, null, 'getPHID');
|
||||
}
|
||||
|
||||
foreach ($page as $key => $child) {
|
||||
$fragment_phid = $child->getFragmentPHID();
|
||||
if (empty($fragments[$fragment_phid])) {
|
||||
unset($page[$key]);
|
||||
continue;
|
||||
}
|
||||
$child->attachFragment($fragments[$fragment_phid]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->needFragmentVersions) {
|
||||
$fragment_versions = array();
|
||||
|
||||
$fragment_version_phids = array_filter(mpull(
|
||||
$page,
|
||||
'getFragmentVersionPHID'));
|
||||
if ($fragment_version_phids) {
|
||||
$fragment_versions = id(new PhabricatorObjectQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs($fragment_version_phids)
|
||||
->setParentQuery($this)
|
||||
->execute();
|
||||
$fragment_versions = mpull($fragment_versions, null, 'getPHID');
|
||||
}
|
||||
|
||||
foreach ($page as $key => $child) {
|
||||
$fragment_version_phid = $child->getFragmentVersionPHID();
|
||||
if (empty($fragment_versions[$fragment_version_phid])) {
|
||||
continue;
|
||||
}
|
||||
$child->attachFragmentVersion(
|
||||
$fragment_versions[$fragment_version_phid]);
|
||||
}
|
||||
}
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
return 'PhabricatorApplicationPhragment';
|
||||
}
|
||||
}
|
110
src/applications/phragment/query/PhragmentSnapshotQuery.php
Normal file
110
src/applications/phragment/query/PhragmentSnapshotQuery.php
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
final class PhragmentSnapshotQuery
|
||||
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||
|
||||
private $ids;
|
||||
private $phids;
|
||||
private $primaryFragmentPHIDs;
|
||||
private $names;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withPHIDs(array $phids) {
|
||||
$this->phids = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withPrimaryFragmentPHIDs(array $primary_fragment_phids) {
|
||||
$this->primaryFragmentPHIDs = $primary_fragment_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withNames(array $names) {
|
||||
$this->names = $names;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function loadPage() {
|
||||
$table = new PhragmentSnapshot();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
||||
$data = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT * FROM %T %Q %Q %Q',
|
||||
$table->getTableName(),
|
||||
$this->buildWhereClause($conn_r),
|
||||
$this->buildOrderClause($conn_r),
|
||||
$this->buildLimitClause($conn_r));
|
||||
|
||||
return $table->loadAllFromArray($data);
|
||||
}
|
||||
|
||||
protected function buildWhereClause($conn_r) {
|
||||
$where = array();
|
||||
|
||||
if ($this->ids) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->phids) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->primaryFragmentPHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'primaryFragmentPHID IN (%Ls)',
|
||||
$this->primaryFragmentPHIDs);
|
||||
}
|
||||
|
||||
if ($this->names) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'name IN (%Ls)',
|
||||
$this->names);
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn_r);
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
}
|
||||
|
||||
protected function willFilterPage(array $page) {
|
||||
$fragments = array();
|
||||
|
||||
$fragment_phids = array_filter(mpull($page, 'getPrimaryFragmentPHID'));
|
||||
if ($fragment_phids) {
|
||||
$fragments = id(new PhabricatorObjectQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs($fragment_phids)
|
||||
->setParentQuery($this)
|
||||
->execute();
|
||||
$fragments = mpull($fragments, null, 'getPHID');
|
||||
}
|
||||
|
||||
foreach ($page as $key => $snapshot) {
|
||||
$fragment_phid = $snapshot->getPrimaryFragmentPHID();
|
||||
if (empty($fragments[$fragment_phid])) {
|
||||
unset($page[$key]);
|
||||
continue;
|
||||
}
|
||||
$snapshot->attachPrimaryFragment($fragments[$fragment_phid]);
|
||||
}
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
return 'PhabricatorApplicationPhragment';
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ final class PhragmentFragment extends PhragmentDAO
|
|||
}
|
||||
|
||||
public function getURI() {
|
||||
return '/phragment/fragment/'.$this->getID().'/';
|
||||
return '/phragment/browse/'.$this->getPath();
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
|
|
69
src/applications/phragment/storage/PhragmentSnapshot.php
Normal file
69
src/applications/phragment/storage/PhragmentSnapshot.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
final class PhragmentSnapshot extends PhragmentDAO
|
||||
implements PhabricatorPolicyInterface {
|
||||
|
||||
protected $primaryFragmentPHID;
|
||||
protected $name;
|
||||
|
||||
private $primaryFragment = self::ATTACHABLE;
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function generatePHID() {
|
||||
return PhabricatorPHID::generateNewPHID(
|
||||
PhragmentPHIDTypeSnapshot::TYPECONST);
|
||||
}
|
||||
|
||||
public function getURI() {
|
||||
return '/phragment/snapshot/view/'.$this->getID().'/';
|
||||
}
|
||||
|
||||
public function getPrimaryFragment() {
|
||||
return $this->assertAttached($this->primaryFragment);
|
||||
}
|
||||
|
||||
public function attachPrimaryFragment(PhragmentFragment $fragment) {
|
||||
return $this->primaryFragment = $fragment;
|
||||
}
|
||||
|
||||
public function delete() {
|
||||
$children = id(new PhragmentSnapshotChild())
|
||||
->loadAllWhere('snapshotPHID = %s', $this->getPHID());
|
||||
$this->openTransaction();
|
||||
foreach ($children as $child) {
|
||||
$child->delete();
|
||||
}
|
||||
$result = parent::delete();
|
||||
$this->saveTransaction();
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/* -( Policy Interface )--------------------------------------------------- */
|
||||
|
||||
|
||||
public function getCapabilities() {
|
||||
return array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW
|
||||
);
|
||||
}
|
||||
|
||||
public function getPolicy($capability) {
|
||||
return $this->getPrimaryFragment()->getPolicy($capability);
|
||||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
return $this->getPrimaryFragment()
|
||||
->hasAutomaticCapability($capability, $viewer);
|
||||
}
|
||||
|
||||
public function describeAutomaticCapability($capability) {
|
||||
return $this->getPrimaryFragment()
|
||||
->describeAutomaticCapability($capability);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
final class PhragmentSnapshotChild extends PhragmentDAO
|
||||
implements PhabricatorPolicyInterface {
|
||||
|
||||
protected $snapshotPHID;
|
||||
protected $fragmentPHID;
|
||||
protected $fragmentVersionPHID;
|
||||
|
||||
private $snapshot = self::ATTACHABLE;
|
||||
private $fragment = self::ATTACHABLE;
|
||||
private $fragmentVersion = self::ATTACHABLE;
|
||||
|
||||
public function getSnapshot() {
|
||||
return $this->assertAttached($this->snapshot);
|
||||
}
|
||||
|
||||
public function attachSnapshot(PhragmentSnapshot $snapshot) {
|
||||
return $this->snapshot = $snapshot;
|
||||
}
|
||||
|
||||
public function getFragment() {
|
||||
return $this->assertAttached($this->fragment);
|
||||
}
|
||||
|
||||
public function attachFragment(PhragmentFragment $fragment) {
|
||||
return $this->fragment = $fragment;
|
||||
}
|
||||
|
||||
public function getFragmentVersion() {
|
||||
if ($this->fragmentVersionPHID === null) {
|
||||
return null;
|
||||
}
|
||||
return $this->assertAttached($this->fragmentVersion);
|
||||
}
|
||||
|
||||
public function attachFragmentVersion(PhragmentFragmentVersion $version) {
|
||||
return $this->fragmentVersion = $version;
|
||||
}
|
||||
|
||||
|
||||
/* -( Policy Interface )--------------------------------------------------- */
|
||||
|
||||
|
||||
public function getCapabilities() {
|
||||
return array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW
|
||||
);
|
||||
}
|
||||
|
||||
public function getPolicy($capability) {
|
||||
return $this->getSnapshot()->getPolicy($capability);
|
||||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
return $this->getSnapshot()
|
||||
->hasAutomaticCapability($capability, $viewer);
|
||||
}
|
||||
|
||||
public function describeAutomaticCapability($capability) {
|
||||
return $this->getSnapshot()
|
||||
->describeAutomaticCapability($capability);
|
||||
}
|
||||
}
|
|
@ -1824,6 +1824,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
|||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('20131206.phragmentnull.sql'),
|
||||
),
|
||||
'20131208.phragmentsnapshot.sql' => array(
|
||||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('20131208.phragmentsnapshot.sql'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue