Page MenuHomePhabricator

D13159.id31806.diff
No OneTemporary

D13159.id31806.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2558,6 +2558,7 @@
'PhabricatorSpacesCapabilityCreateSpaces' => 'applications/spaces/capability/PhabricatorSpacesCapabilityCreateSpaces.php',
'PhabricatorSpacesCapabilityDefaultEdit' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultEdit.php',
'PhabricatorSpacesCapabilityDefaultView' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultView.php',
+ 'PhabricatorSpacesControl' => 'applications/spaces/view/PhabricatorSpacesControl.php',
'PhabricatorSpacesController' => 'applications/spaces/controller/PhabricatorSpacesController.php',
'PhabricatorSpacesDAO' => 'applications/spaces/storage/PhabricatorSpacesDAO.php',
'PhabricatorSpacesEditController' => 'applications/spaces/controller/PhabricatorSpacesEditController.php',
@@ -6037,6 +6038,7 @@
'PhabricatorSpacesCapabilityCreateSpaces' => 'PhabricatorPolicyCapability',
'PhabricatorSpacesCapabilityDefaultEdit' => 'PhabricatorPolicyCapability',
'PhabricatorSpacesCapabilityDefaultView' => 'PhabricatorPolicyCapability',
+ 'PhabricatorSpacesControl' => 'AphrontFormControl',
'PhabricatorSpacesController' => 'PhabricatorController',
'PhabricatorSpacesDAO' => 'PhabricatorLiskDAO',
'PhabricatorSpacesEditController' => 'PhabricatorSpacesController',
diff --git a/src/applications/paste/controller/PhabricatorPasteEditController.php b/src/applications/paste/controller/PhabricatorPasteEditController.php
--- a/src/applications/paste/controller/PhabricatorPasteEditController.php
+++ b/src/applications/paste/controller/PhabricatorPasteEditController.php
@@ -57,13 +57,12 @@
}
}
- $text = null;
- $e_text = true;
- $errors = array();
+ $v_space = $paste->getSpacePHID();
if ($is_create && $parent) {
$v_title = pht('Fork of %s', $parent->getFullName());
$v_language = $parent->getLanguage();
$v_text = $parent->getRawContent();
+ $v_space = $parent->getSpacePHID();
} else {
$v_title = $paste->getTitle();
$v_language = $paste->getLanguage();
@@ -81,68 +80,64 @@
$v_projects = array_reverse($v_projects);
}
+ $validation_exception = null;
if ($request->isFormPost()) {
$xactions = array();
$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_language = $request->getStr('language');
$v_view_policy = $request->getStr('can_view');
$v_edit_policy = $request->getStr('can_edit');
$v_projects = $request->getArr('projects');
+ $v_space = $request->getStr('spacePHID');
// NOTE: The author is the only editor and can always view the paste,
// so it's impossible for them to choose an invalid policy.
- if (!$errors) {
- if ($is_create || ($v_text !== $paste->getRawContent())) {
- $file = PhabricatorPasteEditor::initializeFileForPaste(
- $user,
- $v_title,
- $v_text);
-
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
- ->setNewValue($file->getPHID());
- }
+ if ($is_create || ($v_text !== $paste->getRawContent())) {
+ $file = PhabricatorPasteEditor::initializeFileForPaste(
+ $user,
+ $v_title,
+ $v_text);
$xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
- ->setNewValue($v_title);
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE)
- ->setNewValue($v_language);
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
- ->setNewValue($v_view_policy);
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
- ->setNewValue($v_edit_policy);
+ ->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)
+ ->setNewValue($file->getPHID());
+ }
- $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
- $xactions[] = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
- ->setMetadataValue('edge:type', $proj_edge_type)
- ->setNewValue(array('=' => array_fuse($v_projects)));
-
- $editor = id(new PhabricatorPasteEditor())
- ->setActor($user)
- ->setContentSourceFromRequest($request)
- ->setContinueOnNoEffect(true);
+ $xactions[] = id(new PhabricatorPasteTransaction())
+ ->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)
+ ->setNewValue($v_title);
+ $xactions[] = id(new PhabricatorPasteTransaction())
+ ->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE)
+ ->setNewValue($v_language);
+ $xactions[] = id(new PhabricatorPasteTransaction())
+ ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
+ ->setNewValue($v_view_policy);
+ $xactions[] = id(new PhabricatorPasteTransaction())
+ ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
+ ->setNewValue($v_edit_policy);
+ $xactions[] = id(new PhabricatorPasteTransaction())
+ ->setTransactionType(PhabricatorTransactions::TYPE_SPACE)
+ ->setNewValue($v_space);
+
+ $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
+ $xactions[] = id(new PhabricatorPasteTransaction())
+ ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
+ ->setMetadataValue('edge:type', $proj_edge_type)
+ ->setNewValue(array('=' => array_fuse($v_projects)));
+
+ $editor = id(new PhabricatorPasteEditor())
+ ->setActor($user)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true);
+
+ try {
$xactions = $editor->applyTransactions($paste, $xactions);
return id(new AphrontRedirectResponse())->setURI($paste->getURI());
- } else {
- // make sure we update policy so its correctly populated to what
- // the user chose
- $paste->setViewPolicy($v_view_policy);
- $paste->setEditPolicy($v_edit_policy);
+ } catch (PhabricatorApplicationTransactionValidationException $ex) {
+ $validation_exception = $ex;
}
}
@@ -172,12 +167,19 @@
->setObject($paste)
->execute();
+ $form->appendControl(
+ id(new PhabricatorSpacesControl())
+ ->setObject($paste)
+ ->setValue($v_space)
+ ->setName('spacePHID'));
+
$form->appendChild(
id(new AphrontFormPolicyControl())
->setUser($user)
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
->setPolicyObject($paste)
->setPolicies($policies)
+ ->setValue($v_view_policy)
->setName('can_view'));
$form->appendChild(
@@ -186,6 +188,7 @@
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
->setPolicyObject($paste)
->setPolicies($policies)
+ ->setValue($v_edit_policy)
->setName('can_edit'));
$form->appendControl(
@@ -199,7 +202,6 @@
->appendChild(
id(new AphrontFormTextAreaControl())
->setLabel(pht('Text'))
- ->setError($e_text)
->setValue($v_text)
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
->setCustomClass('PhabricatorMonospaced')
@@ -222,9 +224,12 @@
$form_box = id(new PHUIObjectBoxView())
->setHeaderText($title)
- ->setFormErrors($errors)
->setForm($form);
+ if ($validation_exception) {
+ $form_box->setValidationException($validation_exception);
+ }
+
$crumbs = $this->buildApplicationCrumbs($this->buildSideNavView());
if (!$is_create) {
$crumbs->addTextCrumb('P'.$paste->getID(), '/P'.$paste->getID());
diff --git a/src/applications/paste/storage/PhabricatorPaste.php b/src/applications/paste/storage/PhabricatorPaste.php
--- a/src/applications/paste/storage/PhabricatorPaste.php
+++ b/src/applications/paste/storage/PhabricatorPaste.php
@@ -42,7 +42,11 @@
}
public function getURI() {
- return '/P'.$this->getID();
+ return '/'.$this->getMonogram();
+ }
+
+ public function getMonogram() {
+ return 'P'.$this->getID();
}
protected function getConfiguration() {
diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php
--- a/src/applications/people/storage/PhabricatorUser.php
+++ b/src/applications/people/storage/PhabricatorUser.php
@@ -750,6 +750,20 @@
$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
diff --git a/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php b/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php
--- a/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php
+++ b/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php
@@ -28,7 +28,10 @@
foreach ($handles as $phid => $handle) {
$namespace = $objects[$phid];
+ $monogram = $namespace->getMonogram();
+
$handle->setName($namespace->getNamespaceName());
+ $handle->setURI('/'.$monogram);
}
}
diff --git a/src/applications/spaces/view/PhabricatorSpacesControl.php b/src/applications/spaces/view/PhabricatorSpacesControl.php
new file mode 100644
--- /dev/null
+++ b/src/applications/spaces/view/PhabricatorSpacesControl.php
@@ -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(),
+ ));
+ }
+
+}
diff --git a/src/applications/transactions/constants/PhabricatorTransactions.php b/src/applications/transactions/constants/PhabricatorTransactions.php
--- a/src/applications/transactions/constants/PhabricatorTransactions.php
+++ b/src/applications/transactions/constants/PhabricatorTransactions.php
@@ -12,6 +12,7 @@
const TYPE_BUILDABLE = 'harbormaster:buildable';
const TYPE_TOKEN = 'token:give';
const TYPE_INLINESTATE = 'core:inlinestate';
+ const TYPE_SPACE = 'core:space';
const COLOR_RED = 'red';
const COLOR_ORANGE = 'orange';
diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
--- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
+++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
@@ -264,6 +264,10 @@
$types[] = PhabricatorTransactions::TYPE_EDGE;
}
+ if ($this->object instanceof PhabricatorSpacesInterface) {
+ $types[] = PhabricatorTransactions::TYPE_SPACE;
+ }
+
return $types;
}
@@ -292,6 +296,21 @@
return $object->getEditPolicy();
case PhabricatorTransactions::TYPE_JOIN_POLICY:
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:
$edge_type = $xaction->getMetadataValue('edge:type');
if (!$edge_type) {
@@ -337,7 +356,16 @@
case PhabricatorTransactions::TYPE_BUILDABLE:
case PhabricatorTransactions::TYPE_TOKEN:
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:
return $this->getEdgeTransactionNewValue($xaction);
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
@@ -437,6 +465,7 @@
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
case PhabricatorTransactions::TYPE_INLINESTATE:
case PhabricatorTransactions::TYPE_EDGE:
+ case PhabricatorTransactions::TYPE_SPACE:
case PhabricatorTransactions::TYPE_COMMENT:
return $this->applyBuiltinInternalTransaction($object, $xaction);
}
@@ -485,6 +514,7 @@
case PhabricatorTransactions::TYPE_EDIT_POLICY:
case PhabricatorTransactions::TYPE_JOIN_POLICY:
case PhabricatorTransactions::TYPE_INLINESTATE:
+ case PhabricatorTransactions::TYPE_SPACE:
case PhabricatorTransactions::TYPE_COMMENT:
return $this->applyBuiltinExternalTransaction($object, $xaction);
}
@@ -537,6 +567,9 @@
case PhabricatorTransactions::TYPE_JOIN_POLICY:
$object->setJoinPolicy($xaction->getNewValue());
break;
+ case PhabricatorTransactions::TYPE_SPACE:
+ $object->setSpacePHID($xaction->getNewValue());
+ break;
}
}
@@ -1190,18 +1223,9 @@
PhabricatorPolicyCapability::CAN_VIEW);
break;
case PhabricatorTransactions::TYPE_VIEW_POLICY:
- PhabricatorPolicyFilter::requireCapability(
- $actor,
- $object,
- PhabricatorPolicyCapability::CAN_EDIT);
- break;
case PhabricatorTransactions::TYPE_EDIT_POLICY:
- PhabricatorPolicyFilter::requireCapability(
- $actor,
- $object,
- PhabricatorPolicyCapability::CAN_EDIT);
- break;
case PhabricatorTransactions::TYPE_JOIN_POLICY:
+ case PhabricatorTransactions::TYPE_SPACE:
PhabricatorPolicyFilter::requireCapability(
$actor,
$object,
@@ -1882,6 +1906,12 @@
$type,
PhabricatorPolicyCapability::CAN_EDIT);
break;
+ case PhabricatorTransactions::TYPE_SPACE:
+ $errors[] = $this->validateSpaceTransactions(
+ $object,
+ $xactions,
+ $type);
+ break;
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
$groups = array();
foreach ($xactions as $xaction) {
@@ -1968,6 +1998,52 @@
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 put 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(
PhabricatorLiskDAO $object,
array $xactions) {
diff --git a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php
--- a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php
+++ b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php
@@ -250,6 +250,14 @@
$phids[] = array($new);
}
break;
+ case PhabricatorTransactions::TYPE_SPACE:
+ if ($old) {
+ $phids[] = array($old);
+ }
+ if ($new) {
+ $phids[] = array($new);
+ }
+ break;
case PhabricatorTransactions::TYPE_TOKEN:
break;
case PhabricatorTransactions::TYPE_BUILDABLE:
@@ -369,6 +377,8 @@
return 'fa-wrench';
case PhabricatorTransactions::TYPE_TOKEN:
return 'fa-trophy';
+ case PhabricatorTransactions::TYPE_SPACE:
+ return 'fa-compass';
}
return 'fa-pencil';
@@ -438,6 +448,7 @@
case PhabricatorTransactions::TYPE_VIEW_POLICY:
case PhabricatorTransactions::TYPE_EDIT_POLICY:
case PhabricatorTransactions::TYPE_JOIN_POLICY:
+ case PhabricatorTransactions::TYPE_SPACE:
if ($this->getOldValue() === null) {
return true;
} else {
@@ -597,6 +608,8 @@
return pht(
'All users are already subscribed to this %s.',
$this->getApplicationObjectTypeName());
+ case PhabricatorTransactions::TYPE_SPACE:
+ return pht('This object is already in that space.');
case PhabricatorTransactions::TYPE_EDGE:
return pht('Edges already exist; transaction has no effect.');
}
@@ -636,6 +649,12 @@
$this->getApplicationObjectTypeName(),
$this->renderPolicyName($old, 'old'),
$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:
$add = array_diff($new, $old);
$rem = array_diff($old, $new);
@@ -821,6 +840,13 @@
'%s updated subscribers of %s.',
$this->renderHandleLink($author_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:
$new = ipull($new, 'dst');
$old = ipull($old, 'dst');
diff --git a/src/view/phui/PHUIHeaderView.php b/src/view/phui/PHUIHeaderView.php
--- a/src/view/phui/PHUIHeaderView.php
+++ b/src/view/phui/PHUIHeaderView.php
@@ -174,6 +174,20 @@
$header = array();
+ $header[] = $this->renderObjectSpaceInformation();
+
+ if ($this->objectName) {
+ $header[] = array(
+ phutil_tag(
+ 'a',
+ array(
+ 'href' => '/'.$this->objectName,
+ ),
+ $this->objectName),
+ ' ',
+ );
+ }
+
if ($this->actionLinks) {
$actions = array();
foreach ($this->actionLinks as $button) {
@@ -200,18 +214,6 @@
}
$header[] = $this->header;
- if ($this->objectName) {
- array_unshift(
- $header,
- phutil_tag(
- 'a',
- array(
- 'href' => '/'.$this->objectName,
- ),
- $this->objectName),
- ' ');
- }
-
if ($this->tags) {
$header[] = ' ';
$header[] = phutil_tag(
@@ -268,9 +270,9 @@
}
private function renderPolicyProperty(PhabricatorPolicyInterface $object) {
- $policies = PhabricatorPolicyQuery::loadPolicies(
- $this->getUser(),
- $object);
+ $viewer = $this->getUser();
+
+ $policies = PhabricatorPolicyQuery::loadPolicies($viewer, $object);
$view_capability = PhabricatorPolicyCapability::CAN_VIEW;
$policy = idx($policies, $view_capability);
@@ -294,4 +296,36 @@
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 array(
+ $viewer->renderHandle($space_phid),
+ ' | ',
+ );
+ }
+
+
}

File Metadata

Mime Type
text/plain
Expires
Sun, Nov 3, 4:03 AM (2 w, 1 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6757472
Default Alt Text
D13159.id31806.diff (22 KB)

Event Timeline