@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

Use ApplicationTransactions for all non-path edits to Owners packages

Summary: Ref T8320.

Test Plan: {F437431}

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T8320

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

+592 -72
+2
resources/sql/autopatches/20150526.owners.mailkey.1.sql
··· 1 + ALTER TABLE {$NAMESPACE}_owners.owners_package 2 + ADD mailKey binary(20) NOT NULL;
+18
resources/sql/autopatches/20150526.owners.mailkey.2.php
··· 1 + <?php 2 + 3 + $table = new PhabricatorOwnersPackage(); 4 + $conn_w = $table->establishConnection('w'); 5 + $iterator = new LiskMigrationIterator($table); 6 + foreach ($iterator as $package) { 7 + $id = $package->getID(); 8 + 9 + echo pht('Adding mail key for package %d...', $id); 10 + echo "\n"; 11 + 12 + queryfx( 13 + $conn_w, 14 + 'UPDATE %T SET mailKey = %s WHERE id = %d', 15 + $table->getTableName(), 16 + Filesystem::readRandomCharacters(20), 17 + $id); 18 + }
+19
resources/sql/autopatches/20150526.owners.xaction.sql
··· 1 + CREATE TABLE {$NAMESPACE}_owners.owners_packagetransaction ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 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) DEFAULT NULL, 9 + commentVersion INT UNSIGNED NOT NULL, 10 + transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL, 11 + oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, 12 + newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, 13 + contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, 14 + metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, 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};
+7
src/__phutil_library_map__.php
··· 2180 2180 'PhabricatorOwnersPackageQuery' => 'applications/owners/query/PhabricatorOwnersPackageQuery.php', 2181 2181 'PhabricatorOwnersPackageSearchEngine' => 'applications/owners/query/PhabricatorOwnersPackageSearchEngine.php', 2182 2182 'PhabricatorOwnersPackageTestCase' => 'applications/owners/storage/__tests__/PhabricatorOwnersPackageTestCase.php', 2183 + 'PhabricatorOwnersPackageTransaction' => 'applications/owners/storage/PhabricatorOwnersPackageTransaction.php', 2184 + 'PhabricatorOwnersPackageTransactionEditor' => 'applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php', 2185 + 'PhabricatorOwnersPackageTransactionQuery' => 'applications/owners/query/PhabricatorOwnersPackageTransactionQuery.php', 2183 2186 'PhabricatorOwnersPath' => 'applications/owners/storage/PhabricatorOwnersPath.php', 2184 2187 'PhabricatorOwnersPathsController' => 'applications/owners/controller/PhabricatorOwnersPathsController.php', 2185 2188 'PhabricatorPHDConfigOptions' => 'applications/config/option/PhabricatorPHDConfigOptions.php', ··· 5581 5584 'PhabricatorOwnersPackage' => array( 5582 5585 'PhabricatorOwnersDAO', 5583 5586 'PhabricatorPolicyInterface', 5587 + 'PhabricatorApplicationTransactionInterface', 5584 5588 ), 5585 5589 'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource', 5586 5590 'PhabricatorOwnersPackageEditor' => 'PhabricatorEditor', ··· 5588 5592 'PhabricatorOwnersPackageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 5589 5593 'PhabricatorOwnersPackageSearchEngine' => 'PhabricatorApplicationSearchEngine', 5590 5594 'PhabricatorOwnersPackageTestCase' => 'PhabricatorTestCase', 5595 + 'PhabricatorOwnersPackageTransaction' => 'PhabricatorApplicationTransaction', 5596 + 'PhabricatorOwnersPackageTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 5597 + 'PhabricatorOwnersPackageTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 5591 5598 'PhabricatorOwnersPath' => 'PhabricatorOwnersDAO', 5592 5599 'PhabricatorOwnersPathsController' => 'PhabricatorOwnersController', 5593 5600 'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions',
+6
src/applications/owners/controller/PhabricatorOwnersDetailController.php
··· 124 124 $crumbs = $this->buildApplicationCrumbs(); 125 125 $crumbs->addTextCrumb($package->getName()); 126 126 127 + $timeline = $this->buildTransactionTimeline( 128 + $package, 129 + new PhabricatorOwnersPackageTransactionQuery()); 130 + $timeline->setShouldTerminate(true); 131 + 127 132 return $this->buildApplicationPage( 128 133 array( 129 134 $crumbs, 130 135 $panel, 131 136 $this->renderPathsTable($paths, $repositories), 132 137 $commit_panels, 138 + $timeline, 133 139 ), 134 140 array( 135 141 'title' => $package->getName(),
+76 -70
src/applications/owners/controller/PhabricatorOwnersEditController.php
··· 21 21 if (!$package) { 22 22 return new Aphront404Response(); 23 23 } 24 - 25 24 $is_new = false; 26 25 } else { 27 - $package = new PhabricatorOwnersPackage(); 28 - $package->setPrimaryOwnerPHID($viewer->getPHID()); 29 - 26 + $package = PhabricatorOwnersPackage::initializeNewPackage($viewer); 30 27 $is_new = true; 31 28 } 32 29 33 30 $e_name = true; 34 31 $e_primary = true; 35 32 33 + $v_name = $package->getName(); 34 + $v_primary = $package->getPrimaryOwnerPHID(); 35 + // TODO: Pull these off needOwners() on the Query. 36 + $v_owners = mpull($package->loadOwners(), 'getUserPHID'); 37 + $v_auditing = $package->getAuditingEnabled(); 38 + $v_description = $package->getDescription(); 39 + 40 + 36 41 $errors = array(); 37 - 38 42 if ($request->isFormPost()) { 39 - $package->setName($request->getStr('name')); 40 - $package->setDescription($request->getStr('description')); 41 - $old_auditing_enabled = $package->getAuditingEnabled(); 42 - $package->setAuditingEnabled( 43 - ($request->getStr('auditing') === 'enabled') 44 - ? 1 45 - : 0); 43 + $xactions = array(); 46 44 47 - $primary = $request->getArr('primary'); 48 - $primary = reset($primary); 49 - $old_primary = $package->getPrimaryOwnerPHID(); 50 - $package->setPrimaryOwnerPHID($primary); 45 + $v_name = $request->getStr('name'); 46 + $v_primary = head($request->getArr('primary')); 47 + $v_owners = $request->getArr('owners'); 48 + $v_auditing = ($request->getStr('auditing') == 'enabled'); 49 + $v_description = $request->getStr('description'); 51 50 52 - $owners = $request->getArr('owners'); 53 - if ($primary) { 54 - array_unshift($owners, $primary); 51 + if ($v_primary) { 52 + $v_owners[] = $v_primary; 53 + $v_owners = array_unique($v_owners); 55 54 } 56 - $owners = array_unique($owners); 57 55 58 - if (!strlen($package->getName())) { 59 - $e_name = pht('Required'); 60 - $errors[] = pht('Package name is required.'); 61 - } else { 62 - $e_name = null; 63 - } 56 + $type_name = PhabricatorOwnersPackageTransaction::TYPE_NAME; 57 + $type_primary = PhabricatorOwnersPackageTransaction::TYPE_PRIMARY; 58 + $type_owners = PhabricatorOwnersPackageTransaction::TYPE_OWNERS; 59 + $type_auditing = PhabricatorOwnersPackageTransaction::TYPE_AUDITING; 60 + $type_description = PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION; 64 61 65 - if (!$package->getPrimaryOwnerPHID()) { 66 - $e_primary = pht('Required'); 67 - $errors[] = pht('Package must have a primary owner.'); 68 - } else { 69 - $e_primary = null; 70 - } 62 + $xactions[] = id(new PhabricatorOwnersPackageTransaction()) 63 + ->setTransactionType($type_name) 64 + ->setNewValue($v_name); 71 65 72 - if (!$errors) { 73 - $package->attachUnsavedOwners($owners); 74 - $package->attachUnsavedPaths(array()); 75 - $package->attachOldAuditingEnabled($old_auditing_enabled); 76 - $package->attachOldPrimaryOwnerPHID($old_primary); 77 - try { 78 - id(new PhabricatorOwnersPackageEditor()) 79 - ->setActor($viewer) 80 - ->setPackage($package) 81 - ->save(); 66 + $xactions[] = id(new PhabricatorOwnersPackageTransaction()) 67 + ->setTransactionType($type_primary) 68 + ->setNewValue($v_primary); 82 69 83 - $id = $package->getID(); 84 - if ($is_new) { 85 - $next_uri = '/owners/paths/'.$id.'/'; 86 - } else { 87 - $next_uri = '/owners/package/'.$id.'/'; 88 - } 70 + $xactions[] = id(new PhabricatorOwnersPackageTransaction()) 71 + ->setTransactionType($type_owners) 72 + ->setNewValue($v_owners); 73 + 74 + $xactions[] = id(new PhabricatorOwnersPackageTransaction()) 75 + ->setTransactionType($type_auditing) 76 + ->setNewValue($v_auditing); 77 + 78 + $xactions[] = id(new PhabricatorOwnersPackageTransaction()) 79 + ->setTransactionType($type_description) 80 + ->setNewValue($v_description); 81 + 82 + $editor = id(new PhabricatorOwnersPackageTransactionEditor()) 83 + ->setActor($viewer) 84 + ->setContentSourceFromRequest($request) 85 + ->setContinueOnNoEffect(true); 86 + 87 + try { 88 + $editor->applyTransactions($package, $xactions); 89 89 90 - return id(new AphrontRedirectResponse())->setURI($next_uri); 91 - } catch (AphrontDuplicateKeyQueryException $ex) { 92 - $e_name = pht('Duplicate'); 93 - $errors[] = pht('Package name must be unique.'); 90 + $id = $package->getID(); 91 + if ($is_new) { 92 + $next_uri = '/owners/paths/'.$id.'/'; 93 + } else { 94 + $next_uri = '/owners/package/'.$id.'/'; 94 95 } 96 + 97 + return id(new AphrontRedirectResponse())->setURI($next_uri); 98 + } catch (AphrontDuplicateKeyQueryException $ex) { 99 + $e_name = pht('Duplicate'); 100 + $errors[] = pht('Package name must be unique.'); 101 + } catch (PhabricatorApplicationTransactionValidationException $ex) { 102 + $validation_exception = $ex; 103 + 104 + $e_name = $ex->getShortMessage($type_name); 105 + $e_primary = $ex->getShortMessage($type_primary); 95 106 } 96 - } else { 97 - $owners = $package->loadOwners(); 98 - $owners = mpull($owners, 'getUserPHID'); 99 107 } 100 108 101 - $primary = $package->getPrimaryOwnerPHID(); 102 - if ($primary) { 103 - $value_primary_owner = array($primary); 109 + if ($v_primary) { 110 + $value_primary_owner = array($v_primary); 104 111 } else { 105 112 $value_primary_owner = array(); 106 113 } ··· 121 128 id(new AphrontFormTextControl()) 122 129 ->setLabel(pht('Name')) 123 130 ->setName('name') 124 - ->setValue($package->getName()) 131 + ->setValue($v_name) 125 132 ->setError($e_name)) 126 133 ->appendControl( 127 134 id(new AphrontFormTokenizerControl()) ··· 136 143 ->setDatasource(new PhabricatorProjectOrUserDatasource()) 137 144 ->setLabel(pht('Owners')) 138 145 ->setName('owners') 139 - ->setValue($owners)) 146 + ->setValue($v_owners)) 140 147 ->appendChild( 141 148 id(new AphrontFormSelectControl()) 142 149 ->setName('auditing') ··· 147 154 'this package will be reviewed to make sure an owner '. 148 155 'of the package is involved and the commit message has '. 149 156 'a valid revision, reviewed by, and author.')) 150 - ->setOptions(array( 151 - 'disabled' => pht('Disabled'), 152 - 'enabled' => pht('Enabled'), 153 - )) 154 - ->setValue( 155 - $package->getAuditingEnabled() 156 - ? 'enabled' 157 - : 'disabled')) 157 + ->setOptions( 158 + array( 159 + 'disabled' => pht('Disabled'), 160 + 'enabled' => pht('Enabled'), 161 + )) 162 + ->setValue(($v_auditing ? 'enabled' : 'disabled'))) 158 163 ->appendChild( 159 - id(new AphrontFormTextAreaControl()) 164 + id(new PhabricatorRemarkupControl()) 165 + ->setUser($viewer) 160 166 ->setLabel(pht('Description')) 161 167 ->setName('description') 162 - ->setValue($package->getDescription())) 168 + ->setValue($v_description)) 163 169 ->appendChild( 164 170 id(new AphrontFormSubmitControl()) 165 171 ->addCancelButton($cancel_uri)
+240
src/applications/owners/editor/PhabricatorOwnersPackageTransactionEditor.php
··· 1 + <?php 2 + 3 + final class PhabricatorOwnersPackageTransactionEditor 4 + extends PhabricatorApplicationTransactionEditor { 5 + 6 + public function getEditorApplicationClass() { 7 + return 'PhabricatorOwnersApplication'; 8 + } 9 + 10 + public function getEditorObjectsDescription() { 11 + return pht('Owners Packages'); 12 + } 13 + 14 + public function getTransactionTypes() { 15 + $types = parent::getTransactionTypes(); 16 + 17 + $types[] = PhabricatorOwnersPackageTransaction::TYPE_NAME; 18 + $types[] = PhabricatorOwnersPackageTransaction::TYPE_PRIMARY; 19 + $types[] = PhabricatorOwnersPackageTransaction::TYPE_OWNERS; 20 + $types[] = PhabricatorOwnersPackageTransaction::TYPE_AUDITING; 21 + $types[] = PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION; 22 + 23 + return $types; 24 + } 25 + 26 + protected function getCustomTransactionOldValue( 27 + PhabricatorLiskDAO $object, 28 + PhabricatorApplicationTransaction $xaction) { 29 + 30 + switch ($xaction->getTransactionType()) { 31 + case PhabricatorOwnersPackageTransaction::TYPE_NAME: 32 + return $object->getName(); 33 + case PhabricatorOwnersPackageTransaction::TYPE_PRIMARY: 34 + return $object->getPrimaryOwnerPHID(); 35 + case PhabricatorOwnersPackageTransaction::TYPE_OWNERS: 36 + // TODO: needOwners() this on the Query. 37 + $phids = mpull($object->loadOwners(), 'getUserPHID'); 38 + $phids = array_values($phids); 39 + return $phids; 40 + case PhabricatorOwnersPackageTransaction::TYPE_AUDITING: 41 + return (int)$object->getAuditingEnabled(); 42 + case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION: 43 + return $object->getDescription(); 44 + } 45 + } 46 + 47 + protected function getCustomTransactionNewValue( 48 + PhabricatorLiskDAO $object, 49 + PhabricatorApplicationTransaction $xaction) { 50 + 51 + switch ($xaction->getTransactionType()) { 52 + case PhabricatorOwnersPackageTransaction::TYPE_NAME: 53 + case PhabricatorOwnersPackageTransaction::TYPE_PRIMARY: 54 + case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION: 55 + return $xaction->getNewValue(); 56 + case PhabricatorOwnersPackageTransaction::TYPE_AUDITING: 57 + return (int)$xaction->getNewValue(); 58 + case PhabricatorOwnersPackageTransaction::TYPE_OWNERS: 59 + $phids = $xaction->getNewValue(); 60 + $phids = array_unique($phids); 61 + $phids = array_values($phids); 62 + return $phids; 63 + } 64 + } 65 + 66 + protected function applyCustomInternalTransaction( 67 + PhabricatorLiskDAO $object, 68 + PhabricatorApplicationTransaction $xaction) { 69 + 70 + switch ($xaction->getTransactionType()) { 71 + case PhabricatorOwnersPackageTransaction::TYPE_NAME: 72 + $object->setName($xaction->getNewValue()); 73 + return; 74 + case PhabricatorOwnersPackageTransaction::TYPE_PRIMARY: 75 + $object->setPrimaryOwnerPHID($xaction->getNewValue()); 76 + return; 77 + case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION: 78 + $object->setDescription($xaction->getNewValue()); 79 + return; 80 + case PhabricatorOwnersPackageTransaction::TYPE_AUDITING: 81 + $object->setAuditingEnabled($xaction->getNewValue()); 82 + return; 83 + case PhabricatorOwnersPackageTransaction::TYPE_OWNERS: 84 + return; 85 + } 86 + 87 + return parent::applyCustomInternalTransaction($object, $xaction); 88 + } 89 + 90 + protected function applyCustomExternalTransaction( 91 + PhabricatorLiskDAO $object, 92 + PhabricatorApplicationTransaction $xaction) { 93 + 94 + switch ($xaction->getTransactionType()) { 95 + case PhabricatorOwnersPackageTransaction::TYPE_NAME: 96 + case PhabricatorOwnersPackageTransaction::TYPE_PRIMARY: 97 + case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION: 98 + case PhabricatorOwnersPackageTransaction::TYPE_AUDITING: 99 + return; 100 + case PhabricatorOwnersPackageTransaction::TYPE_OWNERS: 101 + $old = $xaction->getOldValue(); 102 + $new = $xaction->getNewValue(); 103 + 104 + // TODO: needOwners this 105 + $owners = $object->loadOwners(); 106 + $owners = mpull($owners, null, 'getUserPHID'); 107 + 108 + $rem = array_diff($old, $new); 109 + foreach ($rem as $phid) { 110 + if (isset($owners[$phid])) { 111 + $owners[$phid]->delete(); 112 + unset($owners[$phid]); 113 + } 114 + } 115 + 116 + $add = array_diff($new, $old); 117 + foreach ($add as $phid) { 118 + $owners[$phid] = id(new PhabricatorOwnersOwner()) 119 + ->setPackageID($object->getID()) 120 + ->setUserPHID($phid) 121 + ->save(); 122 + } 123 + 124 + // TODO: Attach owners here 125 + return; 126 + } 127 + 128 + return parent::applyCustomExternalTransaction($object, $xaction); 129 + } 130 + 131 + protected function validateTransaction( 132 + PhabricatorLiskDAO $object, 133 + $type, 134 + array $xactions) { 135 + 136 + $errors = parent::validateTransaction($object, $type, $xactions); 137 + 138 + switch ($type) { 139 + case PhabricatorOwnersPackageTransaction::TYPE_NAME: 140 + $missing = $this->validateIsEmptyTextField( 141 + $object->getName(), 142 + $xactions); 143 + 144 + if ($missing) { 145 + $error = new PhabricatorApplicationTransactionValidationError( 146 + $type, 147 + pht('Required'), 148 + pht('Package name is required.'), 149 + nonempty(last($xactions), null)); 150 + 151 + $error->setIsMissingFieldError(true); 152 + $errors[] = $error; 153 + } 154 + break; 155 + case PhabricatorOwnersPackageTransaction::TYPE_PRIMARY: 156 + $missing = $this->validateIsEmptyTextField( 157 + $object->getPrimaryOwnerPHID(), 158 + $xactions); 159 + 160 + if ($missing) { 161 + $error = new PhabricatorApplicationTransactionValidationError( 162 + $type, 163 + pht('Required'), 164 + pht('Packages must have a primary owner.'), 165 + nonempty(last($xactions), null)); 166 + 167 + $error->setIsMissingFieldError(true); 168 + $errors[] = $error; 169 + } 170 + break; 171 + } 172 + 173 + return $errors; 174 + } 175 + 176 + protected function extractFilePHIDsFromCustomTransaction( 177 + PhabricatorLiskDAO $object, 178 + PhabricatorApplicationTransaction $xaction) { 179 + 180 + switch ($xaction->getTransactionType()) { 181 + case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION: 182 + return array($xaction->getNewValue()); 183 + } 184 + 185 + return parent::extractFilePHIDsFromCustomTransaction($object, $xaction); 186 + } 187 + 188 + protected function shouldSendMail( 189 + PhabricatorLiskDAO $object, 190 + array $xactions) { 191 + return true; 192 + } 193 + 194 + protected function getMailSubjectPrefix() { 195 + return PhabricatorEnv::getEnvConfig('metamta.package.subject-prefix'); 196 + } 197 + 198 + protected function getMailTo(PhabricatorLiskDAO $object) { 199 + return array( 200 + $object->getPrimaryOwnerPHID(), 201 + $this->requireActor()->getPHID(), 202 + ); 203 + } 204 + 205 + protected function getMailCC(PhabricatorLiskDAO $object) { 206 + // TODO: needOwners() this 207 + return mpull($object->loadOwners(), 'getUserPHID'); 208 + } 209 + 210 + protected function buildReplyHandler(PhabricatorLiskDAO $object) { 211 + return id(new OwnersPackageReplyHandler()) 212 + ->setMailReceiver($object); 213 + } 214 + 215 + protected function buildMailTemplate(PhabricatorLiskDAO $object) { 216 + $id = $object->getID(); 217 + $name = $object->getName(); 218 + 219 + return id(new PhabricatorMetaMTAMail()) 220 + ->setSubject($name) 221 + ->addHeader('Thread-Topic', $object->getPHID()); 222 + } 223 + 224 + protected function buildMailBody( 225 + PhabricatorLiskDAO $object, 226 + array $xactions) { 227 + 228 + $body = parent::buildMailBody($object, $xactions); 229 + 230 + $detail_uri = PhabricatorEnv::getProductionURI( 231 + '/owners/package/'.$object->getID().'/'); 232 + 233 + $body->addLinkSection( 234 + pht('PACKAGE DETAIL'), 235 + $detail_uri); 236 + 237 + return $body; 238 + } 239 + 240 + }
+10
src/applications/owners/query/PhabricatorOwnersPackageTransactionQuery.php
··· 1 + <?php 2 + 3 + final class PhabricatorOwnersPackageTransactionQuery 4 + extends PhabricatorApplicationTransactionQuery { 5 + 6 + public function getTemplateApplicationTransaction() { 7 + return new PhabricatorOwnersPackageTransaction(); 8 + } 9 + 10 + }
+44 -2
src/applications/owners/storage/PhabricatorOwnersPackage.php
··· 1 1 <?php 2 2 3 - final class PhabricatorOwnersPackage extends PhabricatorOwnersDAO 4 - implements PhabricatorPolicyInterface { 3 + final class PhabricatorOwnersPackage 4 + extends PhabricatorOwnersDAO 5 + implements 6 + PhabricatorPolicyInterface, 7 + PhabricatorApplicationTransactionInterface { 5 8 6 9 protected $name; 7 10 protected $originalName; 8 11 protected $auditingEnabled; 9 12 protected $description; 10 13 protected $primaryOwnerPHID; 14 + protected $mailKey; 11 15 12 16 private $unsavedOwners = self::ATTACHABLE; 13 17 private $unsavedPaths = self::ATTACHABLE; ··· 15 19 private $oldPrimaryOwnerPHID; 16 20 private $oldAuditingEnabled; 17 21 22 + public static function initializeNewPackage(PhabricatorUser $actor) { 23 + return id(new PhabricatorOwnersPackage()) 24 + ->setAuditingEnabled(0) 25 + ->setPrimaryOwnerPHID($actor->getPHID()); 26 + } 27 + 18 28 public function getCapabilities() { 19 29 return array( 20 30 PhabricatorPolicyCapability::CAN_VIEW, ··· 44 54 'description' => 'text', 45 55 'primaryOwnerPHID' => 'phid?', 46 56 'auditingEnabled' => 'bool', 57 + 'mailKey' => 'bytes20', 47 58 ), 48 59 self::CONFIG_KEY_SCHEMA => array( 49 60 'key_phid' => null, ··· 62 73 public function generatePHID() { 63 74 return PhabricatorPHID::generateNewPHID( 64 75 PhabricatorOwnersPackagePHIDType::TYPECONST); 76 + } 77 + 78 + public function save() { 79 + if (!$this->getMailKey()) { 80 + $this->setMailKey(Filesystem::readRandomCharacters(20)); 81 + } 82 + 83 + return parent::save(); 65 84 } 66 85 67 86 public function attachUnsavedOwners(array $owners) { ··· 269 288 } 270 289 return $result; 271 290 } 291 + 292 + 293 + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ 294 + 295 + 296 + public function getApplicationTransactionEditor() { 297 + return new PhabricatorOwnersPackageTransactionEditor(); 298 + } 299 + 300 + public function getApplicationTransactionObject() { 301 + return $this; 302 + } 303 + 304 + public function getApplicationTransactionTemplate() { 305 + return new PhabricatorOwnersPackageTransaction(); 306 + } 307 + 308 + public function willRenderTimeline( 309 + PhabricatorApplicationTransactionView $timeline, 310 + AphrontRequest $request) { 311 + return $timeline; 312 + } 313 + 272 314 }
+152
src/applications/owners/storage/PhabricatorOwnersPackageTransaction.php
··· 1 + <?php 2 + 3 + final class PhabricatorOwnersPackageTransaction 4 + extends PhabricatorApplicationTransaction { 5 + 6 + const TYPE_NAME = 'owners.name'; 7 + const TYPE_PRIMARY = 'owners.primary'; 8 + const TYPE_OWNERS = 'owners.owners'; 9 + const TYPE_AUDITING = 'owners.auditing'; 10 + const TYPE_DESCRIPTION = 'owners.description'; 11 + 12 + public function getApplicationName() { 13 + return 'owners'; 14 + } 15 + 16 + public function getApplicationTransactionType() { 17 + return PhabricatorOwnersPackagePHIDType::TYPECONST; 18 + } 19 + 20 + public function getRequiredHandlePHIDs() { 21 + $phids = parent::getRequiredHandlePHIDs(); 22 + 23 + $old = $this->getOldValue(); 24 + $new = $this->getNewValue(); 25 + 26 + switch ($this->getTransactionType()) { 27 + case self::TYPE_PRIMARY: 28 + if ($old) { 29 + $phids[] = $old; 30 + } 31 + if ($new) { 32 + $phids[] = $new; 33 + } 34 + break; 35 + case self::TYPE_OWNERS: 36 + $add = array_diff($new, $old); 37 + foreach ($add as $phid) { 38 + $phids[] = $phid; 39 + } 40 + $rem = array_diff($old, $new); 41 + foreach ($rem as $phid) { 42 + $phids[] = $phid; 43 + } 44 + break; 45 + } 46 + 47 + return $phids; 48 + } 49 + 50 + public function shouldHide() { 51 + $old = $this->getOldValue(); 52 + $new = $this->getNewValue(); 53 + 54 + switch ($this->getTransactionType()) { 55 + case self::TYPE_DESCRIPTION: 56 + return ($old === null); 57 + } 58 + } 59 + 60 + public function getTitle() { 61 + $old = $this->getOldValue(); 62 + $new = $this->getNewValue(); 63 + $author_phid = $this->getAuthorPHID(); 64 + 65 + switch ($this->getTransactionType()) { 66 + case self::TYPE_NAME: 67 + if ($old === null) { 68 + return pht( 69 + '%s created this package.', 70 + $this->renderHandleLink($author_phid)); 71 + } else { 72 + return pht( 73 + '%s renamed this package from "%s" to "%s".', 74 + $this->renderHandleLink($author_phid), 75 + $old, 76 + $new); 77 + } 78 + case self::TYPE_PRIMARY: 79 + return pht( 80 + '%s changed the primary owner for this package from %s to %s.', 81 + $this->renderHandleLink($author_phid), 82 + $this->renderHandleLink($old), 83 + $this->renderHandleLink($new)); 84 + case self::TYPE_OWNERS: 85 + $add = array_diff($new, $old); 86 + $rem = array_diff($old, $new); 87 + if ($add && !$rem) { 88 + return pht( 89 + '%s added %s owner(s): %s.', 90 + $this->renderHandleLink($author_phid), 91 + count($add), 92 + $this->renderHandleList($add)); 93 + } else if ($rem && !$add) { 94 + return pht( 95 + '%s removed %s owner(s): %s.', 96 + $this->renderHandleLink($author_phid), 97 + count($rem), 98 + $this->renderHandleList($rem)); 99 + } else { 100 + return pht( 101 + '%s changed %s package owner(s), added %s: %s; removed %s: %s.', 102 + $this->renderHandleLink($author_phid), 103 + count($add) + count($rem), 104 + count($add), 105 + $this->renderHandleList($add), 106 + count($rem), 107 + $this->renderHandleList($rem)); 108 + } 109 + case self::TYPE_AUDITING: 110 + if ($new) { 111 + return pht( 112 + '%s enabled auditing for this package.', 113 + $this->renderHandleLink($author_phid)); 114 + } else { 115 + return pht( 116 + '%s disabled auditing for this package.', 117 + $this->renderHandleLink($author_phid)); 118 + } 119 + case self::TYPE_DESCRIPTION: 120 + return pht( 121 + '%s updated the description for this package.', 122 + $this->renderHandleLink($author_phid)); 123 + } 124 + 125 + return parent::getTitle(); 126 + } 127 + 128 + public function hasChangeDetails() { 129 + switch ($this->getTransactionType()) { 130 + case self::TYPE_DESCRIPTION: 131 + return ($this->getOldValue() !== null); 132 + } 133 + 134 + return parent::hasChangeDetails(); 135 + } 136 + 137 + public function renderChangeDetails(PhabricatorUser $viewer) { 138 + switch ($this->getTransactionType()) { 139 + case self::TYPE_DESCRIPTION: 140 + $old = $this->getOldValue(); 141 + $new = $this->getNewValue(); 142 + 143 + return $this->renderTextCorpusChangeDetails( 144 + $viewer, 145 + $old, 146 + $new); 147 + } 148 + 149 + return parent::renderChangeDetails($viewer); 150 + } 151 + 152 + }
+18
src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php
··· 1078 1078 'Are you absolutely certain you want to destroy these objects?', 1079 1079 ), 1080 1080 1081 + '%s added %s owner(s): %s.' => array( 1082 + array( 1083 + '%s added an owner: %3$s.', 1084 + '%s added owners: %3$s.', 1085 + ), 1086 + ), 1087 + 1088 + '%s removed %s owner(s): %s.' => array( 1089 + array( 1090 + '%s removed an owner: %3$s.', 1091 + '%s removed owners: %3$s.', 1092 + ), 1093 + ), 1094 + 1095 + '%s changed %s package owner(s), added %s: %s; removed %s: %s.' => array( 1096 + '%s changed package owners, added: %4$s; removed: %6$s.', 1097 + ), 1098 + 1081 1099 ); 1082 1100 } 1083 1101