@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

Add `diffusion.uri.edit` for creating and editing repository URIs

Summary: Ref T10748. Brings the rest of the transactions to EditEngine, supports creating via API.

Test Plan:
- Created a URI via API.
- Created a URI via web.
- Tried to apply sneaky transactions, got rejected with good error messages. <_< >_>

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10748

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

+188 -6
+2
src/__phutil_library_map__.php
··· 816 816 'DiffusionTagListController' => 'applications/diffusion/controller/DiffusionTagListController.php', 817 817 'DiffusionTagListView' => 'applications/diffusion/view/DiffusionTagListView.php', 818 818 'DiffusionTagsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionTagsQueryConduitAPIMethod.php', 819 + 'DiffusionURIEditConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionURIEditConduitAPIMethod.php', 819 820 'DiffusionURIEditEngine' => 'applications/diffusion/editor/DiffusionURIEditEngine.php', 820 821 'DiffusionURIEditor' => 'applications/diffusion/editor/DiffusionURIEditor.php', 821 822 'DiffusionURITestCase' => 'applications/diffusion/request/__tests__/DiffusionURITestCase.php', ··· 5044 5045 'DiffusionTagListController' => 'DiffusionController', 5045 5046 'DiffusionTagListView' => 'DiffusionView', 5046 5047 'DiffusionTagsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 5048 + 'DiffusionURIEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 5047 5049 'DiffusionURIEditEngine' => 'PhabricatorEditEngine', 5048 5050 'DiffusionURIEditor' => 'PhabricatorApplicationTransactionEditor', 5049 5051 'DiffusionURITestCase' => 'PhutilTestCase',
+20
src/applications/diffusion/conduit/DiffusionURIEditConduitAPIMethod.php
··· 1 + <?php 2 + 3 + final class DiffusionURIEditConduitAPIMethod 4 + extends PhabricatorEditEngineAPIMethod { 5 + 6 + public function getAPIMethodName() { 7 + return 'diffusion.uri.edit'; 8 + } 9 + 10 + public function newEditEngine() { 11 + return new DiffusionURIEditEngine(); 12 + } 13 + 14 + public function getMethodSummary() { 15 + return pht( 16 + 'Apply transactions to create a new repository URI or edit an existing '. 17 + 'one.'); 18 + } 19 + 20 + }
+47 -1
src/applications/diffusion/editor/DiffusionURIEditEngine.php
··· 37 37 } 38 38 39 39 protected function newEditableObject() { 40 + $uri = PhabricatorRepositoryURI::initializeNewURI(); 41 + 40 42 $repository = $this->getRepository(); 41 - return PhabricatorRepositoryURI::initializeNewURI($repository); 43 + if ($repository) { 44 + $uri->setRepositoryPHID($repository->getPHID()); 45 + $uri->attachRepository($repository); 46 + } 47 + 48 + return $uri; 42 49 } 43 50 44 51 protected function newObjectQuery() { ··· 77 84 $viewer = $this->getViewer(); 78 85 79 86 return array( 87 + id(new PhabricatorHandlesEditField()) 88 + ->setKey('repository') 89 + ->setAliases(array('repositoryPHID')) 90 + ->setLabel(pht('Repository')) 91 + ->setIsRequired(true) 92 + ->setIsConduitOnly(true) 93 + ->setTransactionType( 94 + PhabricatorRepositoryURITransaction::TYPE_REPOSITORY) 95 + ->setDescription(pht('The repository this URI is associated with.')) 96 + ->setConduitDescription( 97 + pht( 98 + 'Create a URI in a given repository. This transaction type '. 99 + 'must be present when creating a new URI and must not be '. 100 + 'present when editing an existing URI.')) 101 + ->setConduitTypeDescription( 102 + pht('Repository PHID to create a new URI for.')) 103 + ->setSingleValue($object->getRepositoryPHID()), 80 104 id(new PhabricatorTextEditField()) 81 105 ->setKey('uri') 82 106 ->setLabel(pht('URI')) ··· 104 128 ->setConduitTypeDescription(pht('New display behavior.')) 105 129 ->setValue($object->getDisplayType()) 106 130 ->setOptions($object->getAvailableDisplayTypeOptions()), 131 + id(new PhabricatorHandlesEditField()) 132 + ->setKey('credential') 133 + ->setAliases(array('credentialPHID')) 134 + ->setLabel(pht('Credential')) 135 + ->setIsConduitOnly(true) 136 + ->setTransactionType( 137 + PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL) 138 + ->setDescription( 139 + pht('The credential to use when interacting with this URI.')) 140 + ->setConduitDescription(pht('Change the credential for this URI.')) 141 + ->setConduitTypeDescription(pht('New credential PHID, or null.')) 142 + ->setSingleValue($object->getCredentialPHID()), 143 + id(new PhabricatorBoolEditField()) 144 + ->setKey('disable') 145 + ->setLabel(pht('Disabled')) 146 + ->setIsConduitOnly(true) 147 + ->setTransactionType(PhabricatorRepositoryURITransaction::TYPE_DISABLE) 148 + ->setDescription(pht('Active status of the URI.')) 149 + ->setConduitDescription(pht('Disable or activate the URI.')) 150 + ->setConduitTypeDescription(pht('True to disable the URI.')) 151 + ->setOptions(pht('Enable'), pht('Disable')) 152 + ->setValue($object->getIsDisabled()), 107 153 ); 108 154 } 109 155
+112 -1
src/applications/diffusion/editor/DiffusionURIEditor.php
··· 14 14 public function getTransactionTypes() { 15 15 $types = parent::getTransactionTypes(); 16 16 17 + $types[] = PhabricatorRepositoryURITransaction::TYPE_REPOSITORY; 17 18 $types[] = PhabricatorRepositoryURITransaction::TYPE_URI; 18 19 $types[] = PhabricatorRepositoryURITransaction::TYPE_IO; 19 20 $types[] = PhabricatorRepositoryURITransaction::TYPE_DISPLAY; 21 + $types[] = PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL; 22 + $types[] = PhabricatorRepositoryURITransaction::TYPE_DISABLE; 20 23 21 24 return $types; 22 25 } ··· 32 35 return $object->getIOType(); 33 36 case PhabricatorRepositoryURITransaction::TYPE_DISPLAY: 34 37 return $object->getDisplayType(); 38 + case PhabricatorRepositoryURITransaction::TYPE_REPOSITORY: 39 + return $object->getRepositoryPHID(); 40 + case PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL: 41 + return $object->getCredentialPHID(); 42 + case PhabricatorRepositoryURITransaction::TYPE_DISABLE: 43 + return (int)$object->getIsDisabled(); 35 44 } 36 45 37 46 return parent::getCustomTransactionOldValue($object, $xaction); ··· 45 54 case PhabricatorRepositoryURITransaction::TYPE_URI: 46 55 case PhabricatorRepositoryURITransaction::TYPE_IO: 47 56 case PhabricatorRepositoryURITransaction::TYPE_DISPLAY: 57 + case PhabricatorRepositoryURITransaction::TYPE_REPOSITORY: 58 + case PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL: 48 59 return $xaction->getNewValue(); 60 + case PhabricatorRepositoryURITransaction::TYPE_DISABLE: 61 + return (int)$xaction->getNewValue(); 49 62 } 50 63 51 64 return parent::getCustomTransactionNewValue($object, $xaction); ··· 65 78 case PhabricatorRepositoryURITransaction::TYPE_DISPLAY: 66 79 $object->setDisplayType($xaction->getNewValue()); 67 80 break; 81 + case PhabricatorRepositoryURITransaction::TYPE_REPOSITORY: 82 + $object->setRepositoryPHID($xaction->getNewValue()); 83 + break; 84 + case PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL: 85 + $object->setCredentialPHID($xaction->getNewValue()); 86 + break; 87 + case PhabricatorRepositoryURITransaction::TYPE_DISABLE: 88 + $object->setIsDisabled($xaction->getNewValue()); 89 + break; 68 90 } 69 91 } 70 92 ··· 76 98 case PhabricatorRepositoryURITransaction::TYPE_URI: 77 99 case PhabricatorRepositoryURITransaction::TYPE_IO: 78 100 case PhabricatorRepositoryURITransaction::TYPE_DISPLAY: 101 + case PhabricatorRepositoryURITransaction::TYPE_REPOSITORY: 102 + case PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL: 103 + case PhabricatorRepositoryURITransaction::TYPE_DISABLE: 79 104 return; 80 105 } 81 106 ··· 90 115 $errors = parent::validateTransaction($object, $type, $xactions); 91 116 92 117 switch ($type) { 118 + case PhabricatorRepositoryURITransaction::TYPE_REPOSITORY: 119 + $missing = $this->validateIsEmptyTextField( 120 + $object->getRepositoryPHID(), 121 + $xactions); 122 + if ($missing) { 123 + // NOTE: This isn't being marked as a missing field error because 124 + // it's a fundamental, required property of the URI. 125 + $errors[] = new PhabricatorApplicationTransactionValidationError( 126 + $type, 127 + pht('Required'), 128 + pht( 129 + 'When creating a repository URI, you must specify which '. 130 + 'repository the URI will belong to.'), 131 + nonempty(last($xactions), null)); 132 + break; 133 + } 134 + 135 + $viewer = $this->getActor(); 136 + 137 + foreach ($xactions as $xaction) { 138 + $repository_phid = $xaction->getNewValue(); 139 + 140 + // If this isn't changing anything, let it through as-is. 141 + if ($repository_phid == $object->getRepositoryPHID()) { 142 + continue; 143 + } 144 + 145 + if (!$this->getIsNewObject()) { 146 + $errors[] = new PhabricatorApplicationTransactionValidationError( 147 + $type, 148 + pht('Invalid'), 149 + pht( 150 + 'The repository a URI is associated with is immutable, and '. 151 + 'can not be changed after the URI is created.'), 152 + $xaction); 153 + continue; 154 + } 155 + 156 + $repository = id(new PhabricatorRepositoryQuery()) 157 + ->setViewer($viewer) 158 + ->withPHIDs(array($repository_phid)) 159 + ->requireCapabilities( 160 + array( 161 + PhabricatorPolicyCapability::CAN_VIEW, 162 + PhabricatorPolicyCapability::CAN_EDIT, 163 + )) 164 + ->executeOne(); 165 + if (!$repository) { 166 + $errors[] = new PhabricatorApplicationTransactionValidationError( 167 + $type, 168 + pht('Invalid'), 169 + pht( 170 + 'To create a URI for a repository ("%s"), it must exist and '. 171 + 'you must have permission to edit it.', 172 + $repository_phid), 173 + $xaction); 174 + continue; 175 + } 176 + } 177 + break; 178 + case PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL: 179 + $viewer = $this->getActor(); 180 + foreach ($xactions as $xaction) { 181 + $credential_phid = $xaction->getNewValue(); 182 + 183 + if ($credential_phid == $object->getCredentialPHID()) { 184 + continue; 185 + } 186 + 187 + $credential = id(new PassphraseCredentialQuery()) 188 + ->setViewer($viewer) 189 + ->withPHIDs(array($credential_phid)) 190 + ->executeOne(); 191 + if (!$credential) { 192 + $errors[] = new PhabricatorApplicationTransactionValidationError( 193 + $type, 194 + pht('Invalid'), 195 + pht( 196 + 'You can only associate a credential ("%s") with a repository '. 197 + 'URI if it exists and you have permission to see it.', 198 + $credential_phid), 199 + $xaction); 200 + continue; 201 + } 202 + } 203 + break; 93 204 case PhabricatorRepositoryURITransaction::TYPE_URI: 94 205 $missing = $this->validateIsEmptyTextField( 95 206 $object->getURI(), ··· 99 210 $error = new PhabricatorApplicationTransactionValidationError( 100 211 $type, 101 212 pht('Required'), 102 - pht('Repository URI is required.'), 213 + pht('A repository URI must have a nonempty URI.'), 103 214 nonempty(last($xactions), null)); 104 215 105 216 $error->setIsMissingFieldError(true);
+3 -1
src/applications/repository/storage/PhabricatorRepository.php
··· 2179 2179 $uris = array(); 2180 2180 foreach ($protocol_map as $protocol => $proto_supported) { 2181 2181 foreach ($identifier_map as $identifier => $id_supported) { 2182 - $uris[] = PhabricatorRepositoryURI::initializeNewURI($this) 2182 + $uris[] = PhabricatorRepositoryURI::initializeNewURI() 2183 + ->setRepositoryPHID($this->getPHID()) 2184 + ->attachRepository($this) 2183 2185 ->setBuiltinProtocol($protocol) 2184 2186 ->setBuiltinIdentifier($identifier) 2185 2187 ->setIsDisabled(!$proto_supported || !$id_supported);
+1 -3
src/applications/repository/storage/PhabricatorRepositoryURI.php
··· 62 62 ) + parent::getConfiguration(); 63 63 } 64 64 65 - public static function initializeNewURI(PhabricatorRepository $repository) { 65 + public static function initializeNewURI() { 66 66 return id(new self()) 67 - ->attachRepository($repository) 68 - ->setRepositoryPHID($repository->getPHID()) 69 67 ->setIoType(self::IO_DEFAULT) 70 68 ->setDisplayType(self::DISPLAY_DEFAULT) 71 69 ->setIsDisabled(0);
+3
src/applications/repository/storage/PhabricatorRepositoryURITransaction.php
··· 3 3 final class PhabricatorRepositoryURITransaction 4 4 extends PhabricatorApplicationTransaction { 5 5 6 + const TYPE_REPOSITORY = 'diffusion.uri.repository'; 6 7 const TYPE_URI = 'diffusion.uri.uri'; 7 8 const TYPE_IO = 'diffusion.uri.io'; 8 9 const TYPE_DISPLAY = 'diffusion.uri.display'; 10 + const TYPE_CREDENTIAL = 'diffusion.uri.credential'; 11 + const TYPE_DISABLE = 'diffusion.uri.disable'; 9 12 10 13 public function getApplicationName() { 11 14 return 'repository';