@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.

Policy - move some owners code into an editor class and check policy better

Summary: Ref T7094. We basically need to make sure folks can see repositories before making owners packages about code within. This cleans up things a little bit by moving a bunch of logic out of the storage class and into an editor class.

Test Plan: made a package and it worked! deleted a package and it worked! discovered buggy behavior in more complicated edits and filed T7127; note this bug exists before and after this diff.

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T7094

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

+218 -183
+2
src/__phutil_library_map__.php
··· 2071 2071 'PhabricatorOwnersOwner' => 'applications/owners/storage/PhabricatorOwnersOwner.php', 2072 2072 'PhabricatorOwnersPackage' => 'applications/owners/storage/PhabricatorOwnersPackage.php', 2073 2073 'PhabricatorOwnersPackageDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php', 2074 + 'PhabricatorOwnersPackageEditor' => 'applications/owners/editor/PhabricatorOwnersPackageEditor.php', 2074 2075 'PhabricatorOwnersPackagePHIDType' => 'applications/owners/phid/PhabricatorOwnersPackagePHIDType.php', 2075 2076 'PhabricatorOwnersPackagePathValidator' => 'applications/repository/worker/commitchangeparser/PhabricatorOwnersPackagePathValidator.php', 2076 2077 'PhabricatorOwnersPackageQuery' => 'applications/owners/query/PhabricatorOwnersPackageQuery.php', ··· 5315 5316 'PhabricatorPolicyInterface', 5316 5317 ), 5317 5318 'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource', 5319 + 'PhabricatorOwnersPackageEditor' => 'PhabricatorEditor', 5318 5320 'PhabricatorOwnersPackagePHIDType' => 'PhabricatorPHIDType', 5319 5321 'PhabricatorOwnersPackageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 5320 5322 'PhabricatorOwnersPackageTestCase' => 'PhabricatorTestCase',
+4 -2
src/applications/owners/controller/PhabricatorOwnersDeleteController.php
··· 19 19 } 20 20 21 21 if ($request->isDialogFormPost()) { 22 - $package->attachActorPHID($user->getPHID()); 23 - $package->delete(); 22 + id(new PhabricatorOwnersPackageEditor()) 23 + ->setActor($user) 24 + ->setPackage($package) 25 + ->delete(); 24 26 return id(new AphrontRedirectResponse())->setURI('/owners/'); 25 27 } 26 28
+4 -2
src/applications/owners/controller/PhabricatorOwnersEditController.php
··· 87 87 $package->attachUnsavedPaths($path_refs); 88 88 $package->attachOldAuditingEnabled($old_auditing_enabled); 89 89 $package->attachOldPrimaryOwnerPHID($old_primary); 90 - $package->attachActorPHID($user->getPHID()); 91 90 try { 92 - $package->save(); 91 + id(new PhabricatorOwnersPackageEditor()) 92 + ->setActor($user) 93 + ->setPackage($package) 94 + ->save(); 93 95 return id(new AphrontRedirectResponse()) 94 96 ->setURI('/owners/package/'.$package->getID().'/'); 95 97 } catch (AphrontDuplicateKeyQueryException $ex) {
+198
src/applications/owners/editor/PhabricatorOwnersPackageEditor.php
··· 1 + <?php 2 + 3 + final class PhabricatorOwnersPackageEditor extends PhabricatorEditor { 4 + 5 + private $package; 6 + 7 + public function setPackage(PhabricatorOwnersPackage $package) { 8 + $this->package = $package; 9 + return $this; 10 + } 11 + 12 + public function getPackage() { 13 + return $this->package; 14 + } 15 + 16 + public function save() { 17 + $actor = $this->getActor(); 18 + $package = $this->getPackage(); 19 + $package->attachActorPHID($actor->getPHID()); 20 + 21 + if ($package->getID()) { 22 + $is_new = false; 23 + } else { 24 + $is_new = true; 25 + } 26 + 27 + $package->openTransaction(); 28 + 29 + $ret = $package->save(); 30 + 31 + $add_owners = array(); 32 + $remove_owners = array(); 33 + $all_owners = array(); 34 + if ($package->getUnsavedOwners()) { 35 + $new_owners = array_fill_keys($package->getUnsavedOwners(), true); 36 + $cur_owners = array(); 37 + foreach ($package->loadOwners() as $owner) { 38 + if (empty($new_owners[$owner->getUserPHID()])) { 39 + $remove_owners[$owner->getUserPHID()] = true; 40 + $owner->delete(); 41 + continue; 42 + } 43 + $cur_owners[$owner->getUserPHID()] = true; 44 + } 45 + 46 + $add_owners = array_diff_key($new_owners, $cur_owners); 47 + $all_owners = array_merge( 48 + array($package->getPrimaryOwnerPHID() => true), 49 + $new_owners, 50 + $remove_owners); 51 + foreach ($add_owners as $phid => $ignored) { 52 + $owner = new PhabricatorOwnersOwner(); 53 + $owner->setPackageID($package->getID()); 54 + $owner->setUserPHID($phid); 55 + $owner->save(); 56 + } 57 + $package->attachUnsavedOwners(array()); 58 + } 59 + 60 + $add_paths = array(); 61 + $remove_paths = array(); 62 + $touched_repos = array(); 63 + if ($package->getUnsavedPaths()) { 64 + $new_paths = igroup( 65 + $package->getUnsavedPaths(), 66 + 'repositoryPHID', 67 + 'path'); 68 + $cur_paths = $package->loadPaths(); 69 + foreach ($cur_paths as $key => $path) { 70 + $repository_phid = $path->getRepositoryPHID(); 71 + $new_path = head(idx( 72 + idx($new_paths, $repository_phid, array()), 73 + $path->getPath(), 74 + array())); 75 + $excluded = $path->getExcluded(); 76 + if ($new_path === false || 77 + idx($new_path, 'excluded') != $excluded) { 78 + $touched_repos[$repository_phid] = true; 79 + $remove_paths[$repository_phid][$path->getPath()] = $excluded; 80 + $path->delete(); 81 + unset($cur_paths[$key]); 82 + } 83 + } 84 + 85 + $cur_paths = mgroup($cur_paths, 'getRepositoryPHID', 'getPath'); 86 + $repositories = id(new PhabricatorRepositoryQuery()) 87 + ->setViewer($actor) 88 + ->withPHIDs(array_keys($cur_paths)) 89 + ->execute(); 90 + $repositories = mpull($repositories, null, 'getPHID'); 91 + foreach ($new_paths as $repository_phid => $paths) { 92 + $repository = idx($repositories, $repository_phid); 93 + if (!$repository) { 94 + continue; 95 + } 96 + foreach ($paths as $path => $dicts) { 97 + $path = ltrim($path, '/'); 98 + // build query to validate path 99 + $drequest = DiffusionRequest::newFromDictionary( 100 + array( 101 + 'user' => $actor, 102 + 'repository' => $repository, 103 + 'path' => $path, 104 + )); 105 + $results = DiffusionBrowseResultSet::newFromConduit( 106 + DiffusionQuery::callConduitWithDiffusionRequest( 107 + $actor, 108 + $drequest, 109 + 'diffusion.browsequery', 110 + array( 111 + 'commit' => $drequest->getCommit(), 112 + 'path' => $path, 113 + 'needValidityOnly' => true, 114 + ))); 115 + $valid = $results->isValidResults(); 116 + $is_directory = true; 117 + if (!$valid) { 118 + switch ($results->getReasonForEmptyResultSet()) { 119 + case DiffusionBrowseResultSet::REASON_IS_FILE: 120 + $valid = true; 121 + $is_directory = false; 122 + break; 123 + case DiffusionBrowseResultSet::REASON_IS_EMPTY: 124 + $valid = true; 125 + break; 126 + } 127 + } 128 + if ($is_directory && substr($path, -1) != '/') { 129 + $path .= '/'; 130 + } 131 + if (substr($path, 0, 1) != '/') { 132 + $path = '/'.$path; 133 + } 134 + if (empty($cur_paths[$repository_phid][$path]) && $valid) { 135 + $touched_repos[$repository_phid] = true; 136 + $excluded = idx(reset($dicts), 'excluded', 0); 137 + $add_paths[$repository_phid][$path] = $excluded; 138 + $obj = new PhabricatorOwnersPath(); 139 + $obj->setPackageID($package->getID()); 140 + $obj->setRepositoryPHID($repository_phid); 141 + $obj->setPath($path); 142 + $obj->setExcluded($excluded); 143 + $obj->save(); 144 + } 145 + } 146 + } 147 + $package->attachUnsavedPaths(array()); 148 + } 149 + 150 + $package->saveTransaction(); 151 + 152 + if ($is_new) { 153 + $mail = new PackageCreateMail($package); 154 + } else { 155 + $mail = new PackageModifyMail( 156 + $package, 157 + array_keys($add_owners), 158 + array_keys($remove_owners), 159 + array_keys($all_owners), 160 + array_keys($touched_repos), 161 + $add_paths, 162 + $remove_paths); 163 + } 164 + $mail->setActor($actor); 165 + $mail->send(); 166 + 167 + return $ret; 168 + } 169 + 170 + public function delete() { 171 + $actor = $this->getActor(); 172 + $package = $this->getPackage(); 173 + $package->attachActorPHID($actor->getPHID()); 174 + 175 + $mails = id(new PackageDeleteMail($package)) 176 + ->setActor($actor) 177 + ->prepareMails(); 178 + 179 + $package->openTransaction(); 180 + 181 + foreach ($package->loadOwners() as $owner) { 182 + $owner->delete(); 183 + } 184 + foreach ($package->loadPaths() as $path) { 185 + $path->delete(); 186 + } 187 + $ret = $package->delete(); 188 + 189 + $package->saveTransaction(); 190 + 191 + foreach ($mails as $mail) { 192 + $mail->saveAndSend(); 193 + } 194 + 195 + return $ret; 196 + } 197 + 198 + }
+10 -179
src/applications/owners/storage/PhabricatorOwnersPackage.php
··· 9 9 protected $description; 10 10 protected $primaryOwnerPHID; 11 11 12 - private $unsavedOwners; 13 - private $unsavedPaths; 12 + private $unsavedOwners = self::ATTACHABLE; 13 + private $unsavedPaths = self::ATTACHABLE; 14 14 private $actorPHID; 15 15 private $oldPrimaryOwnerPHID; 16 16 private $oldAuditingEnabled; ··· 68 68 return $this; 69 69 } 70 70 71 + public function getUnsavedOwners() { 72 + return $this->assertAttached($this->unsavedOwners); 73 + } 74 + 71 75 public function attachUnsavedPaths(array $paths) { 72 76 $this->unsavedPaths = $paths; 73 77 return $this; 78 + } 79 + 80 + public function getUnsavedPaths() { 81 + return $this->assertAttached($this->unsavedPaths); 74 82 } 75 83 76 84 public function attachActorPHID($actor_phid) { ··· 246 254 } 247 255 248 256 return $ids; 249 - } 250 - 251 - private function getActor() { 252 - // TODO: This should be cleaner, but we'd likely need to move the whole 253 - // thing to an Editor (T603). 254 - return PhabricatorUser::getOmnipotentUser(); 255 - } 256 - 257 - public function save() { 258 - 259 - if ($this->getID()) { 260 - $is_new = false; 261 - } else { 262 - $is_new = true; 263 - } 264 - 265 - $this->openTransaction(); 266 - 267 - $ret = parent::save(); 268 - 269 - $add_owners = array(); 270 - $remove_owners = array(); 271 - $all_owners = array(); 272 - if ($this->unsavedOwners) { 273 - $new_owners = array_fill_keys($this->unsavedOwners, true); 274 - $cur_owners = array(); 275 - foreach ($this->loadOwners() as $owner) { 276 - if (empty($new_owners[$owner->getUserPHID()])) { 277 - $remove_owners[$owner->getUserPHID()] = true; 278 - $owner->delete(); 279 - continue; 280 - } 281 - $cur_owners[$owner->getUserPHID()] = true; 282 - } 283 - 284 - $add_owners = array_diff_key($new_owners, $cur_owners); 285 - $all_owners = array_merge( 286 - array($this->getPrimaryOwnerPHID() => true), 287 - $new_owners, 288 - $remove_owners); 289 - foreach ($add_owners as $phid => $ignored) { 290 - $owner = new PhabricatorOwnersOwner(); 291 - $owner->setPackageID($this->getID()); 292 - $owner->setUserPHID($phid); 293 - $owner->save(); 294 - } 295 - unset($this->unsavedOwners); 296 - } 297 - 298 - $add_paths = array(); 299 - $remove_paths = array(); 300 - $touched_repos = array(); 301 - if ($this->unsavedPaths) { 302 - $new_paths = igroup($this->unsavedPaths, 'repositoryPHID', 'path'); 303 - $cur_paths = $this->loadPaths(); 304 - foreach ($cur_paths as $key => $path) { 305 - $repository_phid = $path->getRepositoryPHID(); 306 - $new_path = head(idx( 307 - idx($new_paths, $repository_phid, array()), 308 - $path->getPath(), 309 - array())); 310 - $excluded = $path->getExcluded(); 311 - if (!$new_path || idx($new_path, 'excluded') != $excluded) { 312 - $touched_repos[$repository_phid] = true; 313 - $remove_paths[$repository_phid][$path->getPath()] = $excluded; 314 - $path->delete(); 315 - unset($cur_paths[$key]); 316 - } 317 - } 318 - 319 - $cur_paths = mgroup($cur_paths, 'getRepositoryPHID', 'getPath'); 320 - foreach ($new_paths as $repository_phid => $paths) { 321 - // TODO: (T603) Thread policy stuff in here. 322 - 323 - // get repository object for path validation 324 - $repository = id(new PhabricatorRepository())->loadOneWhere( 325 - 'phid = %s', 326 - $repository_phid); 327 - if (!$repository) { 328 - continue; 329 - } 330 - foreach ($paths as $path => $dicts) { 331 - $path = ltrim($path, '/'); 332 - // build query to validate path 333 - $drequest = DiffusionRequest::newFromDictionary( 334 - array( 335 - 'user' => $this->getActor(), 336 - 'repository' => $repository, 337 - 'path' => $path, 338 - )); 339 - $results = DiffusionBrowseResultSet::newFromConduit( 340 - DiffusionQuery::callConduitWithDiffusionRequest( 341 - $this->getActor(), 342 - $drequest, 343 - 'diffusion.browsequery', 344 - array( 345 - 'commit' => $drequest->getCommit(), 346 - 'path' => $path, 347 - 'needValidityOnly' => true, 348 - ))); 349 - $valid = $results->isValidResults(); 350 - $is_directory = true; 351 - if (!$valid) { 352 - switch ($results->getReasonForEmptyResultSet()) { 353 - case DiffusionBrowseResultSet::REASON_IS_FILE: 354 - $valid = true; 355 - $is_directory = false; 356 - break; 357 - case DiffusionBrowseResultSet::REASON_IS_EMPTY: 358 - $valid = true; 359 - break; 360 - } 361 - } 362 - if ($is_directory && substr($path, -1) != '/') { 363 - $path .= '/'; 364 - } 365 - if (substr($path, 0, 1) != '/') { 366 - $path = '/'.$path; 367 - } 368 - if (empty($cur_paths[$repository_phid][$path]) && $valid) { 369 - $touched_repos[$repository_phid] = true; 370 - $excluded = idx(reset($dicts), 'excluded', 0); 371 - $add_paths[$repository_phid][$path] = $excluded; 372 - $obj = new PhabricatorOwnersPath(); 373 - $obj->setPackageID($this->getID()); 374 - $obj->setRepositoryPHID($repository_phid); 375 - $obj->setPath($path); 376 - $obj->setExcluded($excluded); 377 - $obj->save(); 378 - } 379 - } 380 - } 381 - unset($this->unsavedPaths); 382 - } 383 - 384 - $this->saveTransaction(); 385 - 386 - if ($is_new) { 387 - $mail = new PackageCreateMail($this); 388 - } else { 389 - $mail = new PackageModifyMail( 390 - $this, 391 - array_keys($add_owners), 392 - array_keys($remove_owners), 393 - array_keys($all_owners), 394 - array_keys($touched_repos), 395 - $add_paths, 396 - $remove_paths); 397 - } 398 - $mail->setActor($this->getActor()); 399 - $mail->send(); 400 - 401 - return $ret; 402 - } 403 - 404 - public function delete() { 405 - $mails = id(new PackageDeleteMail($this)) 406 - ->setActor($this->getActor()) 407 - ->prepareMails(); 408 - 409 - $this->openTransaction(); 410 - foreach ($this->loadOwners() as $owner) { 411 - $owner->delete(); 412 - } 413 - foreach ($this->loadPaths() as $path) { 414 - $path->delete(); 415 - } 416 - 417 - $ret = parent::delete(); 418 - 419 - $this->saveTransaction(); 420 - 421 - foreach ($mails as $mail) { 422 - $mail->saveAndSend(); 423 - } 424 - 425 - return $ret; 426 257 } 427 258 428 259 private static function splitPath($path) {