Path: blob/master/src/applications/auth/query/PhabricatorExternalAccountQuery.php
12256 views
<?php12/**3* NOTE: When loading ExternalAccounts for use in an authentication context4* (that is, you're going to act as the account or link identities or anything5* like that) you should require CAN_EDIT capability even if you aren't actually6* editing the ExternalAccount.7*8* ExternalAccounts have a permissive CAN_VIEW policy (like users) because they9* interact directly with objects and can leave comments, sign documents, etc.10* However, CAN_EDIT is restricted to users who own the accounts.11*/12final class PhabricatorExternalAccountQuery13extends PhabricatorCursorPagedPolicyAwareQuery {1415private $ids;16private $phids;17private $userPHIDs;18private $needImages;19private $accountSecrets;20private $providerConfigPHIDs;21private $needAccountIdentifiers;22private $rawAccountIdentifiers;2324public function withUserPHIDs(array $user_phids) {25$this->userPHIDs = $user_phids;26return $this;27}2829public function withPHIDs(array $phids) {30$this->phids = $phids;31return $this;32}3334public function withIDs($ids) {35$this->ids = $ids;36return $this;37}3839public function withAccountSecrets(array $secrets) {40$this->accountSecrets = $secrets;41return $this;42}4344public function needImages($need) {45$this->needImages = $need;46return $this;47}4849public function needAccountIdentifiers($need) {50$this->needAccountIdentifiers = $need;51return $this;52}5354public function withProviderConfigPHIDs(array $phids) {55$this->providerConfigPHIDs = $phids;56return $this;57}5859public function withRawAccountIdentifiers(array $identifiers) {60$this->rawAccountIdentifiers = $identifiers;61return $this;62}6364public function newResultObject() {65return new PhabricatorExternalAccount();66}6768protected function willFilterPage(array $accounts) {69$viewer = $this->getViewer();7071$configs = id(new PhabricatorAuthProviderConfigQuery())72->setViewer($viewer)73->withPHIDs(mpull($accounts, 'getProviderConfigPHID'))74->execute();75$configs = mpull($configs, null, 'getPHID');7677foreach ($accounts as $key => $account) {78$config_phid = $account->getProviderConfigPHID();79$config = idx($configs, $config_phid);8081if (!$config) {82unset($accounts[$key]);83continue;84}8586$account->attachProviderConfig($config);87}8889if ($this->needImages) {90$file_phids = mpull($accounts, 'getProfileImagePHID');91$file_phids = array_filter($file_phids);9293if ($file_phids) {94// NOTE: We use the omnipotent viewer here because these files are95// usually created during registration and can't be associated with96// the correct policies, since the relevant user account does not exist97// yet. In effect, if you can see an ExternalAccount, you can see its98// profile image.99$files = id(new PhabricatorFileQuery())100->setViewer(PhabricatorUser::getOmnipotentUser())101->withPHIDs($file_phids)102->execute();103$files = mpull($files, null, 'getPHID');104} else {105$files = array();106}107108$default_file = null;109foreach ($accounts as $account) {110$image_phid = $account->getProfileImagePHID();111if ($image_phid && isset($files[$image_phid])) {112$account->attachProfileImageFile($files[$image_phid]);113} else {114if ($default_file === null) {115$default_file = PhabricatorFile::loadBuiltin(116$this->getViewer(),117'profile.png');118}119$account->attachProfileImageFile($default_file);120}121}122}123124if ($this->needAccountIdentifiers) {125$account_phids = mpull($accounts, 'getPHID');126127$identifiers = id(new PhabricatorExternalAccountIdentifierQuery())128->setViewer($viewer)129->setParentQuery($this)130->withExternalAccountPHIDs($account_phids)131->execute();132133$identifiers = mgroup($identifiers, 'getExternalAccountPHID');134foreach ($accounts as $account) {135$account_phid = $account->getPHID();136$account_identifiers = idx($identifiers, $account_phid, array());137$account->attachAccountIdentifiers($account_identifiers);138}139}140141return $accounts;142}143144protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {145$where = parent::buildWhereClauseParts($conn);146147if ($this->ids !== null) {148$where[] = qsprintf(149$conn,150'account.id IN (%Ld)',151$this->ids);152}153154if ($this->phids !== null) {155$where[] = qsprintf(156$conn,157'account.phid IN (%Ls)',158$this->phids);159}160161if ($this->userPHIDs !== null) {162$where[] = qsprintf(163$conn,164'account.userPHID IN (%Ls)',165$this->userPHIDs);166}167168if ($this->accountSecrets !== null) {169$where[] = qsprintf(170$conn,171'account.accountSecret IN (%Ls)',172$this->accountSecrets);173}174175if ($this->providerConfigPHIDs !== null) {176$where[] = qsprintf(177$conn,178'account.providerConfigPHID IN (%Ls)',179$this->providerConfigPHIDs);180181// If we have a list of ProviderConfig PHIDs and are joining the182// identifiers table, also include the list as an additional constraint183// on the identifiers table.184185// This does not change the query results (an Account and its186// Identifiers always have the same ProviderConfig PHID) but it allows187// us to use keys on the Identifier table more efficiently.188189if ($this->shouldJoinIdentifiersTable()) {190$where[] = qsprintf(191$conn,192'identifier.providerConfigPHID IN (%Ls)',193$this->providerConfigPHIDs);194}195}196197if ($this->rawAccountIdentifiers !== null) {198$hashes = array();199200foreach ($this->rawAccountIdentifiers as $raw_identifier) {201$hashes[] = PhabricatorHash::digestForIndex($raw_identifier);202}203204$where[] = qsprintf(205$conn,206'identifier.identifierHash IN (%Ls)',207$hashes);208}209210return $where;211}212213protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {214$joins = parent::buildJoinClauseParts($conn);215216if ($this->shouldJoinIdentifiersTable()) {217$joins[] = qsprintf(218$conn,219'JOIN %R identifier ON account.phid = identifier.externalAccountPHID',220new PhabricatorExternalAccountIdentifier());221}222223return $joins;224}225226protected function shouldJoinIdentifiersTable() {227return ($this->rawAccountIdentifiers !== null);228}229230protected function shouldGroupQueryResultRows() {231if ($this->shouldJoinIdentifiersTable()) {232return true;233}234235return parent::shouldGroupQueryResultRows();236}237238protected function getPrimaryTableAlias() {239return 'account';240}241242public function getQueryApplicationClass() {243return 'PhabricatorPeopleApplication';244}245246}247248249