Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15465737
D7751.id17551.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
30 KB
Referenced Files
None
Subscribers
None
D7751.id17551.diff
View Options
Index: resources/sql/patches/20131211.phragmentedges.sql
===================================================================
--- /dev/null
+++ resources/sql/patches/20131211.phragmentedges.sql
@@ -0,0 +1,15 @@
+CREATE TABLE {$NAMESPACE}_phragment.edge (
+ src VARCHAR(64) NOT NULL COLLATE utf8_bin,
+ type VARCHAR(64) NOT NULL COLLATE utf8_bin,
+ dst VARCHAR(64) NOT NULL COLLATE utf8_bin,
+ dateCreated INT UNSIGNED NOT NULL,
+ seq INT UNSIGNED NOT NULL,
+ dataID INT UNSIGNED,
+ PRIMARY KEY (src, type, dst),
+ KEY (src, type, dateCreated, seq)
+) ENGINE=InnoDB, COLLATE utf8_general_ci;
+
+CREATE TABLE {$NAMESPACE}_phragment.edgedata (
+ id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ data LONGTEXT NOT NULL COLLATE utf8_bin
+) ENGINE=InnoDB, COLLATE utf8_general_ci;
Index: src/__celerity_resource_map__.php
===================================================================
--- src/__celerity_resource_map__.php
+++ src/__celerity_resource_map__.php
@@ -1776,6 +1776,18 @@
),
'disk' => '/rsrc/js/core/behavior-fancy-datepicker.js',
),
+ 'javelin-behavior-files-download-redirect' =>
+ array(
+ 'uri' => '/res/e3513aad/rsrc/js/application/files/behavior-files-download-redirect.js',
+ 'type' => 'js',
+ 'requires' =>
+ array(
+ 0 => 'javelin-behavior',
+ 1 => 'javelin-dom',
+ 2 => 'javelin-workflow',
+ ),
+ 'disk' => '/rsrc/js/application/files/behavior-files-download-redirect.js',
+ ),
'javelin-behavior-global-drag-and-drop' =>
array(
'uri' => '/res/ee8e9c39/rsrc/js/core/behavior-global-drag-and-drop.js',
Index: src/__phutil_library_map__.php
===================================================================
--- src/__phutil_library_map__.php
+++ src/__phutil_library_map__.php
@@ -1406,6 +1406,7 @@
'PhabricatorFileDAO' => 'applications/files/storage/PhabricatorFileDAO.php',
'PhabricatorFileDataController' => 'applications/files/controller/PhabricatorFileDataController.php',
'PhabricatorFileDeleteController' => 'applications/files/controller/PhabricatorFileDeleteController.php',
+ 'PhabricatorFileDialogController' => 'applications/files/controller/PhabricatorFileDialogController.php',
'PhabricatorFileDropUploadController' => 'applications/files/controller/PhabricatorFileDropUploadController.php',
'PhabricatorFileEditor' => 'applications/files/editor/PhabricatorFileEditor.php',
'PhabricatorFileImageMacro' => 'applications/macro/storage/PhabricatorFileImageMacro.php',
@@ -2176,6 +2177,7 @@
'PhortuneTestPaymentProvider' => 'applications/phortune/provider/PhortuneTestPaymentProvider.php',
'PhortuneWePayPaymentProvider' => 'applications/phortune/provider/PhortuneWePayPaymentProvider.php',
'PhragmentBrowseController' => 'applications/phragment/controller/PhragmentBrowseController.php',
+ 'PhragmentCapabilityCanCreate' => 'applications/phragment/capability/PhragmentCapabilityCanCreate.php',
'PhragmentController' => 'applications/phragment/controller/PhragmentController.php',
'PhragmentCreateController' => 'applications/phragment/controller/PhragmentCreateController.php',
'PhragmentDAO' => 'applications/phragment/storage/PhragmentDAO.php',
@@ -2189,6 +2191,7 @@
'PhragmentPHIDTypeSnapshot' => 'applications/phragment/phid/PhragmentPHIDTypeSnapshot.php',
'PhragmentPatchController' => 'applications/phragment/controller/PhragmentPatchController.php',
'PhragmentPatchUtil' => 'applications/phragment/util/PhragmentPatchUtil.php',
+ 'PhragmentPolicyController' => 'applications/phragment/controller/PhragmentPolicyController.php',
'PhragmentRevertController' => 'applications/phragment/controller/PhragmentRevertController.php',
'PhragmentSnapshot' => 'applications/phragment/storage/PhragmentSnapshot.php',
'PhragmentSnapshotChild' => 'applications/phragment/storage/PhragmentSnapshotChild.php',
@@ -3914,6 +3917,7 @@
'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
'PhabricatorFileDataController' => 'PhabricatorFileController',
'PhabricatorFileDeleteController' => 'PhabricatorFileController',
+ 'PhabricatorFileDialogController' => 'PhabricatorFileController',
'PhabricatorFileDropUploadController' => 'PhabricatorFileController',
'PhabricatorFileEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorFileImageMacro' =>
@@ -4782,6 +4786,7 @@
'PhortuneTestPaymentProvider' => 'PhortunePaymentProvider',
'PhortuneWePayPaymentProvider' => 'PhortunePaymentProvider',
'PhragmentBrowseController' => 'PhragmentController',
+ 'PhragmentCapabilityCanCreate' => 'PhabricatorPolicyCapability',
'PhragmentController' => 'PhabricatorController',
'PhragmentCreateController' => 'PhragmentController',
'PhragmentDAO' => 'PhabricatorLiskDAO',
@@ -4803,6 +4808,7 @@
'PhragmentPHIDTypeSnapshot' => 'PhabricatorPHIDType',
'PhragmentPatchController' => 'PhragmentController',
'PhragmentPatchUtil' => 'Phobject',
+ 'PhragmentPolicyController' => 'PhragmentController',
'PhragmentRevertController' => 'PhragmentController',
'PhragmentSnapshot' =>
array(
Index: src/applications/files/application/PhabricatorApplicationFiles.php
===================================================================
--- src/applications/files/application/PhabricatorApplicationFiles.php
+++ src/applications/files/application/PhabricatorApplicationFiles.php
@@ -61,6 +61,7 @@
'xform/(?P<transform>[^/]+)/(?P<phid>[^/]+)/(?P<key>[^/]+)/'
=> 'PhabricatorFileTransformController',
'uploaddialog/' => 'PhabricatorFileUploadDialogController',
+ 'download/(?P<phid>[^/]+)/' => 'PhabricatorFileDialogController',
),
);
}
Index: src/applications/files/controller/PhabricatorFileDialogController.php
===================================================================
--- /dev/null
+++ src/applications/files/controller/PhabricatorFileDialogController.php
@@ -0,0 +1,57 @@
+<?php
+
+final class PhabricatorFileDialogController extends PhabricatorFileController {
+
+ private $phid;
+
+ public function shouldAllowPublic() {
+ return true;
+ }
+
+ public function willProcessRequest(array $data) {
+ $this->phid = $data['phid'];
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $user = $request->getUser();
+
+ $file = id(new PhabricatorFileQuery())
+ ->setViewer($user)
+ ->withPHIDs(array($this->phid))
+ ->executeOne();
+
+ if (!$file) {
+ return new Aphront404Response();
+ }
+
+ $return = $request->getStr('return');
+
+ if (!PhabricatorEnv::isValidWebResource($return)) {
+ throw new Exception("Invalid or unsafe return URI!");
+ }
+
+ $dialog_id = celerity_generate_unique_node_id();
+
+ Javelin::initBehavior(
+ 'files-download-redirect',
+ array(
+ 'dialogID' => $dialog_id,
+ 'return' => $return,
+ ));
+
+ $dialog = id(new AphrontDialogView())
+ ->setFormID($dialog_id)
+ ->setTitle(pht('Download: %s', $file->getName()))
+ ->setUser($request->getUser())
+ ->addSubmitButton(pht('Download'))
+ ->addCancelButton($return, pht('Back'))
+ ->setSubmitURI($file->getDownloadURI())
+ ->appendParagraph(pht("File Type: %s", $file->getMimeType()))
+ ->appendParagraph(pht(
+ "File Size: %s",
+ phabricator_format_bytes($file->getByteSize())));
+ return id(new AphrontDialogResponse())->setDialog($dialog);
+ }
+
+}
Index: src/applications/files/storage/PhabricatorFile.php
===================================================================
--- src/applications/files/storage/PhabricatorFile.php
+++ src/applications/files/storage/PhabricatorFile.php
@@ -512,6 +512,12 @@
return (string) $uri;
}
+ public function getDownloadDialogURI($return) {
+ $uri = id(new PhutilURI('/file/download/'.$this->getPHID().'/'))
+ ->setQueryParam('return', $return);
+ return (string) $uri;
+ }
+
public function getProfileThumbURI() {
$path = '/file/xform/thumb-profile/'.$this->getPHID().'/'
.$this->getSecretKey().'/';
Index: src/applications/phragment/application/PhabricatorApplicationPhragment.php
===================================================================
--- src/applications/phragment/application/PhabricatorApplicationPhragment.php
+++ src/applications/phragment/application/PhabricatorApplicationPhragment.php
@@ -37,6 +37,7 @@
'browse/(?P<dblob>.*)' => 'PhragmentBrowseController',
'create/(?P<dblob>.*)' => 'PhragmentCreateController',
'update/(?P<dblob>.*)' => 'PhragmentUpdateController',
+ 'policy/(?P<dblob>.*)' => 'PhragmentPolicyController',
'history/(?P<dblob>.*)' => 'PhragmentHistoryController',
'zip/(?P<dblob>.*)' => 'PhragmentZIPController',
'zip@(?P<snapshot>[^/]+)/(?P<dblob>.*)' => 'PhragmentZIPController',
@@ -56,5 +57,12 @@
);
}
+ protected function getCustomCapabilities() {
+ return array(
+ PhragmentCapabilityCanCreate::CAPABILITY => array(
+ ),
+ );
+ }
+
}
Index: src/applications/phragment/capability/PhragmentCapabilityCanCreate.php
===================================================================
--- /dev/null
+++ src/applications/phragment/capability/PhragmentCapabilityCanCreate.php
@@ -0,0 +1,20 @@
+<?php
+
+final class PhragmentCapabilityCanCreate
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'phragment.create';
+
+ public function getCapabilityKey() {
+ return self::CAPABILITY;
+ }
+
+ public function getCapabilityName() {
+ return pht('Can Create Fragments');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht('You do not have permission to create fragments.');
+ }
+
+}
Index: src/applications/phragment/controller/PhragmentBrowseController.php
===================================================================
--- src/applications/phragment/controller/PhragmentBrowseController.php
+++ src/applications/phragment/controller/PhragmentBrowseController.php
@@ -4,6 +4,10 @@
private $dblob;
+ public function shouldAllowPublic() {
+ return true;
+ }
+
public function willProcessRequest(array $data) {
$this->dblob = idx($data, "dblob", "");
}
@@ -24,11 +28,14 @@
}
$crumbs = $this->buildApplicationCrumbsWithPath($parents);
- $crumbs->addAction(
- id(new PHUIListItemView())
- ->setName(pht('Create Fragment'))
- ->setHref($this->getApplicationURI('/create/'.$path))
- ->setIcon('create'));
+ if ($this->hasApplicationCapability(
+ PhragmentCapabilityCanCreate::CAPABILITY)) {
+ $crumbs->addAction(
+ id(new PHUIListItemView())
+ ->setName(pht('Create Fragment'))
+ ->setHref($this->getApplicationURI('/create/'.$path))
+ ->setIcon('create'));
+ }
$current_box = $this->createCurrentFragmentView($current, false);
Index: src/applications/phragment/controller/PhragmentController.php
===================================================================
--- src/applications/phragment/controller/PhragmentController.php
+++ src/applications/phragment/controller/PhragmentController.php
@@ -84,7 +84,7 @@
->withPHIDs(array($fragment->getLatestVersion()->getFilePHID()))
->executeOne();
if ($file !== null) {
- $file_uri = $file->getBestURI();
+ $file_uri = $file->getDownloadURI();
}
}
@@ -93,6 +93,11 @@
->setPolicyObject($fragment)
->setUser($viewer);
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $fragment,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
$actions = id(new PhabricatorActionListView())
->setUser($viewer)
->setObject($fragment)
@@ -102,28 +107,38 @@
->setName(pht('Download Fragment'))
->setHref($file_uri)
->setDisabled($file === null)
+ ->setRenderAsForm(true)
+ ->setDownload(true)
->setIcon('download'));
$actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Download Contents as ZIP'))
->setHref($this->getApplicationURI("zip/".$fragment->getPath()))
- ->setDisabled(false) // TODO: Policy
->setIcon('zip'));
if (!$fragment->isDirectory()) {
$actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Update Fragment'))
->setHref($this->getApplicationURI("update/".$fragment->getPath()))
- ->setDisabled(false) // TODO: Policy
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit)
->setIcon('edit'));
} else {
$actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Convert to File'))
->setHref($this->getApplicationURI("update/".$fragment->getPath()))
- ->setDisabled(false) // TODO: Policy
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit)
->setIcon('edit'));
}
+ $actions->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Set Fragment Policies'))
+ ->setHref($this->getApplicationURI("policy/".$fragment->getPath()))
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit)
+ ->setIcon('edit'));
if ($is_history_view) {
$actions->addAction(
id(new PhabricatorActionView())
@@ -142,7 +157,8 @@
->setName(pht('Create Snapshot'))
->setHref($this->getApplicationURI(
"snapshot/create/".$fragment->getPath()))
- ->setDisabled(false) // TODO: Policy
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit)
->setIcon('snapshot'));
$actions->addAction(
id(new PhabricatorActionView())
@@ -150,7 +166,7 @@
->setHref($this->getApplicationURI(
"snapshot/promote/latest/".$fragment->getPath()))
->setWorkflow(true)
- ->setDisabled(false) // TODO: Policy
+ ->setDisabled(!$can_edit)
->setIcon('promote'));
$properties = id(new PHUIPropertyListView())
Index: src/applications/phragment/controller/PhragmentHistoryController.php
===================================================================
--- src/applications/phragment/controller/PhragmentHistoryController.php
+++ src/applications/phragment/controller/PhragmentHistoryController.php
@@ -4,6 +4,10 @@
private $dblob;
+ public function shouldAllowPublic() {
+ return true;
+ }
+
public function willProcessRequest(array $data) {
$this->dblob = idx($data, "dblob", "");
}
@@ -21,11 +25,14 @@
$path = $current->getPath();
$crumbs = $this->buildApplicationCrumbsWithPath($parents);
- $crumbs->addAction(
- id(new PHUIListItemView())
- ->setName(pht('Create Fragment'))
- ->setHref($this->getApplicationURI('/create/'.$path))
- ->setIcon('create'));
+ if ($this->hasApplicationCapability(
+ PhragmentCapabilityCanCreate::CAPABILITY)) {
+ $crumbs->addAction(
+ id(new PHUIListItemView())
+ ->setName(pht('Create Fragment'))
+ ->setHref($this->getApplicationURI('/create/'.$path))
+ ->setIcon('create'));
+ }
$current_box = $this->createCurrentFragmentView($current, true);
@@ -44,6 +51,11 @@
->execute();
$files = mpull($files, null, 'getPHID');
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $current,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
$first = true;
foreach ($versions as $version) {
$item = id(new PHUIObjectItemView());
@@ -58,7 +70,7 @@
$item->addAttribute('Deletion');
}
- if (!$first) {
+ if (!$first && $can_edit) {
$item->addAction(id(new PHUIListItemView())
->setIcon('undo')
->setRenderNameAsTooltip(true)
@@ -75,9 +87,11 @@
->setRenderNameAsTooltip(true)
->setName(pht("Download"));
if (!$disabled) {
- $action->setHref($files[$version->getFilePHID()]->getBestURI());
+ $action->setHref($files[$version->getFilePHID()]
+ ->getDownloadDialogURI($version->getURI()));
}
$item->addAction($action);
+
$list->addItem($item);
$first = false;
Index: src/applications/phragment/controller/PhragmentPatchController.php
===================================================================
--- src/applications/phragment/controller/PhragmentPatchController.php
+++ src/applications/phragment/controller/PhragmentPatchController.php
@@ -5,6 +5,10 @@
private $aid;
private $bid;
+ public function shouldAllowPublic() {
+ return true;
+ }
+
public function willProcessRequest(array $data) {
$this->aid = idx($data, "aid", 0);
$this->bid = idx($data, "bid", 0);
@@ -61,7 +65,9 @@
$patch = PhragmentPatchUtil::calculatePatch($file_a, $file_b);
if ($patch === null) {
- throw new Exception("Unable to compute patch!");
+ // There are no differences between the two files, so we output
+ // an empty patch.
+ $patch = '';
}
$a_sequence = 'x';
@@ -74,6 +80,11 @@
$a_sequence.'.'.
$version_b->getSequence().'.patch';
+ $return = $version_b->getURI();
+ if ($request->getExists('return')) {
+ $return = $request->getStr('return');
+ }
+
$result = PhabricatorFile::buildFromFileDataOrHash(
$patch,
array(
@@ -81,8 +92,13 @@
'mime-type' => 'text/plain',
'ttl' => time() + 60 * 60 * 24,
));
+
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+ $result->attachToObject($viewer, $version_b->getFragmentPHID());
+ unset($unguarded);
+
return id(new AphrontRedirectResponse())
- ->setURI($result->getBestURI());
+ ->setURI($result->getDownloadDialogURI($return));
}
}
Index: src/applications/phragment/controller/PhragmentPolicyController.php
===================================================================
--- /dev/null
+++ src/applications/phragment/controller/PhragmentPolicyController.php
@@ -0,0 +1,109 @@
+<?php
+
+final class PhragmentPolicyController 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 = idx($parents, count($parents) - 1, null);
+
+ $error_view = null;
+
+ if ($request->isFormPost()) {
+ $errors = array();
+
+ $v_view_policy = $request->getStr('viewPolicy');
+ $v_edit_policy = $request->getStr('editPolicy');
+ $v_replace_children = $request->getBool('replacePoliciesOnChildren');
+
+ $fragment->setViewPolicy($v_view_policy);
+ $fragment->setEditPolicy($v_edit_policy);
+
+ $fragment->save();
+
+ if ($v_replace_children) {
+ // If you can edit a fragment, you can forcibly set the policies
+ // on child fragments, regardless of whether you can see them or not.
+ $children = id(new PhragmentFragmentQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withLeadingPath($fragment->getPath().'/')
+ ->execute();
+ $children_phids = mpull($children, 'getPHID');
+
+ $fragment->openTransaction();
+ foreach ($children as $child) {
+ $child->setViewPolicy($v_view_policy);
+ $child->setEditPolicy($v_edit_policy);
+ $child->save();
+ }
+ $fragment->saveTransaction();
+ }
+
+ return id(new AphrontRedirectResponse())
+ ->setURI('/phragment/browse/'.$fragment->getPath());
+ }
+
+ $policies = id(new PhabricatorPolicyQuery())
+ ->setViewer($viewer)
+ ->setObject($fragment)
+ ->execute();
+
+ $form = id(new AphrontFormView())
+ ->setUser($viewer)
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('viewPolicy')
+ ->setPolicyObject($fragment)
+ ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
+ ->setPolicies($policies))
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('editPolicy')
+ ->setPolicyObject($fragment)
+ ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
+ ->setPolicies($policies))
+ ->appendChild(
+ id(new AphrontFormCheckboxControl())
+ ->addCheckbox(
+ 'replacePoliciesOnChildren',
+ 'true',
+ pht(
+ 'Replace policies on child fragments with '.
+ 'the policies above.')))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue(pht('Save Fragment Policies'))
+ ->addCancelButton(
+ $this->getApplicationURI('browse/'.$fragment->getPath())));
+
+ $crumbs = $this->buildApplicationCrumbsWithPath($parents);
+ $crumbs->addCrumb(
+ id(new PhabricatorCrumbView())
+ ->setName(pht('Edit Fragment Policies')));
+
+ $box = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Edit Fragment Policies: %s', $fragment->getPath()))
+ ->setValidationException(null)
+ ->setForm($form);
+
+ return $this->buildApplicationPage(
+ array(
+ $crumbs,
+ $box),
+ array(
+ 'title' => pht('Edit Fragment Policies'),
+ 'device' => true));
+ }
+
+}
Index: src/applications/phragment/controller/PhragmentSnapshotCreateController.php
===================================================================
--- src/applications/phragment/controller/PhragmentSnapshotCreateController.php
+++ src/applications/phragment/controller/PhragmentSnapshotCreateController.php
@@ -21,6 +21,11 @@
return new Aphront404Response();
}
+ PhabricatorPolicyFilter::requireCapability(
+ $viewer,
+ $fragment,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
$children = id(new PhragmentFragmentQuery())
->setViewer($viewer)
->needLatestVersion(true)
Index: src/applications/phragment/controller/PhragmentSnapshotDeleteController.php
===================================================================
--- src/applications/phragment/controller/PhragmentSnapshotDeleteController.php
+++ src/applications/phragment/controller/PhragmentSnapshotDeleteController.php
@@ -14,6 +14,9 @@
$snapshot = id(new PhragmentSnapshotQuery())
->setViewer($viewer)
+ ->requireCapabilities(array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT))
->withIDs(array($this->id))
->executeOne();
if ($snapshot === null) {
Index: src/applications/phragment/controller/PhragmentSnapshotPromoteController.php
===================================================================
--- src/applications/phragment/controller/PhragmentSnapshotPromoteController.php
+++ src/applications/phragment/controller/PhragmentSnapshotPromoteController.php
@@ -23,6 +23,9 @@
if ($this->dblob !== null) {
$this->targetFragment = id(new PhragmentFragmentQuery())
->setViewer($viewer)
+ ->requireCapabilities(array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT))
->withPaths(array($this->dblob))
->executeOne();
if ($this->targetFragment === null) {
@@ -40,6 +43,9 @@
if ($this->id !== null) {
$this->targetSnapshot = id(new PhragmentSnapshotQuery())
->setViewer($viewer)
+ ->requireCapabilities(array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT))
->withIDs(array($this->id))
->executeOne();
if ($this->targetSnapshot === null) {
@@ -141,7 +147,13 @@
}
$snapshot->saveTransaction();
- return id(new AphrontRedirectResponse());
+ if ($this->id === null) {
+ return id(new AphrontRedirectResponse())
+ ->setURI($this->targetFragment->getURI());
+ } else {
+ return id(new AphrontRedirectResponse())
+ ->setURI($this->targetSnapshot->getURI());
+ }
}
return $this->createDialog();
Index: src/applications/phragment/controller/PhragmentSnapshotViewController.php
===================================================================
--- src/applications/phragment/controller/PhragmentSnapshotViewController.php
+++ src/applications/phragment/controller/PhragmentSnapshotViewController.php
@@ -4,6 +4,10 @@
private $id;
+ public function shouldAllowPublic() {
+ return true;
+ }
+
public function willProcessRequest(array $data) {
$this->id = idx($data, "id", "");
}
@@ -100,6 +104,11 @@
"zip@".$snapshot->getName().
"/".$snapshot->getPrimaryFragment()->getPath());
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $snapshot,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
$actions = id(new PhabricatorActionListView())
->setUser($viewer)
->setObject($snapshot)
@@ -108,23 +117,22 @@
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()."/"))
+ ->setDisabled(!$can_edit)
->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()."/"))
+ ->setDisabled(!$can_edit)
->setWorkflow(true)
- ->setDisabled(false) // TODO: Policy
->setIcon('promote'));
$properties = id(new PHUIPropertyListView())
Index: src/applications/phragment/controller/PhragmentVersionController.php
===================================================================
--- src/applications/phragment/controller/PhragmentVersionController.php
+++ src/applications/phragment/controller/PhragmentVersionController.php
@@ -4,6 +4,10 @@
private $id;
+ public function shouldAllowPublic() {
+ return true;
+ }
+
public function willProcessRequest(array $data) {
$this->id = idx($data, "id", 0);
}
@@ -41,7 +45,7 @@
->withPHIDs(array($version->getFilePHID()))
->executeOne();
if ($file !== null) {
- $file_uri = $file->getBestURI();
+ $file_uri = $file->getDownloadURI();
}
$header = id(new PHUIHeaderView())
@@ -61,6 +65,8 @@
->setName(pht('Download Version'))
->setHref($file_uri)
->setDisabled($file === null)
+ ->setRenderAsForm(true)
+ ->setDownload(true)
->setIcon('download'));
$properties = id(new PHUIPropertyListView())
Index: src/applications/phragment/controller/PhragmentZIPController.php
===================================================================
--- src/applications/phragment/controller/PhragmentZIPController.php
+++ src/applications/phragment/controller/PhragmentZIPController.php
@@ -7,6 +7,10 @@
private $snapshotCache;
+ public function shouldAllowPublic() {
+ return true;
+ }
+
public function willProcessRequest(array $data) {
$this->dblob = idx($data, "dblob", "");
$this->snapshot = idx($data, "snapshot", null);
@@ -87,7 +91,9 @@
}
foreach ($mappings as $path => $file) {
- $zip->addFromString($path, $file->loadFileData());
+ if ($file !== null) {
+ $zip->addFromString($path, $file->loadFileData());
+ }
}
$zip->close();
@@ -103,8 +109,18 @@
'name' => $zip_name,
'ttl' => time() + 60 * 60 * 24,
));
+
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+ $file->attachToObject($viewer, $fragment->getPHID());
+ unset($unguarded);
+
+ $return = $fragment->getURI();
+ if ($request->getExists('return')) {
+ $return = $request->getStr('return');
+ }
+
return id(new AphrontRedirectResponse())
- ->setURI($file->getBestURI());
+ ->setURI($file->getDownloadDialogURI($return));
}
/**
Index: src/applications/phragment/storage/PhragmentFragment.php
===================================================================
--- src/applications/phragment/storage/PhragmentFragment.php
+++ src/applications/phragment/storage/PhragmentFragment.php
@@ -118,6 +118,8 @@
$this->setLatestVersionPHID($version->getPHID());
$this->save();
$this->saveTransaction();
+
+ $file->attachToObject($viewer, $version->getPHID());
}
/**
Index: src/applications/phragment/storage/PhragmentSnapshot.php
===================================================================
--- src/applications/phragment/storage/PhragmentSnapshot.php
+++ src/applications/phragment/storage/PhragmentSnapshot.php
@@ -48,9 +48,7 @@
public function getCapabilities() {
- return array(
- PhabricatorPolicyCapability::CAN_VIEW
- );
+ return $this->getPrimaryFragment()->getCapabilities();
}
public function getPolicy($capability) {
Index: src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
===================================================================
--- src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
+++ src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
@@ -1828,6 +1828,10 @@
'type' => 'sql',
'name' => $this->getPatchPath('20131208.phragmentsnapshot.sql'),
),
+ '20131211.phragmentedges.sql' => array(
+ 'type' => 'sql',
+ 'name' => $this->getPatchPath('20131211.phragmentedges.sql'),
+ ),
);
}
}
Index: src/view/layout/PhabricatorActionView.php
===================================================================
--- src/view/layout/PhabricatorActionView.php
+++ src/view/layout/PhabricatorActionView.php
@@ -40,7 +40,7 @@
* viewing.
*/
public function getHref() {
- if ($this->workflow || $this->renderAsForm) {
+ if (($this->workflow || $this->renderAsForm) && !$this->download) {
if (!$this->user || !$this->user->isLoggedIn()) {
return id(new PhutilURI('/auth/start/'))
->setQueryParam('next', (string)$this->getObjectURI());
Index: webroot/rsrc/js/application/files/behavior-files-download-redirect.js
===================================================================
--- /dev/null
+++ webroot/rsrc/js/application/files/behavior-files-download-redirect.js
@@ -0,0 +1,19 @@
+/**
+ * @provides javelin-behavior-files-download-redirect
+ * @requires javelin-behavior
+ * javelin-dom
+ * javelin-workflow
+ */
+
+JX.behavior('files-download-redirect', function(config) {
+
+ JX.DOM.listen(
+ JX.$(config.dialogID),
+ 'submit',
+ null,
+ function(e) {
+ window.setTimeout(function() { location.href = config.return; }, 2000);
+ });
+
+});
+
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Apr 3, 10:47 PM (1 w, 22 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7706136
Default Alt Text
D7751.id17551.diff (30 KB)
Attached To
Mode
D7751: Implement policies in Phragment
Attached
Detach File
Event Timeline
Log In to Comment