mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-18 21:02:41 +01:00
Support Spaces transactions
Summary: Ref T8424. This adds crude integration with Paste's edit/view workflows: you can change the space a Paste appears in, see transactions, and get a policy callout. Lots of rough edges and non-obviousness but it pretty much works. Test Plan: - Created and updated Pastes. - Moved them between spaces, saw policy effects. - Read transactions. - Looked at feed. - Faked query to return no spaces, saw control and other stuff vanish. - Faked query to return no spaces, created pastes. - Tried to submit bad values and got errors. Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8424 Differential Revision: https://secure.phabricator.com/D13159
This commit is contained in:
parent
5deaeec668
commit
ef90007a21
13 changed files with 306 additions and 79 deletions
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
return array(
|
return array(
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'core.pkg.css' => 'e2460e8f',
|
'core.pkg.css' => 'd7ecac6d',
|
||||||
'core.pkg.js' => '3bbe23c6',
|
'core.pkg.js' => '3bbe23c6',
|
||||||
'darkconsole.pkg.js' => 'e7393ebb',
|
'darkconsole.pkg.js' => 'e7393ebb',
|
||||||
'differential.pkg.css' => '02273347',
|
'differential.pkg.css' => '02273347',
|
||||||
|
@ -136,7 +136,7 @@ return array(
|
||||||
'rsrc/css/phui/phui-fontkit.css' => 'dd8ddf27',
|
'rsrc/css/phui/phui-fontkit.css' => 'dd8ddf27',
|
||||||
'rsrc/css/phui/phui-form-view.css' => '808329f2',
|
'rsrc/css/phui/phui-form-view.css' => '808329f2',
|
||||||
'rsrc/css/phui/phui-form.css' => '25876baf',
|
'rsrc/css/phui/phui-form.css' => '25876baf',
|
||||||
'rsrc/css/phui/phui-header-view.css' => '75aaf372',
|
'rsrc/css/phui/phui-header-view.css' => '2dd74fe0',
|
||||||
'rsrc/css/phui/phui-icon.css' => 'bc766998',
|
'rsrc/css/phui/phui-icon.css' => 'bc766998',
|
||||||
'rsrc/css/phui/phui-image-mask.css' => '5a8b09c8',
|
'rsrc/css/phui/phui-image-mask.css' => '5a8b09c8',
|
||||||
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
|
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
|
||||||
|
@ -779,7 +779,7 @@ return array(
|
||||||
'phui-fontkit-css' => 'dd8ddf27',
|
'phui-fontkit-css' => 'dd8ddf27',
|
||||||
'phui-form-css' => '25876baf',
|
'phui-form-css' => '25876baf',
|
||||||
'phui-form-view-css' => '808329f2',
|
'phui-form-view-css' => '808329f2',
|
||||||
'phui-header-view-css' => '75aaf372',
|
'phui-header-view-css' => '2dd74fe0',
|
||||||
'phui-icon-view-css' => 'bc766998',
|
'phui-icon-view-css' => 'bc766998',
|
||||||
'phui-image-mask-css' => '5a8b09c8',
|
'phui-image-mask-css' => '5a8b09c8',
|
||||||
'phui-info-panel-css' => '27ea50a1',
|
'phui-info-panel-css' => '27ea50a1',
|
||||||
|
|
|
@ -2560,6 +2560,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSpacesCapabilityCreateSpaces' => 'applications/spaces/capability/PhabricatorSpacesCapabilityCreateSpaces.php',
|
'PhabricatorSpacesCapabilityCreateSpaces' => 'applications/spaces/capability/PhabricatorSpacesCapabilityCreateSpaces.php',
|
||||||
'PhabricatorSpacesCapabilityDefaultEdit' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultEdit.php',
|
'PhabricatorSpacesCapabilityDefaultEdit' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultEdit.php',
|
||||||
'PhabricatorSpacesCapabilityDefaultView' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultView.php',
|
'PhabricatorSpacesCapabilityDefaultView' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultView.php',
|
||||||
|
'PhabricatorSpacesControl' => 'applications/spaces/view/PhabricatorSpacesControl.php',
|
||||||
'PhabricatorSpacesController' => 'applications/spaces/controller/PhabricatorSpacesController.php',
|
'PhabricatorSpacesController' => 'applications/spaces/controller/PhabricatorSpacesController.php',
|
||||||
'PhabricatorSpacesDAO' => 'applications/spaces/storage/PhabricatorSpacesDAO.php',
|
'PhabricatorSpacesDAO' => 'applications/spaces/storage/PhabricatorSpacesDAO.php',
|
||||||
'PhabricatorSpacesEditController' => 'applications/spaces/controller/PhabricatorSpacesEditController.php',
|
'PhabricatorSpacesEditController' => 'applications/spaces/controller/PhabricatorSpacesEditController.php',
|
||||||
|
@ -6041,6 +6042,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSpacesCapabilityCreateSpaces' => 'PhabricatorPolicyCapability',
|
'PhabricatorSpacesCapabilityCreateSpaces' => 'PhabricatorPolicyCapability',
|
||||||
'PhabricatorSpacesCapabilityDefaultEdit' => 'PhabricatorPolicyCapability',
|
'PhabricatorSpacesCapabilityDefaultEdit' => 'PhabricatorPolicyCapability',
|
||||||
'PhabricatorSpacesCapabilityDefaultView' => 'PhabricatorPolicyCapability',
|
'PhabricatorSpacesCapabilityDefaultView' => 'PhabricatorPolicyCapability',
|
||||||
|
'PhabricatorSpacesControl' => 'AphrontFormControl',
|
||||||
'PhabricatorSpacesController' => 'PhabricatorController',
|
'PhabricatorSpacesController' => 'PhabricatorController',
|
||||||
'PhabricatorSpacesDAO' => 'PhabricatorLiskDAO',
|
'PhabricatorSpacesDAO' => 'PhabricatorLiskDAO',
|
||||||
'PhabricatorSpacesEditController' => 'PhabricatorSpacesController',
|
'PhabricatorSpacesEditController' => 'PhabricatorSpacesController',
|
||||||
|
|
|
@ -57,13 +57,12 @@ final class PhabricatorPasteEditController extends PhabricatorPasteController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$text = null;
|
$v_space = $paste->getSpacePHID();
|
||||||
$e_text = true;
|
|
||||||
$errors = array();
|
|
||||||
if ($is_create && $parent) {
|
if ($is_create && $parent) {
|
||||||
$v_title = pht('Fork of %s', $parent->getFullName());
|
$v_title = pht('Fork of %s', $parent->getFullName());
|
||||||
$v_language = $parent->getLanguage();
|
$v_language = $parent->getLanguage();
|
||||||
$v_text = $parent->getRawContent();
|
$v_text = $parent->getRawContent();
|
||||||
|
$v_space = $parent->getSpacePHID();
|
||||||
} else {
|
} else {
|
||||||
$v_title = $paste->getTitle();
|
$v_title = $paste->getTitle();
|
||||||
$v_language = $paste->getLanguage();
|
$v_language = $paste->getLanguage();
|
||||||
|
@ -81,27 +80,21 @@ final class PhabricatorPasteEditController extends PhabricatorPasteController {
|
||||||
$v_projects = array_reverse($v_projects);
|
$v_projects = array_reverse($v_projects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$validation_exception = null;
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
$xactions = array();
|
$xactions = array();
|
||||||
|
|
||||||
$v_text = $request->getStr('text');
|
$v_text = $request->getStr('text');
|
||||||
if (!strlen($v_text)) {
|
|
||||||
$e_text = pht('Required');
|
|
||||||
$errors[] = pht('The paste may not be blank.');
|
|
||||||
} else {
|
|
||||||
$e_text = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$v_title = $request->getStr('title');
|
$v_title = $request->getStr('title');
|
||||||
$v_language = $request->getStr('language');
|
$v_language = $request->getStr('language');
|
||||||
$v_view_policy = $request->getStr('can_view');
|
$v_view_policy = $request->getStr('can_view');
|
||||||
$v_edit_policy = $request->getStr('can_edit');
|
$v_edit_policy = $request->getStr('can_edit');
|
||||||
$v_projects = $request->getArr('projects');
|
$v_projects = $request->getArr('projects');
|
||||||
|
$v_space = $request->getStr('spacePHID');
|
||||||
|
|
||||||
// NOTE: The author is the only editor and can always view the paste,
|
// NOTE: The author is the only editor and can always view the paste,
|
||||||
// so it's impossible for them to choose an invalid policy.
|
// so it's impossible for them to choose an invalid policy.
|
||||||
|
|
||||||
if (!$errors) {
|
|
||||||
if ($is_create || ($v_text !== $paste->getRawContent())) {
|
if ($is_create || ($v_text !== $paste->getRawContent())) {
|
||||||
$file = PhabricatorPasteEditor::initializeFileForPaste(
|
$file = PhabricatorPasteEditor::initializeFileForPaste(
|
||||||
$user,
|
$user,
|
||||||
|
@ -125,6 +118,9 @@ final class PhabricatorPasteEditController extends PhabricatorPasteController {
|
||||||
$xactions[] = id(new PhabricatorPasteTransaction())
|
$xactions[] = id(new PhabricatorPasteTransaction())
|
||||||
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
|
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
|
||||||
->setNewValue($v_edit_policy);
|
->setNewValue($v_edit_policy);
|
||||||
|
$xactions[] = id(new PhabricatorPasteTransaction())
|
||||||
|
->setTransactionType(PhabricatorTransactions::TYPE_SPACE)
|
||||||
|
->setNewValue($v_space);
|
||||||
|
|
||||||
$proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
|
$proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
|
||||||
$xactions[] = id(new PhabricatorPasteTransaction())
|
$xactions[] = id(new PhabricatorPasteTransaction())
|
||||||
|
@ -136,13 +132,12 @@ final class PhabricatorPasteEditController extends PhabricatorPasteController {
|
||||||
->setActor($user)
|
->setActor($user)
|
||||||
->setContentSourceFromRequest($request)
|
->setContentSourceFromRequest($request)
|
||||||
->setContinueOnNoEffect(true);
|
->setContinueOnNoEffect(true);
|
||||||
|
|
||||||
|
try {
|
||||||
$xactions = $editor->applyTransactions($paste, $xactions);
|
$xactions = $editor->applyTransactions($paste, $xactions);
|
||||||
return id(new AphrontRedirectResponse())->setURI($paste->getURI());
|
return id(new AphrontRedirectResponse())->setURI($paste->getURI());
|
||||||
} else {
|
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||||
// make sure we update policy so its correctly populated to what
|
$validation_exception = $ex;
|
||||||
// the user chose
|
|
||||||
$paste->setViewPolicy($v_view_policy);
|
|
||||||
$paste->setEditPolicy($v_edit_policy);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,12 +167,19 @@ final class PhabricatorPasteEditController extends PhabricatorPasteController {
|
||||||
->setObject($paste)
|
->setObject($paste)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
|
$form->appendControl(
|
||||||
|
id(new PhabricatorSpacesControl())
|
||||||
|
->setObject($paste)
|
||||||
|
->setValue($v_space)
|
||||||
|
->setName('spacePHID'));
|
||||||
|
|
||||||
$form->appendChild(
|
$form->appendChild(
|
||||||
id(new AphrontFormPolicyControl())
|
id(new AphrontFormPolicyControl())
|
||||||
->setUser($user)
|
->setUser($user)
|
||||||
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
|
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
|
||||||
->setPolicyObject($paste)
|
->setPolicyObject($paste)
|
||||||
->setPolicies($policies)
|
->setPolicies($policies)
|
||||||
|
->setValue($v_view_policy)
|
||||||
->setName('can_view'));
|
->setName('can_view'));
|
||||||
|
|
||||||
$form->appendChild(
|
$form->appendChild(
|
||||||
|
@ -186,6 +188,7 @@ final class PhabricatorPasteEditController extends PhabricatorPasteController {
|
||||||
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
|
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
|
||||||
->setPolicyObject($paste)
|
->setPolicyObject($paste)
|
||||||
->setPolicies($policies)
|
->setPolicies($policies)
|
||||||
|
->setValue($v_edit_policy)
|
||||||
->setName('can_edit'));
|
->setName('can_edit'));
|
||||||
|
|
||||||
$form->appendControl(
|
$form->appendControl(
|
||||||
|
@ -199,7 +202,6 @@ final class PhabricatorPasteEditController extends PhabricatorPasteController {
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormTextAreaControl())
|
id(new AphrontFormTextAreaControl())
|
||||||
->setLabel(pht('Text'))
|
->setLabel(pht('Text'))
|
||||||
->setError($e_text)
|
|
||||||
->setValue($v_text)
|
->setValue($v_text)
|
||||||
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
|
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
|
||||||
->setCustomClass('PhabricatorMonospaced')
|
->setCustomClass('PhabricatorMonospaced')
|
||||||
|
@ -222,9 +224,12 @@ final class PhabricatorPasteEditController extends PhabricatorPasteController {
|
||||||
|
|
||||||
$form_box = id(new PHUIObjectBoxView())
|
$form_box = id(new PHUIObjectBoxView())
|
||||||
->setHeaderText($title)
|
->setHeaderText($title)
|
||||||
->setFormErrors($errors)
|
|
||||||
->setForm($form);
|
->setForm($form);
|
||||||
|
|
||||||
|
if ($validation_exception) {
|
||||||
|
$form_box->setValidationException($validation_exception);
|
||||||
|
}
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs($this->buildSideNavView());
|
$crumbs = $this->buildApplicationCrumbs($this->buildSideNavView());
|
||||||
if (!$is_create) {
|
if (!$is_create) {
|
||||||
$crumbs->addTextCrumb('P'.$paste->getID(), '/P'.$paste->getID());
|
$crumbs->addTextCrumb('P'.$paste->getID(), '/P'.$paste->getID());
|
||||||
|
|
|
@ -42,7 +42,11 @@ final class PhabricatorPaste extends PhabricatorPasteDAO
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getURI() {
|
public function getURI() {
|
||||||
return '/P'.$this->getID();
|
return '/'.$this->getMonogram();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMonogram() {
|
||||||
|
return 'P'.$this->getID();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getConfiguration() {
|
protected function getConfiguration() {
|
||||||
|
|
|
@ -751,6 +751,20 @@ final class PhabricatorUser
|
||||||
$email->getUserPHID());
|
$email->getUserPHID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDefaultSpacePHID() {
|
||||||
|
// TODO: We might let the user switch which space they're "in" later on;
|
||||||
|
// for now just use the global space if one exists.
|
||||||
|
|
||||||
|
$spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($this);
|
||||||
|
foreach ($spaces as $space) {
|
||||||
|
if ($space->getIsDefaultNamespace()) {
|
||||||
|
return $space->getPHID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Grant a user a source of authority, to let them bypass policy checks they
|
* Grant a user a source of authority, to let them bypass policy checks they
|
||||||
|
|
|
@ -15,7 +15,7 @@ final class PhabricatorSpacesApplication extends PhabricatorApplication {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFontIcon() {
|
public function getFontIcon() {
|
||||||
return 'fa-compass';
|
return 'fa-th-large';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTitleGlyph() {
|
public function getTitleGlyph() {
|
||||||
|
|
|
@ -28,7 +28,10 @@ final class PhabricatorSpacesNamespacePHIDType
|
||||||
|
|
||||||
foreach ($handles as $phid => $handle) {
|
foreach ($handles as $phid => $handle) {
|
||||||
$namespace = $objects[$phid];
|
$namespace = $objects[$phid];
|
||||||
|
$monogram = $namespace->getMonogram();
|
||||||
|
|
||||||
$handle->setName($namespace->getNamespaceName());
|
$handle->setName($namespace->getNamespaceName());
|
||||||
|
$handle->setURI('/'.$monogram);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
49
src/applications/spaces/view/PhabricatorSpacesControl.php
Normal file
49
src/applications/spaces/view/PhabricatorSpacesControl.php
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorSpacesControl extends AphrontFormControl {
|
||||||
|
|
||||||
|
private $object;
|
||||||
|
|
||||||
|
protected function shouldRender() {
|
||||||
|
// Render this control only if some Spaces exist.
|
||||||
|
return PhabricatorSpacesNamespaceQuery::getAllSpaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setObject(PhabricatorSpacesInterface $object) {
|
||||||
|
$this->object = $object;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCustomControlClass() {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getOptions() {
|
||||||
|
$viewer = $this->getUser();
|
||||||
|
$viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer);
|
||||||
|
|
||||||
|
$map = mpull($viewer_spaces, 'getNamespaceName', 'getPHID');
|
||||||
|
asort($map);
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderInput() {
|
||||||
|
$viewer = $this->getUser();
|
||||||
|
|
||||||
|
$this->setLabel(pht('Space'));
|
||||||
|
|
||||||
|
$value = $this->getValue();
|
||||||
|
if ($value === null) {
|
||||||
|
$value = $viewer->getDefaultSpacePHID();
|
||||||
|
}
|
||||||
|
|
||||||
|
return AphrontFormSelectControl::renderSelectTag(
|
||||||
|
$value,
|
||||||
|
$this->getOptions(),
|
||||||
|
array(
|
||||||
|
'name' => $this->getName(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ final class PhabricatorTransactions {
|
||||||
const TYPE_BUILDABLE = 'harbormaster:buildable';
|
const TYPE_BUILDABLE = 'harbormaster:buildable';
|
||||||
const TYPE_TOKEN = 'token:give';
|
const TYPE_TOKEN = 'token:give';
|
||||||
const TYPE_INLINESTATE = 'core:inlinestate';
|
const TYPE_INLINESTATE = 'core:inlinestate';
|
||||||
|
const TYPE_SPACE = 'core:space';
|
||||||
|
|
||||||
const COLOR_RED = 'red';
|
const COLOR_RED = 'red';
|
||||||
const COLOR_ORANGE = 'orange';
|
const COLOR_ORANGE = 'orange';
|
||||||
|
|
|
@ -264,6 +264,10 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->object instanceof PhabricatorSpacesInterface) {
|
||||||
|
$types[] = PhabricatorTransactions::TYPE_SPACE;
|
||||||
|
}
|
||||||
|
|
||||||
return $types;
|
return $types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,6 +296,21 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
return $object->getEditPolicy();
|
return $object->getEditPolicy();
|
||||||
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
||||||
return $object->getJoinPolicy();
|
return $object->getJoinPolicy();
|
||||||
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
|
$space_phid = $object->getSpacePHID();
|
||||||
|
if ($space_phid === null) {
|
||||||
|
if ($this->getIsNewObject()) {
|
||||||
|
// In this case, just return `null` so we know this is the initial
|
||||||
|
// transaction and it should be hidden.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$default_space = PhabricatorSpacesNamespaceQuery::getDefaultSpace();
|
||||||
|
if ($default_space) {
|
||||||
|
$space_phid = $default_space->getPHID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $space_phid;
|
||||||
case PhabricatorTransactions::TYPE_EDGE:
|
case PhabricatorTransactions::TYPE_EDGE:
|
||||||
$edge_type = $xaction->getMetadataValue('edge:type');
|
$edge_type = $xaction->getMetadataValue('edge:type');
|
||||||
if (!$edge_type) {
|
if (!$edge_type) {
|
||||||
|
@ -337,7 +356,16 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
case PhabricatorTransactions::TYPE_BUILDABLE:
|
case PhabricatorTransactions::TYPE_BUILDABLE:
|
||||||
case PhabricatorTransactions::TYPE_TOKEN:
|
case PhabricatorTransactions::TYPE_TOKEN:
|
||||||
case PhabricatorTransactions::TYPE_INLINESTATE:
|
case PhabricatorTransactions::TYPE_INLINESTATE:
|
||||||
return $xaction->getNewValue();
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
|
$space_phid = $xaction->getNewValue();
|
||||||
|
if (!strlen($space_phid)) {
|
||||||
|
// If an install has no Spaces, we might end up with the empty string
|
||||||
|
// here instead of a strict `null`. Just make this work like callers
|
||||||
|
// might reasonably expect.
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return $space_phid;
|
||||||
|
}
|
||||||
case PhabricatorTransactions::TYPE_EDGE:
|
case PhabricatorTransactions::TYPE_EDGE:
|
||||||
return $this->getEdgeTransactionNewValue($xaction);
|
return $this->getEdgeTransactionNewValue($xaction);
|
||||||
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
|
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
|
||||||
|
@ -437,6 +465,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
|
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
|
||||||
case PhabricatorTransactions::TYPE_INLINESTATE:
|
case PhabricatorTransactions::TYPE_INLINESTATE:
|
||||||
case PhabricatorTransactions::TYPE_EDGE:
|
case PhabricatorTransactions::TYPE_EDGE:
|
||||||
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
case PhabricatorTransactions::TYPE_COMMENT:
|
case PhabricatorTransactions::TYPE_COMMENT:
|
||||||
return $this->applyBuiltinInternalTransaction($object, $xaction);
|
return $this->applyBuiltinInternalTransaction($object, $xaction);
|
||||||
}
|
}
|
||||||
|
@ -485,6 +514,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
||||||
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
||||||
case PhabricatorTransactions::TYPE_INLINESTATE:
|
case PhabricatorTransactions::TYPE_INLINESTATE:
|
||||||
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
case PhabricatorTransactions::TYPE_COMMENT:
|
case PhabricatorTransactions::TYPE_COMMENT:
|
||||||
return $this->applyBuiltinExternalTransaction($object, $xaction);
|
return $this->applyBuiltinExternalTransaction($object, $xaction);
|
||||||
}
|
}
|
||||||
|
@ -537,6 +567,9 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
||||||
$object->setJoinPolicy($xaction->getNewValue());
|
$object->setJoinPolicy($xaction->getNewValue());
|
||||||
break;
|
break;
|
||||||
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
|
$object->setSpacePHID($xaction->getNewValue());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1190,18 +1223,9 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
PhabricatorPolicyCapability::CAN_VIEW);
|
PhabricatorPolicyCapability::CAN_VIEW);
|
||||||
break;
|
break;
|
||||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
|
||||||
$actor,
|
|
||||||
$object,
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
|
||||||
break;
|
|
||||||
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
|
||||||
$actor,
|
|
||||||
$object,
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
|
||||||
break;
|
|
||||||
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
||||||
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
PhabricatorPolicyFilter::requireCapability(
|
||||||
$actor,
|
$actor,
|
||||||
$object,
|
$object,
|
||||||
|
@ -1882,6 +1906,12 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
$type,
|
$type,
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
break;
|
break;
|
||||||
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
|
$errors[] = $this->validateSpaceTransactions(
|
||||||
|
$object,
|
||||||
|
$xactions,
|
||||||
|
$type);
|
||||||
|
break;
|
||||||
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
|
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
|
||||||
$groups = array();
|
$groups = array();
|
||||||
foreach ($xactions as $xaction) {
|
foreach ($xactions as $xaction) {
|
||||||
|
@ -1968,6 +1998,52 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function validateSpaceTransactions(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
array $xactions,
|
||||||
|
$transaction_type) {
|
||||||
|
$errors = array();
|
||||||
|
|
||||||
|
$all_spaces = PhabricatorSpacesNamespaceQuery::getAllSpaces();
|
||||||
|
$viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces(
|
||||||
|
$this->getActor());
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$space_phid = $xaction->getNewValue();
|
||||||
|
|
||||||
|
if ($space_phid === null) {
|
||||||
|
if (!$all_spaces) {
|
||||||
|
// The install doesn't have any spaces, so this is fine.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The install has some spaces, so every object needs to be put
|
||||||
|
// in a valid space.
|
||||||
|
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||||
|
$transaction_type,
|
||||||
|
pht('Invalid'),
|
||||||
|
pht('You must choose a space for this object.'),
|
||||||
|
$xaction);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the PHID isn't `null`, it needs to be a valid space that the
|
||||||
|
// viewer can see.
|
||||||
|
if (empty($viewer_spaces[$space_phid])) {
|
||||||
|
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||||
|
$transaction_type,
|
||||||
|
pht('Invalid'),
|
||||||
|
pht(
|
||||||
|
'You can not shift this object in the selected space, because '.
|
||||||
|
'the space does not exist or you do not have access to it.'),
|
||||||
|
$xaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function adjustObjectForPolicyChecks(
|
protected function adjustObjectForPolicyChecks(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
array $xactions) {
|
array $xactions) {
|
||||||
|
|
|
@ -250,6 +250,14 @@ abstract class PhabricatorApplicationTransaction
|
||||||
$phids[] = array($new);
|
$phids[] = array($new);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
|
if ($old) {
|
||||||
|
$phids[] = array($old);
|
||||||
|
}
|
||||||
|
if ($new) {
|
||||||
|
$phids[] = array($new);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case PhabricatorTransactions::TYPE_TOKEN:
|
case PhabricatorTransactions::TYPE_TOKEN:
|
||||||
break;
|
break;
|
||||||
case PhabricatorTransactions::TYPE_BUILDABLE:
|
case PhabricatorTransactions::TYPE_BUILDABLE:
|
||||||
|
@ -369,6 +377,8 @@ abstract class PhabricatorApplicationTransaction
|
||||||
return 'fa-wrench';
|
return 'fa-wrench';
|
||||||
case PhabricatorTransactions::TYPE_TOKEN:
|
case PhabricatorTransactions::TYPE_TOKEN:
|
||||||
return 'fa-trophy';
|
return 'fa-trophy';
|
||||||
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
|
return 'fa-th-large';
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'fa-pencil';
|
return 'fa-pencil';
|
||||||
|
@ -438,6 +448,7 @@ abstract class PhabricatorApplicationTransaction
|
||||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||||
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
||||||
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
case PhabricatorTransactions::TYPE_JOIN_POLICY:
|
||||||
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
if ($this->getOldValue() === null) {
|
if ($this->getOldValue() === null) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -597,6 +608,8 @@ abstract class PhabricatorApplicationTransaction
|
||||||
return pht(
|
return pht(
|
||||||
'All users are already subscribed to this %s.',
|
'All users are already subscribed to this %s.',
|
||||||
$this->getApplicationObjectTypeName());
|
$this->getApplicationObjectTypeName());
|
||||||
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
|
return pht('This object is already in that space.');
|
||||||
case PhabricatorTransactions::TYPE_EDGE:
|
case PhabricatorTransactions::TYPE_EDGE:
|
||||||
return pht('Edges already exist; transaction has no effect.');
|
return pht('Edges already exist; transaction has no effect.');
|
||||||
}
|
}
|
||||||
|
@ -636,6 +649,12 @@ abstract class PhabricatorApplicationTransaction
|
||||||
$this->getApplicationObjectTypeName(),
|
$this->getApplicationObjectTypeName(),
|
||||||
$this->renderPolicyName($old, 'old'),
|
$this->renderPolicyName($old, 'old'),
|
||||||
$this->renderPolicyName($new, 'new'));
|
$this->renderPolicyName($new, 'new'));
|
||||||
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
|
return pht(
|
||||||
|
'%s shifted this object from the %s space to the %s space.',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
$this->renderHandleLink($old),
|
||||||
|
$this->renderHandleLink($new));
|
||||||
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
|
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
|
||||||
$add = array_diff($new, $old);
|
$add = array_diff($new, $old);
|
||||||
$rem = array_diff($old, $new);
|
$rem = array_diff($old, $new);
|
||||||
|
@ -821,6 +840,13 @@ abstract class PhabricatorApplicationTransaction
|
||||||
'%s updated subscribers of %s.',
|
'%s updated subscribers of %s.',
|
||||||
$this->renderHandleLink($author_phid),
|
$this->renderHandleLink($author_phid),
|
||||||
$this->renderHandleLink($object_phid));
|
$this->renderHandleLink($object_phid));
|
||||||
|
case PhabricatorTransactions::TYPE_SPACE:
|
||||||
|
return pht(
|
||||||
|
'%s shifted %s from the %s space to the %s space.',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
$this->renderHandleLink($object_phid),
|
||||||
|
$this->renderHandleLink($old),
|
||||||
|
$this->renderHandleLink($new));
|
||||||
case PhabricatorTransactions::TYPE_EDGE:
|
case PhabricatorTransactions::TYPE_EDGE:
|
||||||
$new = ipull($new, 'dst');
|
$new = ipull($new, 'dst');
|
||||||
$old = ipull($old, 'dst');
|
$old = ipull($old, 'dst');
|
||||||
|
|
|
@ -174,6 +174,20 @@ final class PHUIHeaderView extends AphrontTagView {
|
||||||
|
|
||||||
$header = array();
|
$header = array();
|
||||||
|
|
||||||
|
$header[] = $this->renderObjectSpaceInformation();
|
||||||
|
|
||||||
|
if ($this->objectName) {
|
||||||
|
$header[] = array(
|
||||||
|
phutil_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => '/'.$this->objectName,
|
||||||
|
),
|
||||||
|
$this->objectName),
|
||||||
|
' ',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->actionLinks) {
|
if ($this->actionLinks) {
|
||||||
$actions = array();
|
$actions = array();
|
||||||
foreach ($this->actionLinks as $button) {
|
foreach ($this->actionLinks as $button) {
|
||||||
|
@ -200,18 +214,6 @@ final class PHUIHeaderView extends AphrontTagView {
|
||||||
}
|
}
|
||||||
$header[] = $this->header;
|
$header[] = $this->header;
|
||||||
|
|
||||||
if ($this->objectName) {
|
|
||||||
array_unshift(
|
|
||||||
$header,
|
|
||||||
phutil_tag(
|
|
||||||
'a',
|
|
||||||
array(
|
|
||||||
'href' => '/'.$this->objectName,
|
|
||||||
),
|
|
||||||
$this->objectName),
|
|
||||||
' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->tags) {
|
if ($this->tags) {
|
||||||
$header[] = ' ';
|
$header[] = ' ';
|
||||||
$header[] = phutil_tag(
|
$header[] = phutil_tag(
|
||||||
|
@ -268,9 +270,9 @@ final class PHUIHeaderView extends AphrontTagView {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderPolicyProperty(PhabricatorPolicyInterface $object) {
|
private function renderPolicyProperty(PhabricatorPolicyInterface $object) {
|
||||||
$policies = PhabricatorPolicyQuery::loadPolicies(
|
$viewer = $this->getUser();
|
||||||
$this->getUser(),
|
|
||||||
$object);
|
$policies = PhabricatorPolicyQuery::loadPolicies($viewer, $object);
|
||||||
|
|
||||||
$view_capability = PhabricatorPolicyCapability::CAN_VIEW;
|
$view_capability = PhabricatorPolicyCapability::CAN_VIEW;
|
||||||
$policy = idx($policies, $view_capability);
|
$policy = idx($policies, $view_capability);
|
||||||
|
@ -294,4 +296,41 @@ final class PHUIHeaderView extends AphrontTagView {
|
||||||
|
|
||||||
return array($icon, $link);
|
return array($icon, $link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function renderObjectSpaceInformation() {
|
||||||
|
$viewer = $this->getUser();
|
||||||
|
|
||||||
|
$object = $this->policyObject;
|
||||||
|
if (!$object) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($object instanceof PhabricatorSpacesInterface)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$space_phid = $object->getSpacePHID();
|
||||||
|
if ($space_phid === null) {
|
||||||
|
$default_space = PhabricatorSpacesNamespaceQuery::getDefaultSpace();
|
||||||
|
if ($default_space) {
|
||||||
|
$space_phid = $default_space->getPHID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($space_phid === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return phutil_tag(
|
||||||
|
'span',
|
||||||
|
array(
|
||||||
|
'class' => 'spaces-name',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
$viewer->renderHandle($space_phid),
|
||||||
|
' | ',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,3 +140,11 @@ body.device-phone .phui-header-view {
|
||||||
.device .phui-header-action-links .phui-mobile-menu {
|
.device .phui-header-action-links .phui-mobile-menu {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spaces-name {
|
||||||
|
color: {$lightbluetext};
|
||||||
|
}
|
||||||
|
|
||||||
|
.spaces-name .phui-handle {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue