diff --git a/src/applications/herald/query/HeraldRuleQuery.php b/src/applications/herald/query/HeraldRuleQuery.php index 9673bd0810..4fd48d3109 100644 --- a/src/applications/herald/query/HeraldRuleQuery.php +++ b/src/applications/herald/query/HeraldRuleQuery.php @@ -1,284 +1,279 @@ ids = $ids; return $this; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function withAuthorPHIDs(array $author_phids) { $this->authorPHIDs = $author_phids; return $this; } public function withRuleTypes(array $types) { $this->ruleTypes = $types; return $this; } public function withContentTypes(array $types) { $this->contentTypes = $types; return $this; } public function withDisabled($disabled) { $this->disabled = $disabled; return $this; } public function withDatasourceQuery($query) { $this->datasourceQuery = $query; return $this; } public function withTriggerObjectPHIDs(array $phids) { $this->triggerObjectPHIDs = $phids; return $this; } public function needConditionsAndActions($need) { $this->needConditionsAndActions = $need; return $this; } public function needAppliedToPHIDs(array $phids) { $this->needAppliedToPHIDs = $phids; return $this; } public function needValidateAuthors($need) { $this->needValidateAuthors = $need; return $this; } + public function newResultObject() { + return new HeraldRule(); + } + protected function loadPage() { - $table = new HeraldRule(); - $conn_r = $table->establishConnection('r'); - - $data = queryfx_all( - $conn_r, - 'SELECT rule.* FROM %T rule %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - return $table->loadAllFromArray($data); + return $this->loadStandardPage($this->newResultObject()); } protected function willFilterPage(array $rules) { $rule_ids = mpull($rules, 'getID'); // Filter out any rules that have invalid adapters, or have adapters the // viewer isn't permitted to see or use (for example, Differential rules // if the user can't use Differential or Differential is not installed). $types = HeraldAdapter::getEnabledAdapterMap($this->getViewer()); foreach ($rules as $key => $rule) { if (empty($types[$rule->getContentType()])) { $this->didRejectResult($rule); unset($rules[$key]); } } if ($this->needValidateAuthors) { $this->validateRuleAuthors($rules); } if ($this->needConditionsAndActions) { $conditions = id(new HeraldCondition())->loadAllWhere( 'ruleID IN (%Ld)', $rule_ids); $conditions = mgroup($conditions, 'getRuleID'); $actions = id(new HeraldActionRecord())->loadAllWhere( 'ruleID IN (%Ld)', $rule_ids); $actions = mgroup($actions, 'getRuleID'); foreach ($rules as $rule) { $rule->attachActions(idx($actions, $rule->getID(), array())); $rule->attachConditions(idx($conditions, $rule->getID(), array())); } } if ($this->needAppliedToPHIDs) { $conn_r = id(new HeraldRule())->establishConnection('r'); $applied = queryfx_all( $conn_r, 'SELECT * FROM %T WHERE ruleID IN (%Ld) AND phid IN (%Ls)', HeraldRule::TABLE_RULE_APPLIED, $rule_ids, $this->needAppliedToPHIDs); $map = array(); foreach ($applied as $row) { $map[$row['ruleID']][$row['phid']] = true; } foreach ($rules as $rule) { foreach ($this->needAppliedToPHIDs as $phid) { $rule->setRuleApplied( $phid, isset($map[$rule->getID()][$phid])); } } } $object_phids = array(); foreach ($rules as $rule) { if ($rule->isObjectRule()) { $object_phids[] = $rule->getTriggerObjectPHID(); } } if ($object_phids) { $objects = id(new PhabricatorObjectQuery()) ->setParentQuery($this) ->setViewer($this->getViewer()) ->withPHIDs($object_phids) ->execute(); $objects = mpull($objects, null, 'getPHID'); } else { $objects = array(); } foreach ($rules as $key => $rule) { if ($rule->isObjectRule()) { $object = idx($objects, $rule->getTriggerObjectPHID()); if (!$object) { unset($rules[$key]); continue; } $rule->attachTriggerObject($object); } } return $rules; } - protected function buildWhereClause(AphrontDatabaseConnection $conn) { - $where = array(); + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); - if ($this->ids) { + if ($this->ids !== null) { $where[] = qsprintf( $conn, 'rule.id IN (%Ld)', $this->ids); } - if ($this->phids) { + if ($this->phids !== null) { $where[] = qsprintf( $conn, 'rule.phid IN (%Ls)', $this->phids); } - if ($this->authorPHIDs) { + if ($this->authorPHIDs !== null) { $where[] = qsprintf( $conn, 'rule.authorPHID IN (%Ls)', $this->authorPHIDs); } - if ($this->ruleTypes) { + if ($this->ruleTypes !== null) { $where[] = qsprintf( $conn, 'rule.ruleType IN (%Ls)', $this->ruleTypes); } - if ($this->contentTypes) { + if ($this->contentTypes !== null) { $where[] = qsprintf( $conn, 'rule.contentType IN (%Ls)', $this->contentTypes); } if ($this->disabled !== null) { $where[] = qsprintf( $conn, 'rule.isDisabled = %d', (int)$this->disabled); } - if ($this->datasourceQuery) { + if ($this->datasourceQuery !== null) { $where[] = qsprintf( $conn, 'rule.name LIKE %>', $this->datasourceQuery); } - if ($this->triggerObjectPHIDs) { + if ($this->triggerObjectPHIDs !== null) { $where[] = qsprintf( $conn, 'rule.triggerObjectPHID IN (%Ls)', $this->triggerObjectPHIDs); } - $where[] = $this->buildPagingClause($conn); - - return $this->formatWhereClause($conn, $where); + return $where; } private function validateRuleAuthors(array $rules) { // "Global" and "Object" rules always have valid authors. foreach ($rules as $key => $rule) { if ($rule->isGlobalRule() || $rule->isObjectRule()) { $rule->attachValidAuthor(true); unset($rules[$key]); continue; } } if (!$rules) { return; } // For personal rules, the author needs to exist and not be disabled. $user_phids = mpull($rules, 'getAuthorPHID'); $users = id(new PhabricatorPeopleQuery()) ->setViewer($this->getViewer()) ->withPHIDs($user_phids) ->execute(); $users = mpull($users, null, 'getPHID'); foreach ($rules as $key => $rule) { $author_phid = $rule->getAuthorPHID(); if (empty($users[$author_phid])) { $rule->attachValidAuthor(false); continue; } if (!$users[$author_phid]->isUserActivated()) { $rule->attachValidAuthor(false); continue; } $rule->attachValidAuthor(true); $rule->attachAuthor($users[$author_phid]); } } public function getQueryApplicationClass() { return 'PhabricatorHeraldApplication'; } + protected function getPrimaryTableAlias() { + return 'rule'; + } + } diff --git a/src/applications/herald/query/HeraldRuleSearchEngine.php b/src/applications/herald/query/HeraldRuleSearchEngine.php index 3b8196c13a..3a6da6145a 100644 --- a/src/applications/herald/query/HeraldRuleSearchEngine.php +++ b/src/applications/herald/query/HeraldRuleSearchEngine.php @@ -1,234 +1,184 @@ setParameter( - 'authorPHIDs', - $this->readUsersFromRequest($request, 'authors')); + protected function buildCustomSearchFields() { + $viewer = $this->requireViewer(); - $saved->setParameter('contentType', $request->getStr('contentType')); - $saved->setParameter('ruleType', $request->getStr('ruleType')); - $saved->setParameter( - 'disabled', - $this->readBoolFromRequest($request, 'disabled')); + $rule_types = HeraldRuleTypeConfig::getRuleTypeMap(); + $content_types = HeraldAdapter::getEnabledAdapterMap($viewer); - return $saved; + return array( + id(new PhabricatorUsersSearchField()) + ->setLabel(pht('Authors')) + ->setKey('authorPHIDs') + ->setAliases(array('author', 'authors', 'authorPHID')) + ->setDescription( + pht('Search for rules with given authors.')), + id(new PhabricatorSearchCheckboxesField()) + ->setKey('ruleTypes') + ->setAliases(array('ruleType')) + ->setLabel(pht('Rule Type')) + ->setDescription( + pht('Search for rules of given types.')) + ->setOptions($rule_types), + id(new PhabricatorSearchCheckboxesField()) + ->setKey('contentTypes') + ->setLabel(pht('Content Type')) + ->setDescription( + pht('Search for rules affecting given types of content.')) + ->setOptions($content_types), + id(new PhabricatorSearchThreeStateField()) + ->setLabel(pht('Rule Status')) + ->setKey('disabled') + ->setOptions( + pht('(Show All)'), + pht('Show Only Disabled Rules'), + pht('Show Only Enabled Rules')), + ); } - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { - $query = id(new HeraldRuleQuery()); + protected function buildQueryFromParameters(array $map) { + $query = $this->newQuery(); - $author_phids = $saved->getParameter('authorPHIDs'); - if ($author_phids) { - $query->withAuthorPHIDs($author_phids); + if ($map['authorPHIDs']) { + $query->withAuthorPHIDs($map['authorPHIDs']); } - $content_type = $saved->getParameter('contentType'); - $content_type = idx($this->getContentTypeValues(), $content_type); - if ($content_type) { - $query->withContentTypes(array($content_type)); + if ($map['contentTypes']) { + $query->withContentTypes($map['contentTypes']); } - $rule_type = $saved->getParameter('ruleType'); - $rule_type = idx($this->getRuleTypeValues(), $rule_type); - if ($rule_type) { - $query->withRuleTypes(array($rule_type)); + if ($map['ruleTypes']) { + $query->withRuleTypes($map['ruleTypes']); } - $disabled = $saved->getParameter('disabled'); - if ($disabled !== null) { - $query->withDisabled($disabled); + if ($map['disabled'] !== null) { + $query->withDisabled($map['disabled']); } return $query; } - public function buildSearchForm( - AphrontFormView $form, - PhabricatorSavedQuery $saved_query) { - - $author_phids = $saved_query->getParameter('authorPHIDs', array()); - $content_type = $saved_query->getParameter('contentType'); - $rule_type = $saved_query->getParameter('ruleType'); - - $form - ->appendControl( - id(new AphrontFormTokenizerControl()) - ->setDatasource(new PhabricatorPeopleDatasource()) - ->setName('authors') - ->setLabel(pht('Authors')) - ->setValue($author_phids)) - ->appendChild( - id(new AphrontFormSelectControl()) - ->setName('contentType') - ->setLabel(pht('Content Type')) - ->setValue($content_type) - ->setOptions($this->getContentTypeOptions())) - ->appendChild( - id(new AphrontFormSelectControl()) - ->setName('ruleType') - ->setLabel(pht('Rule Type')) - ->setValue($rule_type) - ->setOptions($this->getRuleTypeOptions())) - ->appendChild( - id(new AphrontFormSelectControl()) - ->setName('disabled') - ->setLabel(pht('Rule Status')) - ->setValue($this->getBoolFromQuery($saved_query, 'disabled')) - ->setOptions( - array( - '' => pht('Show Enabled and Disabled Rules'), - 'false' => pht('Show Only Enabled Rules'), - 'true' => pht('Show Only Disabled Rules'), - ))); - } - protected function getURI($path) { return '/herald/'.$path; } protected function getBuiltinQueryNames() { $names = array(); if ($this->requireViewer()->isLoggedIn()) { $names['authored'] = pht('Authored'); } $names['active'] = pht('Active'); $names['all'] = pht('All'); return $names; } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); $viewer_phid = $this->requireViewer()->getPHID(); switch ($query_key) { case 'all': return $query; case 'active': return $query->setParameter('disabled', false); case 'authored': return $query ->setParameter('authorPHIDs', array($viewer_phid)) ->setParameter('disabled', false); } return parent::buildSavedQueryFromBuiltin($query_key); } - private function getContentTypeOptions() { - return array( - '' => pht('(All Content Types)'), - ) + HeraldAdapter::getEnabledAdapterMap($this->requireViewer()); - } - - private function getContentTypeValues() { - return array_fuse( - array_keys( - HeraldAdapter::getEnabledAdapterMap($this->requireViewer()))); - } - - private function getRuleTypeOptions() { - return array( - '' => pht('(All Rule Types)'), - ) + HeraldRuleTypeConfig::getRuleTypeMap(); - } - - private function getRuleTypeValues() { - return array_fuse(array_keys(HeraldRuleTypeConfig::getRuleTypeMap())); - } - - protected function getRequiredHandlePHIDsForResultList( - array $rules, - PhabricatorSavedQuery $query) { - - return mpull($rules, 'getAuthorPHID'); - } - protected function renderResultList( array $rules, PhabricatorSavedQuery $query, array $handles) { assert_instances_of($rules, 'HeraldRule'); $viewer = $this->requireViewer(); + $handles = $viewer->loadHandles(mpull($rules, 'getAuthorPHID')); $content_type_map = HeraldAdapter::getEnabledAdapterMap($viewer); $list = id(new PHUIObjectItemListView()) ->setUser($viewer); foreach ($rules as $rule) { $monogram = $rule->getMonogram(); $item = id(new PHUIObjectItemView()) ->setObjectName($monogram) ->setHeader($rule->getName()) ->setHref("/{$monogram}"); if ($rule->isPersonalRule()) { $item->addIcon('fa-user', pht('Personal Rule')); $item->addByline( pht( 'Authored by %s', $handles[$rule->getAuthorPHID()]->renderLink())); } else if ($rule->isObjectRule()) { $item->addIcon('fa-briefcase', pht('Object Rule')); } else { $item->addIcon('fa-globe', pht('Global Rule')); } if ($rule->getIsDisabled()) { $item->setDisabled(true); $item->addIcon('fa-lock grey', pht('Disabled')); } $content_type_name = idx($content_type_map, $rule->getContentType()); $item->addAttribute(pht('Affects: %s', $content_type_name)); $list->addItem($item); } $result = new PhabricatorApplicationSearchResultView(); $result->setObjectList($list); $result->setNoDataString(pht('No rules found.')); return $result; } protected function getNewUserBody() { $create_button = id(new PHUIButtonView()) ->setTag('a') ->setText(pht('Create Herald Rule')) ->setHref('/herald/create/') ->setColor(PHUIButtonView::GREEN); $icon = $this->getApplication()->getIcon(); $app_name = $this->getApplication()->getName(); $view = id(new PHUIBigInfoView()) ->setIcon($icon) ->setTitle(pht('Welcome to %s', $app_name)) ->setDescription( pht('A flexible rules engine that can notify and act on '. 'other actions such as tasks, diffs, and commits.')) ->addAction($create_button); return $view; } }