@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add "Spaces", an application for managing policy namespaces

Summary: Ref T3820. This doesn't actually do anything yet, but dumps in all the plumbing.

Test Plan:
{F156989}

{F156990}

{F156991}

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: eadler, wienczny, jdloft, devurandom, thz, hwinkel, 20after4, sascha-egerer, seporaitis, joshuaspence, chad, epriestley

Maniphest Tasks: T3820

Differential Revision: https://secure.phabricator.com/D9204

+1045
+12
resources/sql/autopatches/20150601.spaces.1.namespace.sql
··· 1 + CREATE TABLE {$NAMESPACE}_spaces.spaces_namespace ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + phid VARBINARY(64) NOT NULL, 4 + namespaceName VARCHAR(255) NOT NULL COLLATE {$COLLATE_TEXT}, 5 + viewPolicy VARBINARY(64) NOT NULL, 6 + editPolicy VARBINARY(64) NOT NULL, 7 + isDefaultNamespace BOOL, 8 + dateCreated INT UNSIGNED NOT NULL, 9 + dateModified INT UNSIGNED NOT NULL, 10 + UNIQUE KEY `key_phid` (phid), 11 + UNIQUE KEY `key_default` (isDefaultNamespace) 12 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+19
resources/sql/autopatches/20150601.spaces.2.xaction.sql
··· 1 + CREATE TABLE {$NAMESPACE}_spaces.spaces_namespacetransaction ( 2 + id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, 3 + phid VARBINARY(64) NOT NULL, 4 + authorPHID VARBINARY(64) NOT NULL, 5 + objectPHID VARBINARY(64) NOT NULL, 6 + viewPolicy VARBINARY(64) NOT NULL, 7 + editPolicy VARBINARY(64) NOT NULL, 8 + commentPHID VARBINARY(64), 9 + commentVersion INT UNSIGNED NOT NULL, 10 + transactionType VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}, 11 + oldValue LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, 12 + newValue LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, 13 + contentSource LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, 14 + metadata LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, 15 + dateCreated INT UNSIGNED NOT NULL, 16 + dateModified INT UNSIGNED NOT NULL, 17 + UNIQUE KEY `key_phid` (phid), 18 + KEY `key_object` (objectPHID) 19 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+38
src/__phutil_library_map__.php
··· 1318 1318 'PhabricatorApplicationSearchController' => 'applications/search/controller/PhabricatorApplicationSearchController.php', 1319 1319 'PhabricatorApplicationSearchEngine' => 'applications/search/engine/PhabricatorApplicationSearchEngine.php', 1320 1320 'PhabricatorApplicationSearchResultsControllerInterface' => 'applications/search/interface/PhabricatorApplicationSearchResultsControllerInterface.php', 1321 + 'PhabricatorApplicationSpaces' => 'applications/spaces/application/PhabricatorApplicationSpaces.php', 1321 1322 'PhabricatorApplicationStatusView' => 'applications/meta/view/PhabricatorApplicationStatusView.php', 1322 1323 'PhabricatorApplicationTransaction' => 'applications/transactions/storage/PhabricatorApplicationTransaction.php', 1323 1324 'PhabricatorApplicationTransactionComment' => 'applications/transactions/storage/PhabricatorApplicationTransactionComment.php', ··· 2561 2562 'PhabricatorSlugTestCase' => 'infrastructure/util/__tests__/PhabricatorSlugTestCase.php', 2562 2563 'PhabricatorSortTableUIExample' => 'applications/uiexample/examples/PhabricatorSortTableUIExample.php', 2563 2564 'PhabricatorSourceCodeView' => 'view/layout/PhabricatorSourceCodeView.php', 2565 + 'PhabricatorSpacesCapabilityCreateSpaces' => 'applications/spaces/capability/PhabricatorSpacesCapabilityCreateSpaces.php', 2566 + 'PhabricatorSpacesCapabilityDefaultEdit' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultEdit.php', 2567 + 'PhabricatorSpacesCapabilityDefaultView' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultView.php', 2568 + 'PhabricatorSpacesController' => 'applications/spaces/controller/PhabricatorSpacesController.php', 2569 + 'PhabricatorSpacesDAO' => 'applications/spaces/storage/PhabricatorSpacesDAO.php', 2570 + 'PhabricatorSpacesEditController' => 'applications/spaces/controller/PhabricatorSpacesEditController.php', 2571 + 'PhabricatorSpacesInterface' => 'applications/spaces/interface/PhabricatorSpacesInterface.php', 2572 + 'PhabricatorSpacesListController' => 'applications/spaces/controller/PhabricatorSpacesListController.php', 2573 + 'PhabricatorSpacesNamespace' => 'applications/spaces/storage/PhabricatorSpacesNamespace.php', 2574 + 'PhabricatorSpacesNamespaceEditor' => 'applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php', 2575 + 'PhabricatorSpacesNamespacePHIDType' => 'applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php', 2576 + 'PhabricatorSpacesNamespaceQuery' => 'applications/spaces/query/PhabricatorSpacesNamespaceQuery.php', 2577 + 'PhabricatorSpacesNamespaceSearchEngine' => 'applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php', 2578 + 'PhabricatorSpacesNamespaceTransaction' => 'applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php', 2579 + 'PhabricatorSpacesNamespaceTransactionQuery' => 'applications/spaces/query/PhabricatorSpacesNamespaceTransactionQuery.php', 2580 + 'PhabricatorSpacesViewController' => 'applications/spaces/controller/PhabricatorSpacesViewController.php', 2564 2581 'PhabricatorStandardCustomField' => 'infrastructure/customfield/standard/PhabricatorStandardCustomField.php', 2565 2582 'PhabricatorStandardCustomFieldBool' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldBool.php', 2566 2583 'PhabricatorStandardCustomFieldCredential' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php', ··· 4647 4664 'PhabricatorApplicationPanelController' => 'PhabricatorApplicationsController', 4648 4665 'PhabricatorApplicationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 4649 4666 'PhabricatorApplicationSearchController' => 'PhabricatorSearchBaseController', 4667 + 'PhabricatorApplicationSpaces' => 'PhabricatorApplication', 4650 4668 'PhabricatorApplicationStatusView' => 'AphrontView', 4651 4669 'PhabricatorApplicationTransaction' => array( 4652 4670 'PhabricatorLiskDAO', ··· 6027 6045 'PhabricatorSlugTestCase' => 'PhabricatorTestCase', 6028 6046 'PhabricatorSortTableUIExample' => 'PhabricatorUIExample', 6029 6047 'PhabricatorSourceCodeView' => 'AphrontView', 6048 + 'PhabricatorSpacesCapabilityCreateSpaces' => 'PhabricatorPolicyCapability', 6049 + 'PhabricatorSpacesCapabilityDefaultEdit' => 'PhabricatorPolicyCapability', 6050 + 'PhabricatorSpacesCapabilityDefaultView' => 'PhabricatorPolicyCapability', 6051 + 'PhabricatorSpacesController' => 'PhabricatorController', 6052 + 'PhabricatorSpacesDAO' => 'PhabricatorLiskDAO', 6053 + 'PhabricatorSpacesEditController' => 'PhabricatorSpacesController', 6054 + 'PhabricatorSpacesInterface' => 'PhabricatorPHIDInterface', 6055 + 'PhabricatorSpacesListController' => 'PhabricatorSpacesController', 6056 + 'PhabricatorSpacesNamespace' => array( 6057 + 'PhabricatorSpacesDAO', 6058 + 'PhabricatorPolicyInterface', 6059 + 'PhabricatorApplicationTransactionInterface', 6060 + ), 6061 + 'PhabricatorSpacesNamespaceEditor' => 'PhabricatorApplicationTransactionEditor', 6062 + 'PhabricatorSpacesNamespacePHIDType' => 'PhabricatorPHIDType', 6063 + 'PhabricatorSpacesNamespaceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 6064 + 'PhabricatorSpacesNamespaceSearchEngine' => 'PhabricatorApplicationSearchEngine', 6065 + 'PhabricatorSpacesNamespaceTransaction' => 'PhabricatorApplicationTransaction', 6066 + 'PhabricatorSpacesNamespaceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 6067 + 'PhabricatorSpacesViewController' => 'PhabricatorSpacesController', 6030 6068 'PhabricatorStandardCustomField' => 'PhabricatorCustomField', 6031 6069 'PhabricatorStandardCustomFieldBool' => 'PhabricatorStandardCustomField', 6032 6070 'PhabricatorStandardCustomFieldCredential' => 'PhabricatorStandardCustomField',
+67
src/applications/spaces/application/PhabricatorApplicationSpaces.php
··· 1 + <?php 2 + 3 + final class PhabricatorApplicationSpaces extends PhabricatorApplication { 4 + 5 + public function getBaseURI() { 6 + return '/spaces/'; 7 + } 8 + 9 + public function getName() { 10 + return pht('Spaces'); 11 + } 12 + 13 + public function getShortDescription() { 14 + return pht('Policy Namespaces'); 15 + } 16 + 17 + public function getFontIcon() { 18 + return 'fa-compass'; 19 + } 20 + 21 + public function getTitleGlyph() { 22 + return "\xE2\x97\x8B"; 23 + } 24 + 25 + public function getFlavorText() { 26 + return pht('Control access to groups of objects.'); 27 + } 28 + 29 + public function getApplicationGroup() { 30 + return self::GROUP_UTILITIES; 31 + } 32 + 33 + public function canUninstall() { 34 + return true; 35 + } 36 + 37 + public function isPrototype() { 38 + return true; 39 + } 40 + 41 + public function getRoutes() { 42 + return array( 43 + '/S(?P<id>[1-9]\d*)' => 'PhabricatorSpacesViewController', 44 + '/spaces/' => array( 45 + '(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorSpacesListController', 46 + 'create/' => 'PhabricatorSpacesEditController', 47 + 'edit/(?:(?P<id>\d+)/)?' => 'PhabricatorSpacesEditController', 48 + ), 49 + ); 50 + } 51 + 52 + protected function getCustomCapabilities() { 53 + return array( 54 + PhabricatorSpacesCapabilityCreateSpaces::CAPABILITY => array( 55 + 'default' => PhabricatorPolicies::POLICY_ADMIN, 56 + ), 57 + PhabricatorSpacesCapabilityDefaultView::CAPABILITY => array( 58 + 'caption' => pht('Default view policy for newly created spaces.'), 59 + ), 60 + PhabricatorSpacesCapabilityDefaultEdit::CAPABILITY => array( 61 + 'caption' => pht('Default edit policy for newly created spaces.'), 62 + 'default' => PhabricatorPolicies::POLICY_ADMIN, 63 + ), 64 + ); 65 + } 66 + 67 + }
+16
src/applications/spaces/capability/PhabricatorSpacesCapabilityCreateSpaces.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesCapabilityCreateSpaces 4 + extends PhabricatorPolicyCapability { 5 + 6 + const CAPABILITY = 'spaces.create'; 7 + 8 + public function getCapabilityName() { 9 + return pht('Can Create Spaces'); 10 + } 11 + 12 + public function describeCapabilityRejection() { 13 + return pht('You do not have permission to create spaces.'); 14 + } 15 + 16 + }
+12
src/applications/spaces/capability/PhabricatorSpacesCapabilityDefaultEdit.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesCapabilityDefaultEdit 4 + extends PhabricatorPolicyCapability { 5 + 6 + const CAPABILITY = 'spaces.default.edit'; 7 + 8 + public function getCapabilityName() { 9 + return pht('Default Edit Policy'); 10 + } 11 + 12 + }
+16
src/applications/spaces/capability/PhabricatorSpacesCapabilityDefaultView.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesCapabilityDefaultView 4 + extends PhabricatorPolicyCapability { 5 + 6 + const CAPABILITY = 'spaces.default.view'; 7 + 8 + public function getCapabilityName() { 9 + return pht('Default View Policy'); 10 + } 11 + 12 + public function shouldAllowPublicPolicySetting() { 13 + return true; 14 + } 15 + 16 + }
+3
src/applications/spaces/controller/PhabricatorSpacesController.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorSpacesController extends PhabricatorController {}
+174
src/applications/spaces/controller/PhabricatorSpacesEditController.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesEditController 4 + extends PhabricatorSpacesController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $request->getUser(); 8 + 9 + $make_default = false; 10 + 11 + $id = $request->getURIData('id'); 12 + if ($id) { 13 + $space = id(new PhabricatorSpacesNamespaceQuery()) 14 + ->setViewer($viewer) 15 + ->withIDs(array($id)) 16 + ->requireCapabilities( 17 + array( 18 + PhabricatorPolicyCapability::CAN_VIEW, 19 + PhabricatorPolicyCapability::CAN_EDIT, 20 + )) 21 + ->executeOne(); 22 + if (!$space) { 23 + return new Aphront404Response(); 24 + } 25 + 26 + $is_new = false; 27 + $cancel_uri = '/'.$space->getMonogram(); 28 + 29 + $header_text = pht('Edit %s', $space->getNamespaceName()); 30 + $title = pht('Edit Space'); 31 + $button_text = pht('Save Changes'); 32 + } else { 33 + $this->requireApplicationCapability( 34 + PhabricatorSpacesCapabilityCreateSpaces::CAPABILITY); 35 + 36 + $space = PhabricatorSpacesNamespace::initializeNewNamespace($viewer); 37 + 38 + $is_new = true; 39 + $cancel_uri = $this->getApplicationURI(); 40 + 41 + $header_text = pht('Create Space'); 42 + $title = pht('Create Space'); 43 + $button_text = pht('Create Space'); 44 + 45 + $default = id(new PhabricatorSpacesNamespaceQuery()) 46 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 47 + ->withIsDefaultNamespace(true) 48 + ->execute(); 49 + if (!$default) { 50 + $make_default = true; 51 + } 52 + } 53 + 54 + $validation_exception = null; 55 + $e_name = true; 56 + $v_name = $space->getNamespaceName(); 57 + $v_view = $space->getViewPolicy(); 58 + $v_edit = $space->getEditPolicy(); 59 + 60 + if ($request->isFormPost()) { 61 + $xactions = array(); 62 + $e_name = null; 63 + 64 + $v_name = $request->getStr('name'); 65 + $v_view = $request->getStr('viewPolicy'); 66 + $v_edit = $request->getStr('editPolicy'); 67 + 68 + $type_name = PhabricatorSpacesNamespaceTransaction::TYPE_NAME; 69 + $type_default = PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT; 70 + $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; 71 + $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; 72 + 73 + $xactions[] = id(new PhabricatorSpacesNamespaceTransaction()) 74 + ->setTransactionType($type_name) 75 + ->setNewValue($v_name); 76 + 77 + $xactions[] = id(new PhabricatorSpacesNamespaceTransaction()) 78 + ->setTransactionType($type_view) 79 + ->setNewValue($v_view); 80 + 81 + $xactions[] = id(new PhabricatorSpacesNamespaceTransaction()) 82 + ->setTransactionType($type_edit) 83 + ->setNewValue($v_edit); 84 + 85 + if ($make_default) { 86 + $xactions[] = id(new PhabricatorSpacesNamespaceTransaction()) 87 + ->setTransactionType($type_default) 88 + ->setNewValue(1); 89 + } 90 + 91 + $editor = id(new PhabricatorSpacesNamespaceEditor()) 92 + ->setActor($viewer) 93 + ->setContinueOnNoEffect(true) 94 + ->setContentSourceFromRequest($request); 95 + 96 + try { 97 + $editor->applyTransactions($space, $xactions); 98 + 99 + return id(new AphrontRedirectResponse()) 100 + ->setURI('/'.$space->getMonogram()); 101 + } catch (PhabricatorApplicationTransactionValidationException $ex) { 102 + $validation_exception = $ex; 103 + 104 + $e_name = $ex->getShortMessage($type_name); 105 + } 106 + } 107 + 108 + $policies = id(new PhabricatorPolicyQuery()) 109 + ->setViewer($viewer) 110 + ->setObject($space) 111 + ->execute(); 112 + 113 + $form = id(new AphrontFormView()) 114 + ->setUser($viewer); 115 + 116 + if ($make_default) { 117 + $form->appendRemarkupInstructions( 118 + pht( 119 + 'NOTE: You are creating the **default space**. All existing '. 120 + 'objects will be put into this space. You must create a default '. 121 + 'space before you can create other spaces.')); 122 + } 123 + 124 + $form 125 + ->appendChild( 126 + id(new AphrontFormTextControl()) 127 + ->setLabel(pht('Name')) 128 + ->setName('name') 129 + ->setValue($v_name) 130 + ->setError($e_name)) 131 + ->appendChild( 132 + id(new AphrontFormPolicyControl()) 133 + ->setUser($viewer) 134 + ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) 135 + ->setPolicyObject($space) 136 + ->setPolicies($policies) 137 + ->setValue($v_view) 138 + ->setName('viewPolicy')) 139 + ->appendChild( 140 + id(new AphrontFormPolicyControl()) 141 + ->setUser($viewer) 142 + ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) 143 + ->setPolicyObject($space) 144 + ->setPolicies($policies) 145 + ->setValue($v_edit) 146 + ->setName('editPolicy')) 147 + ->appendChild( 148 + id(new AphrontFormSubmitControl()) 149 + ->setValue($button_text) 150 + ->addCancelButton($cancel_uri)); 151 + 152 + $box = id(new PHUIObjectBoxView()) 153 + ->setHeaderText($header_text) 154 + ->setValidationException($validation_exception) 155 + ->appendChild($form); 156 + 157 + $crumbs = $this->buildApplicationCrumbs(); 158 + if (!$is_new) { 159 + $crumbs->addTextCrumb( 160 + $space->getMonogram(), 161 + $cancel_uri); 162 + } 163 + $crumbs->addTextCrumb($title); 164 + 165 + return $this->buildApplicationPage( 166 + array( 167 + $crumbs, 168 + $box, 169 + ), 170 + array( 171 + 'title' => $title, 172 + )); 173 + } 174 + }
+52
src/applications/spaces/controller/PhabricatorSpacesListController.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesListController 4 + extends PhabricatorSpacesController { 5 + 6 + public function shouldAllowPublic() { 7 + return true; 8 + } 9 + 10 + public function handleRequest(AphrontRequest $request) { 11 + $request = $this->getRequest(); 12 + $controller = id(new PhabricatorApplicationSearchController($request)) 13 + ->setQueryKey($request->getURIData('queryKey')) 14 + ->setSearchEngine(new PhabricatorSpacesNamespaceSearchEngine()) 15 + ->setNavigation($this->buildSideNavView()); 16 + 17 + return $this->delegateToController($controller); 18 + } 19 + 20 + public function buildSideNavView($for_app = false) { 21 + $user = $this->getRequest()->getUser(); 22 + 23 + $nav = new AphrontSideNavFilterView(); 24 + $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); 25 + 26 + id(new PhabricatorSpacesNamespaceSearchEngine()) 27 + ->setViewer($user) 28 + ->addNavigationItems($nav->getMenu()); 29 + 30 + $nav->selectFilter(null); 31 + 32 + return $nav; 33 + } 34 + 35 + public function buildApplicationCrumbs() { 36 + $crumbs = parent::buildApplicationCrumbs(); 37 + 38 + $can_create = $this->hasApplicationCapability( 39 + PhabricatorSpacesCapabilityCreateSpaces::CAPABILITY); 40 + 41 + $crumbs->addAction( 42 + id(new PHUIListItemView()) 43 + ->setName(pht('Create Space')) 44 + ->setHref($this->getApplicationURI('create/')) 45 + ->setIcon('fa-plus-square') 46 + ->setDisabled(!$can_create) 47 + ->setWorkflow(!$can_create)); 48 + 49 + return $crumbs; 50 + } 51 + 52 + }
+104
src/applications/spaces/controller/PhabricatorSpacesViewController.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesViewController 4 + extends PhabricatorSpacesController { 5 + 6 + public function shouldAllowPublic() { 7 + return true; 8 + } 9 + 10 + public function handleRequest(AphrontRequest $request) { 11 + $viewer = $this->getViewer(); 12 + 13 + $space = id(new PhabricatorSpacesNamespaceQuery()) 14 + ->setViewer($viewer) 15 + ->withIDs(array($request->getURIData('id'))) 16 + ->executeOne(); 17 + if (!$space) { 18 + return new Aphront404Response(); 19 + } 20 + 21 + $action_list = $this->buildActionListView($space); 22 + $property_list = $this->buildPropertyListView($space); 23 + $property_list->setActionList($action_list); 24 + 25 + $xactions = id(new PhabricatorSpacesNamespaceTransactionQuery()) 26 + ->setViewer($viewer) 27 + ->withObjectPHIDs(array($space->getPHID())) 28 + ->execute(); 29 + 30 + $timeline = $this->buildTransactionTimeline( 31 + $space, 32 + new PhabricatorSpacesNamespaceTransactionQuery()); 33 + $timeline->setShouldTerminate(true); 34 + 35 + $header = id(new PHUIHeaderView()) 36 + ->setUser($viewer) 37 + ->setHeader($space->getNamespaceName()) 38 + ->setPolicyObject($space); 39 + 40 + $box = id(new PHUIObjectBoxView()) 41 + ->setHeader($header) 42 + ->addPropertyList($property_list); 43 + 44 + $crumbs = $this->buildApplicationCrumbs(); 45 + $crumbs->addTextCrumb($space->getMonogram()); 46 + 47 + return $this->buildApplicationPage( 48 + array( 49 + $crumbs, 50 + $box, 51 + $timeline, 52 + ), 53 + array( 54 + 'title' => array($space->getMonogram(), $space->getNamespaceName()), 55 + )); 56 + } 57 + 58 + private function buildPropertyListView(PhabricatorSpacesNamespace $space) { 59 + $viewer = $this->getRequest()->getUser(); 60 + 61 + $list = id(new PHUIPropertyListView()) 62 + ->setUser($viewer); 63 + 64 + $list->addProperty( 65 + pht('Default Space'), 66 + $space->getIsDefaultNamespace() 67 + ? pht('Yes') 68 + : pht('No')); 69 + 70 + $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( 71 + $viewer, 72 + $space); 73 + 74 + $list->addProperty( 75 + pht('Editable By'), 76 + $descriptions[PhabricatorPolicyCapability::CAN_EDIT]); 77 + 78 + return $list; 79 + } 80 + 81 + private function buildActionListView(PhabricatorSpacesNamespace $space) { 82 + $viewer = $this->getRequest()->getUser(); 83 + 84 + $list = id(new PhabricatorActionListView()) 85 + ->setUser($viewer) 86 + ->setObjectURI('/'.$space->getMonogram()); 87 + 88 + $can_edit = PhabricatorPolicyFilter::hasCapability( 89 + $viewer, 90 + $space, 91 + PhabricatorPolicyCapability::CAN_EDIT); 92 + 93 + $list->addAction( 94 + id(new PhabricatorActionView()) 95 + ->setName(pht('Edit Space')) 96 + ->setIcon('fa-pencil') 97 + ->setHref($this->getApplicationURI('edit/'.$space->getID().'/')) 98 + ->setWorkflow(!$can_edit) 99 + ->setDisabled(!$can_edit)); 100 + 101 + return $list; 102 + } 103 + 104 + }
+132
src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesNamespaceEditor 4 + extends PhabricatorApplicationTransactionEditor { 5 + 6 + public function getEditorApplicationClass() { 7 + return pht('PhabricatorSpacesApplication'); 8 + } 9 + 10 + public function getEditorObjectsDescription() { 11 + return pht('Spaces'); 12 + } 13 + 14 + public function getTransactionTypes() { 15 + $types = parent::getTransactionTypes(); 16 + 17 + $types[] = PhabricatorSpacesNamespaceTransaction::TYPE_NAME; 18 + $types[] = PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT; 19 + 20 + $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; 21 + $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; 22 + 23 + return $types; 24 + } 25 + 26 + protected function getCustomTransactionOldValue( 27 + PhabricatorLiskDAO $object, 28 + PhabricatorApplicationTransaction $xaction) { 29 + 30 + switch ($xaction->getTransactionType()) { 31 + case PhabricatorSpacesNamespaceTransaction::TYPE_NAME: 32 + $name = $object->getNamespaceName(); 33 + if (!strlen($name)) { 34 + return null; 35 + } 36 + return $name; 37 + case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: 38 + return $object->getIsDefaultNamespace() ? 1 : null; 39 + case PhabricatorTransactions::TYPE_VIEW_POLICY: 40 + return $object->getViewPolicy(); 41 + case PhabricatorTransactions::TYPE_EDIT_POLICY: 42 + return $object->getEditPolicy(); 43 + } 44 + 45 + return parent::getCustomTransactionOldValue($object, $xaction); 46 + } 47 + 48 + protected function getCustomTransactionNewValue( 49 + PhabricatorLiskDAO $object, 50 + PhabricatorApplicationTransaction $xaction) { 51 + 52 + switch ($xaction->getTransactionType()) { 53 + case PhabricatorSpacesNamespaceTransaction::TYPE_NAME: 54 + case PhabricatorTransactions::TYPE_VIEW_POLICY: 55 + case PhabricatorTransactions::TYPE_EDIT_POLICY: 56 + return $xaction->getNewValue(); 57 + case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: 58 + return $xaction->getNewValue() ? 1 : null; 59 + } 60 + 61 + return parent::getCustomTransactionNewValue($object, $xaction); 62 + } 63 + 64 + protected function applyCustomInternalTransaction( 65 + PhabricatorLiskDAO $object, 66 + PhabricatorApplicationTransaction $xaction) { 67 + 68 + $new = $xaction->getNewValue(); 69 + 70 + switch ($xaction->getTransactionType()) { 71 + case PhabricatorSpacesNamespaceTransaction::TYPE_NAME: 72 + $object->setNamespaceName($new); 73 + return; 74 + case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: 75 + $object->setIsDefaultNamespace($new ? 1 : null); 76 + return; 77 + case PhabricatorTransactions::TYPE_VIEW_POLICY: 78 + $object->setViewPolicy($new); 79 + return; 80 + case PhabricatorTransactions::TYPE_EDIT_POLICY: 81 + $object->setEditPolicy($new); 82 + return; 83 + } 84 + 85 + return parent::applyCustomInternalTransaction($object, $xaction); 86 + } 87 + 88 + protected function applyCustomExternalTransaction( 89 + PhabricatorLiskDAO $object, 90 + PhabricatorApplicationTransaction $xaction) { 91 + 92 + switch ($xaction->getTransactionType()) { 93 + case PhabricatorSpacesNamespaceTransaction::TYPE_NAME: 94 + case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: 95 + case PhabricatorTransactions::TYPE_VIEW_POLICY: 96 + case PhabricatorTransactions::TYPE_EDIT_POLICY: 97 + return; 98 + } 99 + 100 + return parent::applyCustomExternalTransaction($object, $xaction); 101 + } 102 + 103 + protected function validateTransaction( 104 + PhabricatorLiskDAO $object, 105 + $type, 106 + array $xactions) { 107 + 108 + $errors = parent::validateTransaction($object, $type, $xactions); 109 + 110 + switch ($type) { 111 + case PhabricatorSpacesNamespaceTransaction::TYPE_NAME: 112 + $missing = $this->validateIsEmptyTextField( 113 + $object->getNamespaceName(), 114 + $xactions); 115 + 116 + if ($missing) { 117 + $error = new PhabricatorApplicationTransactionValidationError( 118 + $type, 119 + pht('Required'), 120 + pht('Spaces must have a name.'), 121 + nonempty(last($xactions), null)); 122 + 123 + $error->setIsMissingFieldError(true); 124 + $errors[] = $error; 125 + } 126 + break; 127 + } 128 + 129 + return $errors; 130 + } 131 + 132 + }
+3
src/applications/spaces/interface/PhabricatorSpacesInterface.php
··· 1 + <?php 2 + 3 + interface PhabricatorSpacesInterface extends PhabricatorPHIDInterface {}
+64
src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesNamespacePHIDType 4 + extends PhabricatorPHIDType { 5 + 6 + const TYPECONST = 'SPCE'; 7 + 8 + public function getTypeName() { 9 + return pht('Space'); 10 + } 11 + 12 + public function newObject() { 13 + return new PhabricatorSpacesNamespace(); 14 + } 15 + 16 + protected function buildQueryForObjects( 17 + PhabricatorObjectQuery $query, 18 + array $phids) { 19 + 20 + return id(new PhabricatorSpacesNamespaceQuery()) 21 + ->withPHIDs($phids); 22 + } 23 + 24 + public function loadHandles( 25 + PhabricatorHandleQuery $query, 26 + array $handles, 27 + array $objects) { 28 + 29 + foreach ($handles as $phid => $handle) { 30 + $namespace = $objects[$phid]; 31 + $handle->setName($namespace->getNamespaceName()); 32 + } 33 + } 34 + 35 + public function canLoadNamedObject($name) { 36 + return preg_match('/^S[1-9]\d*$/i', $name); 37 + } 38 + 39 + public function loadNamedObjects( 40 + PhabricatorObjectQuery $query, 41 + array $names) { 42 + 43 + $id_map = array(); 44 + foreach ($names as $name) { 45 + $id = (int)substr($name, 1); 46 + $id_map[$id][] = $name; 47 + } 48 + 49 + $objects = id(new PhabricatorSpacesNamespaceQuery()) 50 + ->setViewer($query->getViewer()) 51 + ->withIDs(array_keys($id_map)) 52 + ->execute(); 53 + 54 + $results = array(); 55 + foreach ($objects as $id => $object) { 56 + foreach (idx($id_map, $id, array()) as $name) { 57 + $results[$name] = $object; 58 + } 59 + } 60 + 61 + return $results; 62 + } 63 + 64 + }
+77
src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesNamespaceQuery 4 + extends PhabricatorCursorPagedPolicyAwareQuery { 5 + 6 + private $ids; 7 + private $phids; 8 + private $isDefaultNamespace; 9 + 10 + public function withIDs(array $ids) { 11 + $this->ids = $ids; 12 + return $this; 13 + } 14 + 15 + public function withPHIDs(array $phids) { 16 + $this->phids = $phids; 17 + return $this; 18 + } 19 + 20 + public function withIsDefaultNamespace($default) { 21 + $this->isDefaultNamespace = $default; 22 + return $this; 23 + } 24 + 25 + public function getQueryApplicationClass() { 26 + return 'PhabricatorApplicationSpaces'; 27 + } 28 + 29 + protected function loadPage() { 30 + $table = new PhabricatorSpacesNamespace(); 31 + $conn_r = $table->establishConnection('r'); 32 + 33 + $rows = queryfx_all( 34 + $conn_r, 35 + 'SELECT * FROM %T %Q %Q %Q', 36 + $table->getTableName(), 37 + $this->buildWhereClause($conn_r), 38 + $this->buildOrderClause($conn_r), 39 + $this->buildLimitClause($conn_r)); 40 + 41 + return $table->loadAllFromArray($rows); 42 + } 43 + 44 + protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { 45 + $where = array(); 46 + 47 + if ($this->ids !== null) { 48 + $where[] = qsprintf( 49 + $conn_r, 50 + 'id IN (%Ld)', 51 + $this->ids); 52 + } 53 + 54 + if ($this->phids !== null) { 55 + $where[] = qsprintf( 56 + $conn_r, 57 + 'phid IN (%Ls)', 58 + $this->phids); 59 + } 60 + 61 + if ($this->isDefaultNamespace !== null) { 62 + if ($this->isDefaultNamespace) { 63 + $where[] = qsprintf( 64 + $conn_r, 65 + 'isDefaultNamespace = 1'); 66 + } else { 67 + $where[] = qsprintf( 68 + $conn_r, 69 + 'isDefaultNamespace IS NULL'); 70 + } 71 + } 72 + 73 + $where[] = $this->buildPagingClause($conn_r); 74 + return $this->formatWhereClause($where); 75 + } 76 + 77 + }
+81
src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesNamespaceSearchEngine 4 + extends PhabricatorApplicationSearchEngine { 5 + 6 + public function getApplicationClassName() { 7 + return 'PhabricatorSpacesApplication'; 8 + } 9 + 10 + public function getResultTypeDescription() { 11 + return pht('Spaces'); 12 + } 13 + 14 + public function buildSavedQueryFromRequest(AphrontRequest $request) { 15 + $saved = new PhabricatorSavedQuery(); 16 + 17 + return $saved; 18 + } 19 + 20 + public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { 21 + $query = id(new PhabricatorSpacesNamespaceQuery()); 22 + 23 + return $query; 24 + } 25 + 26 + public function buildSearchForm( 27 + AphrontFormView $form, 28 + PhabricatorSavedQuery $saved_query) {} 29 + 30 + protected function getURI($path) { 31 + return '/spaces/'.$path; 32 + } 33 + 34 + public function getBuiltinQueryNames() { 35 + $names = array( 36 + 'all' => pht('All Spaces'), 37 + ); 38 + 39 + return $names; 40 + } 41 + 42 + public function buildSavedQueryFromBuiltin($query_key) { 43 + 44 + $query = $this->newSavedQuery(); 45 + $query->setQueryKey($query_key); 46 + 47 + switch ($query_key) { 48 + case 'all': 49 + return $query; 50 + } 51 + 52 + return parent::buildSavedQueryFromBuiltin($query_key); 53 + } 54 + 55 + protected function renderResultList( 56 + array $spaces, 57 + PhabricatorSavedQuery $query, 58 + array $handles) { 59 + assert_instances_of($spaces, 'PhabricatorSpacesNamespace'); 60 + 61 + $viewer = $this->requireViewer(); 62 + 63 + $list = new PHUIObjectItemListView(); 64 + $list->setUser($viewer); 65 + foreach ($spaces as $space) { 66 + $item = id(new PHUIObjectItemView()) 67 + ->setObjectName($space->getMonogram()) 68 + ->setHeader($space->getNamespaceName()) 69 + ->setHref('/'.$space->getMonogram()); 70 + 71 + if ($space->getIsDefaultNamespace()) { 72 + $item->addIcon('fa-certificate', pht('Default Space')); 73 + } 74 + 75 + $list->addItem($item); 76 + } 77 + 78 + return $list; 79 + } 80 + 81 + }
+10
src/applications/spaces/query/PhabricatorSpacesNamespaceTransactionQuery.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesNamespaceTransactionQuery 4 + extends PhabricatorApplicationTransactionQuery { 5 + 6 + public function getTemplateApplicationTransaction() { 7 + return new PhabricatorSpacesNamespaceTransaction(); 8 + } 9 + 10 + }
+9
src/applications/spaces/storage/PhabricatorSpacesDAO.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorSpacesDAO extends PhabricatorLiskDAO { 4 + 5 + public function getApplicationName() { 6 + return 'spaces'; 7 + } 8 + 9 + }
+106
src/applications/spaces/storage/PhabricatorSpacesNamespace.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesNamespace 4 + extends PhabricatorSpacesDAO 5 + implements 6 + PhabricatorPolicyInterface, 7 + PhabricatorApplicationTransactionInterface { 8 + 9 + protected $namespaceName; 10 + protected $viewPolicy; 11 + protected $editPolicy; 12 + protected $isDefaultNamespace; 13 + 14 + public static function initializeNewNamespace(PhabricatorUser $actor) { 15 + $app = id(new PhabricatorApplicationQuery()) 16 + ->setViewer($actor) 17 + ->withClasses(array('PhabricatorApplicationSpaces')) 18 + ->executeOne(); 19 + 20 + $view_policy = $app->getPolicy( 21 + PhabricatorSpacesCapabilityDefaultView::CAPABILITY); 22 + $edit_policy = $app->getPolicy( 23 + PhabricatorSpacesCapabilityDefaultEdit::CAPABILITY); 24 + 25 + return id(new PhabricatorSpacesNamespace()) 26 + ->setIsDefaultNamespace(null) 27 + ->setViewPolicy($view_policy) 28 + ->setEditPolicy($edit_policy); 29 + } 30 + 31 + public function getConfiguration() { 32 + return array( 33 + self::CONFIG_AUX_PHID => true, 34 + self::CONFIG_COLUMN_SCHEMA => array( 35 + 'namespaceName' => 'text255', 36 + 'isDefaultNamespace' => 'bool?', 37 + ), 38 + self::CONFIG_KEY_SCHEMA => array( 39 + 'key_default' => array( 40 + 'columns' => array('isDefaultNamespace'), 41 + 'unique' => true, 42 + ), 43 + ), 44 + ) + parent::getConfiguration(); 45 + } 46 + 47 + public function generatePHID() { 48 + return PhabricatorPHID::generateNewPHID( 49 + PhabricatorSpacesNamespacePHIDType::TYPECONST); 50 + } 51 + 52 + public function getMonogram() { 53 + return 'S'.$this->getID(); 54 + } 55 + 56 + 57 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 58 + 59 + 60 + public function getCapabilities() { 61 + return array( 62 + PhabricatorPolicyCapability::CAN_VIEW, 63 + PhabricatorPolicyCapability::CAN_EDIT, 64 + ); 65 + } 66 + 67 + public function getPolicy($capability) { 68 + switch ($capability) { 69 + case PhabricatorPolicyCapability::CAN_VIEW: 70 + return $this->getViewPolicy(); 71 + case PhabricatorPolicyCapability::CAN_EDIT: 72 + return $this->getEditPolicy(); 73 + } 74 + } 75 + 76 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 77 + return false; 78 + } 79 + 80 + public function describeAutomaticCapability($capability) { 81 + return null; 82 + } 83 + 84 + 85 + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ 86 + 87 + 88 + public function getApplicationTransactionEditor() { 89 + return new PhabricatorSpacesNamespaceEditor(); 90 + } 91 + 92 + public function getApplicationTransactionObject() { 93 + return $this; 94 + } 95 + 96 + public function getApplicationTransactionTemplate() { 97 + return new PhabricatorSpacesNamespaceTransaction(); 98 + } 99 + 100 + public function willRenderTimeline( 101 + PhabricatorApplicationTransactionView $timeline, 102 + AphrontRequest $request) { 103 + return $timeline; 104 + } 105 + 106 + }
+49
src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php
··· 1 + <?php 2 + 3 + final class PhabricatorSpacesNamespaceTransaction 4 + extends PhabricatorApplicationTransaction { 5 + 6 + const TYPE_NAME = 'spaces:name'; 7 + const TYPE_DEFAULT = 'spaces:default'; 8 + 9 + public function getApplicationName() { 10 + return 'spaces'; 11 + } 12 + 13 + public function getApplicationTransactionType() { 14 + return PhabricatorSpacesNamespacePHIDType::TYPECONST; 15 + } 16 + 17 + public function getApplicationTransactionCommentObject() { 18 + return null; 19 + } 20 + 21 + public function getTitle() { 22 + $old = $this->getOldValue(); 23 + $new = $this->getNewValue(); 24 + 25 + $author_phid = $this->getAuthorPHID(); 26 + 27 + switch ($this->getTransactionType()) { 28 + case self::TYPE_NAME: 29 + if ($old === null) { 30 + return pht( 31 + '%s created this space.', 32 + $this->renderHandleLink($author_phid)); 33 + } else { 34 + return pht( 35 + '%s renamed this space from "%s" to "%s".', 36 + $this->renderHandleLink($author_phid), 37 + $old, 38 + $new); 39 + } 40 + case self::TYPE_DEFAULT: 41 + return pht( 42 + '%s made this the default space.', 43 + $this->renderHandleLink($author_phid)); 44 + } 45 + 46 + return parent::getTitle(); 47 + } 48 + 49 + }
+1
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 105 105 'db.fund' => array(), 106 106 'db.almanac' => array(), 107 107 'db.multimeter' => array(), 108 + 'db.spaces' => array(), 108 109 '0000.legacy.sql' => array( 109 110 'legacy' => 0, 110 111 ),