@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
at recaptime-dev/main 241 lines 6.4 kB view raw
1<?php 2 3final class DiffusionCommitAuditorsTransaction 4 extends DiffusionCommitTransactionType { 5 6 const TRANSACTIONTYPE = 'diffusion.commit.auditors'; 7 8 public function generateOldValue($object) { 9 $auditors = $object->getAudits(); 10 return mpull($auditors, 'getAuditStatus', 'getAuditorPHID'); 11 } 12 13 public function generateNewValue($object, $value) { 14 $actor = $this->getActor(); 15 16 $auditors = $this->generateOldValue($object); 17 $old_auditors = $auditors; 18 19 $request_status = PhabricatorAuditRequestStatus::AUDIT_REQUESTED; 20 21 $rem = idx($value, '-', array()); 22 foreach ($rem as $phid) { 23 unset($auditors[$phid]); 24 } 25 26 $add = idx($value, '+', array()); 27 $add_map = array(); 28 foreach ($add as $phid) { 29 $add_map[$phid] = $request_status; 30 } 31 32 $set = idx($value, '=', null); 33 if ($set !== null) { 34 foreach ($set as $phid) { 35 $add_map[$phid] = $request_status; 36 } 37 38 $auditors = array(); 39 } 40 41 foreach ($add_map as $phid => $new_status) { 42 $old_status = idx($old_auditors, $phid); 43 44 if ($old_status) { 45 $auditors[$phid] = $old_status; 46 continue; 47 } 48 49 $auditors[$phid] = $new_status; 50 } 51 52 return $auditors; 53 } 54 55 public function getTransactionHasEffect($object, $old, $new) { 56 ksort($old); 57 ksort($new); 58 return ($old !== $new); 59 } 60 61 public function mergeTransactions( 62 $object, 63 PhabricatorApplicationTransaction $u, 64 PhabricatorApplicationTransaction $v) { 65 66 $u_new = $u->getNewValue(); 67 $v_new = $v->getNewValue(); 68 69 $result = $v_new; 70 foreach (array('-', '+') as $key) { 71 $u_value = idx($u_new, $key, array()); 72 $v_value = idx($v_new, $key, array()); 73 74 $merged = $u_value + $v_value; 75 76 if ($merged) { 77 $result[$key] = $merged; 78 } 79 } 80 81 $u->setNewValue($result); 82 83 return $u; 84 } 85 86 public function applyExternalEffects($object, $value) { 87 $src_phid = $object->getPHID(); 88 89 $old = $this->generateOldValue($object); 90 $new = $value; 91 92 $auditors = $object->getAudits(); 93 $auditors = mpull($auditors, null, 'getAuditorPHID'); 94 95 $rem = array_diff_key($old, $new); 96 foreach ($rem as $phid => $status) { 97 $auditor = idx($auditors, $phid); 98 if ($auditor) { 99 $auditor->delete(); 100 } 101 } 102 103 $this->updateAudits($object, $new); 104 } 105 106 public function getTitle() { 107 $old = $this->getOldValue(); 108 $new = $this->getNewValue(); 109 110 $rem = array_diff_key($old, $new); 111 $add = array_diff_key($new, $old); 112 $rem_phids = array_keys($rem); 113 $add_phids = array_keys($add); 114 $total_count = count($rem) + count($add); 115 116 if ($rem && $add) { 117 return pht( 118 '%s edited %s auditor(s), removed %s: %s; added %s: %s.', 119 $this->renderAuthor(), 120 new PhutilNumber($total_count), 121 phutil_count($rem_phids), 122 $this->renderHandleList($rem_phids), 123 phutil_count($add_phids), 124 $this->renderHandleList($add_phids)); 125 } else if ($add) { 126 return pht( 127 '%s added %s auditor(s): %s.', 128 $this->renderAuthor(), 129 phutil_count($add_phids), 130 $this->renderHandleList($add_phids)); 131 } else { 132 return pht( 133 '%s removed %s auditor(s): %s.', 134 $this->renderAuthor(), 135 phutil_count($rem_phids), 136 $this->renderHandleList($rem_phids)); 137 } 138 } 139 140 public function getTitleForFeed() { 141 $old = $this->getOldValue(); 142 $new = $this->getNewValue(); 143 144 $rem = array_diff_key($old, $new); 145 $add = array_diff_key($new, $old); 146 $rem_phids = array_keys($rem); 147 $add_phids = array_keys($add); 148 $total_count = count($rem) + count($add); 149 150 if ($rem && $add) { 151 return pht( 152 '%s edited %s auditor(s) for %s, removed %s: %s; added %s: %s.', 153 $this->renderAuthor(), 154 new PhutilNumber($total_count), 155 $this->renderObject(), 156 phutil_count($rem_phids), 157 $this->renderHandleList($rem_phids), 158 phutil_count($add_phids), 159 $this->renderHandleList($add_phids)); 160 } else if ($add) { 161 return pht( 162 '%s added %s auditor(s) for %s: %s.', 163 $this->renderAuthor(), 164 phutil_count($add_phids), 165 $this->renderObject(), 166 $this->renderHandleList($add_phids)); 167 } else { 168 return pht( 169 '%s removed %s auditor(s) for %s: %s.', 170 $this->renderAuthor(), 171 phutil_count($rem_phids), 172 $this->renderObject(), 173 $this->renderHandleList($rem_phids)); 174 } 175 } 176 177 public function validateTransactions($object, array $xactions) { 178 $actor = $this->getActor(); 179 $errors = array(); 180 181 if (!$xactions) { 182 return $errors; 183 } 184 185 $author_phid = $object->getEffectiveAuthorPHID(); 186 $can_author_close_key = 'audit.can-author-close-audit'; 187 $can_author_close = PhabricatorEnv::getEnvConfig($can_author_close_key); 188 189 $old = $this->generateOldValue($object); 190 foreach ($xactions as $xaction) { 191 $new = $this->generateNewValue($object, $xaction->getNewValue()); 192 193 $add = array_diff_key($new, $old); 194 if (!$add) { 195 continue; 196 } 197 198 $objects = id(new PhabricatorObjectQuery()) 199 ->setViewer($actor) 200 ->withPHIDs(array_keys($add)) 201 ->execute(); 202 $objects = mpull($objects, null, 'getPHID'); 203 204 foreach ($add as $phid => $status) { 205 if (!isset($objects[$phid])) { 206 $errors[] = $this->newInvalidError( 207 pht( 208 'Auditor "%s" is not a valid object.', 209 $phid), 210 $xaction); 211 continue; 212 } 213 214 switch (phid_get_type($phid)) { 215 case PhabricatorPeopleUserPHIDType::TYPECONST: 216 case PhabricatorOwnersPackagePHIDType::TYPECONST: 217 case PhabricatorProjectProjectPHIDType::TYPECONST: 218 break; 219 default: 220 $errors[] = $this->newInvalidError( 221 pht( 222 'Auditor "%s" must be a user, a package, or a project.', 223 $phid), 224 $xaction); 225 continue 2; 226 } 227 228 $is_self = ($phid === $author_phid); 229 if ($is_self && !$can_author_close) { 230 $errors[] = $this->newInvalidError( 231 pht('The author of a commit can not be an auditor.'), 232 $xaction); 233 continue; 234 } 235 } 236 } 237 238 return $errors; 239 } 240 241}