@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 upstream/main 340 lines 8.5 kB view raw
1<?php 2 3/** 4 * @extends PhabricatorCursorPagedPolicyAwareQuery<HeraldRule> 5 */ 6final class HeraldRuleQuery extends PhabricatorCursorPagedPolicyAwareQuery { 7 8 private $ids; 9 private $phids; 10 private $authorPHIDs; 11 private $ruleTypes; 12 private $contentTypes; 13 private $disabled; 14 private $active; 15 private $datasourceQuery; 16 private $triggerObjectPHIDs; 17 private $affectedObjectPHIDs; 18 19 private $needConditionsAndActions; 20 private $needAppliedToPHIDs; 21 private $needValidateAuthors; 22 23 public function withIDs(array $ids) { 24 $this->ids = $ids; 25 return $this; 26 } 27 28 public function withPHIDs(array $phids) { 29 $this->phids = $phids; 30 return $this; 31 } 32 33 public function withAuthorPHIDs(array $author_phids) { 34 $this->authorPHIDs = $author_phids; 35 return $this; 36 } 37 38 public function withRuleTypes(array $types) { 39 $this->ruleTypes = $types; 40 return $this; 41 } 42 43 public function withContentTypes(array $types) { 44 $this->contentTypes = $types; 45 return $this; 46 } 47 48 public function withDisabled($disabled) { 49 $this->disabled = $disabled; 50 return $this; 51 } 52 53 public function withActive($active) { 54 $this->active = $active; 55 return $this; 56 } 57 58 public function withDatasourceQuery($query) { 59 $this->datasourceQuery = $query; 60 return $this; 61 } 62 63 public function withTriggerObjectPHIDs(array $phids) { 64 $this->triggerObjectPHIDs = $phids; 65 return $this; 66 } 67 68 public function withAffectedObjectPHIDs(array $phids) { 69 $this->affectedObjectPHIDs = $phids; 70 return $this; 71 } 72 73 public function needConditionsAndActions($need) { 74 $this->needConditionsAndActions = $need; 75 return $this; 76 } 77 78 public function needAppliedToPHIDs(array $phids) { 79 $this->needAppliedToPHIDs = $phids; 80 return $this; 81 } 82 83 public function needValidateAuthors($need) { 84 $this->needValidateAuthors = $need; 85 return $this; 86 } 87 88 public function newResultObject() { 89 return new HeraldRule(); 90 } 91 92 protected function willFilterPage(array $rules) { 93 $rule_ids = mpull($rules, 'getID'); 94 95 // Filter out any rules that have invalid adapters, or have adapters the 96 // viewer isn't permitted to see or use (for example, Differential rules 97 // if the user can't use Differential or Differential is disabled). 98 $types = HeraldAdapter::getEnabledAdapterMap($this->getViewer()); 99 foreach ($rules as $key => $rule) { 100 if (empty($types[$rule->getContentType()])) { 101 $this->didRejectResult($rule); 102 unset($rules[$key]); 103 } 104 } 105 106 if ($this->needValidateAuthors || ($this->active !== null)) { 107 $this->validateRuleAuthors($rules); 108 } 109 110 if ($this->active !== null) { 111 $need_active = (bool)$this->active; 112 foreach ($rules as $key => $rule) { 113 if ($rule->getIsDisabled()) { 114 $is_active = false; 115 } else if (!$rule->hasValidAuthor()) { 116 $is_active = false; 117 } else { 118 $is_active = true; 119 } 120 121 if ($is_active != $need_active) { 122 unset($rules[$key]); 123 } 124 } 125 } 126 127 if (!$rules) { 128 return array(); 129 } 130 131 if ($this->needConditionsAndActions) { 132 $conditions = id(new HeraldCondition())->loadAllWhere( 133 'ruleID IN (%Ld)', 134 $rule_ids); 135 $conditions = mgroup($conditions, 'getRuleID'); 136 137 $actions = id(new HeraldActionRecord())->loadAllWhere( 138 'ruleID IN (%Ld)', 139 $rule_ids); 140 $actions = mgroup($actions, 'getRuleID'); 141 142 foreach ($rules as $rule) { 143 $rule->attachActions(idx($actions, $rule->getID(), array())); 144 $rule->attachConditions(idx($conditions, $rule->getID(), array())); 145 } 146 } 147 148 if ($this->needAppliedToPHIDs) { 149 $conn_r = id(new HeraldRule())->establishConnection('r'); 150 $applied = queryfx_all( 151 $conn_r, 152 'SELECT * FROM %T WHERE ruleID IN (%Ld) AND phid IN (%Ls)', 153 HeraldRule::TABLE_RULE_APPLIED, 154 $rule_ids, 155 $this->needAppliedToPHIDs); 156 157 $map = array(); 158 foreach ($applied as $row) { 159 $map[$row['ruleID']][$row['phid']] = true; 160 } 161 162 foreach ($rules as $rule) { 163 foreach ($this->needAppliedToPHIDs as $phid) { 164 $rule->setRuleApplied( 165 $phid, 166 isset($map[$rule->getID()][$phid])); 167 } 168 } 169 } 170 171 $object_phids = array(); 172 foreach ($rules as $rule) { 173 if ($rule->isObjectRule()) { 174 $object_phids[] = $rule->getTriggerObjectPHID(); 175 } 176 } 177 178 if ($object_phids) { 179 $objects = id(new PhabricatorObjectQuery()) 180 ->setParentQuery($this) 181 ->setViewer($this->getViewer()) 182 ->withPHIDs($object_phids) 183 ->execute(); 184 $objects = mpull($objects, null, 'getPHID'); 185 } else { 186 $objects = array(); 187 } 188 189 foreach ($rules as $key => $rule) { 190 if ($rule->isObjectRule()) { 191 $object = idx($objects, $rule->getTriggerObjectPHID()); 192 if (!$object) { 193 unset($rules[$key]); 194 continue; 195 } 196 $rule->attachTriggerObject($object); 197 } 198 } 199 200 return $rules; 201 } 202 203 protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { 204 $where = parent::buildWhereClauseParts($conn); 205 206 if ($this->ids !== null) { 207 $where[] = qsprintf( 208 $conn, 209 'rule.id IN (%Ld)', 210 $this->ids); 211 } 212 213 if ($this->phids !== null) { 214 $where[] = qsprintf( 215 $conn, 216 'rule.phid IN (%Ls)', 217 $this->phids); 218 } 219 220 if ($this->authorPHIDs !== null) { 221 $where[] = qsprintf( 222 $conn, 223 'rule.authorPHID IN (%Ls)', 224 $this->authorPHIDs); 225 } 226 227 if ($this->ruleTypes !== null) { 228 $where[] = qsprintf( 229 $conn, 230 'rule.ruleType IN (%Ls)', 231 $this->ruleTypes); 232 } 233 234 if ($this->contentTypes !== null) { 235 $where[] = qsprintf( 236 $conn, 237 'rule.contentType IN (%Ls)', 238 $this->contentTypes); 239 } 240 241 if ($this->disabled !== null) { 242 $where[] = qsprintf( 243 $conn, 244 'rule.isDisabled = %d', 245 (int)$this->disabled); 246 } 247 248 if ($this->active !== null) { 249 $where[] = qsprintf( 250 $conn, 251 'rule.isDisabled = %d', 252 (int)(!$this->active)); 253 } 254 255 if ($this->datasourceQuery !== null) { 256 $where[] = qsprintf( 257 $conn, 258 'rule.name LIKE %>', 259 $this->datasourceQuery); 260 } 261 262 if ($this->triggerObjectPHIDs !== null) { 263 $where[] = qsprintf( 264 $conn, 265 'rule.triggerObjectPHID IN (%Ls)', 266 $this->triggerObjectPHIDs); 267 } 268 269 if ($this->affectedObjectPHIDs !== null) { 270 $where[] = qsprintf( 271 $conn, 272 'edge_affects.dst IN (%Ls)', 273 $this->affectedObjectPHIDs); 274 } 275 276 return $where; 277 } 278 279 protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { 280 $joins = parent::buildJoinClauseParts($conn); 281 282 if ($this->affectedObjectPHIDs !== null) { 283 $joins[] = qsprintf( 284 $conn, 285 'JOIN %T edge_affects ON rule.phid = edge_affects.src 286 AND edge_affects.type = %d', 287 PhabricatorEdgeConfig::TABLE_NAME_EDGE, 288 HeraldRuleActionAffectsObjectEdgeType::EDGECONST); 289 } 290 291 return $joins; 292 } 293 294 private function validateRuleAuthors(array $rules) { 295 // "Global" and "Object" rules always have valid authors. 296 foreach ($rules as $key => $rule) { 297 if ($rule->isGlobalRule() || $rule->isObjectRule()) { 298 $rule->attachValidAuthor(true); 299 unset($rules[$key]); 300 continue; 301 } 302 } 303 304 if (!$rules) { 305 return; 306 } 307 308 // For personal rules, the author needs to exist and not be disabled. 309 $user_phids = mpull($rules, 'getAuthorPHID'); 310 $users = id(new PhabricatorPeopleQuery()) 311 ->setViewer($this->getViewer()) 312 ->withPHIDs($user_phids) 313 ->execute(); 314 $users = mpull($users, null, 'getPHID'); 315 316 foreach ($rules as $key => $rule) { 317 $author_phid = $rule->getAuthorPHID(); 318 if (empty($users[$author_phid])) { 319 $rule->attachValidAuthor(false); 320 continue; 321 } 322 if (!$users[$author_phid]->isUserActivated()) { 323 $rule->attachValidAuthor(false); 324 continue; 325 } 326 327 $rule->attachValidAuthor(true); 328 $rule->attachAuthor($users[$author_phid]); 329 } 330 } 331 332 public function getQueryApplicationClass() { 333 return PhabricatorHeraldApplication::class; 334 } 335 336 protected function getPrimaryTableAlias() { 337 return 'rule'; 338 } 339 340}