public function renderContextualDescription(PhabricatorConfigOption $option, AphrontRequest $request)
 {
     switch ($option->getKey()) {
         case 'asana.workspace-id':
             break;
         case 'asana.project-ids':
             return $this->renderContextualProjectDescription($option, $request);
         default:
             return parent::renderContextualDescription($option, $request);
     }
     $viewer = $request->getUser();
     $provider = PhabricatorAsanaAuthProvider::getAsanaProvider();
     if (!$provider) {
         return null;
     }
     $account = id(new PhabricatorExternalAccountQuery())->setViewer($viewer)->withUserPHIDs(array($viewer->getPHID()))->withAccountTypes(array($provider->getProviderType()))->withAccountDomains(array($provider->getProviderDomain()))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
     if (!$account) {
         return null;
     }
     $token = $provider->getOAuthAccessToken($account);
     if (!$token) {
         return null;
     }
     try {
         $workspaces = id(new PhutilAsanaFuture())->setAccessToken($token)->setRawAsanaQuery('workspaces')->resolve();
     } catch (Exception $ex) {
         return null;
     }
     if (!$workspaces) {
         return null;
     }
     $out = array();
     $out[] = pht('| Workspace ID | Workspace Name |');
     $out[] = '| ------------ | -------------- |';
     foreach ($workspaces as $workspace) {
         $out[] = sprintf('| `%s` | `%s` |', $workspace['id'], $workspace['name']);
     }
     $out = implode("\n", $out);
     $out = pht("The Asana Workspaces your linked account has access to are:\n\n%s", $out);
     return PhabricatorMarkupEngine::renderOneObject(id(new PhabricatorMarkupOneOff())->setContent($out), 'default', $viewer);
 }
 public function pullRefs(array $refs)
 {
     $id_map = mpull($refs, 'getObjectID', 'getObjectKey');
     $viewer = $this->getViewer();
     $provider = PhabricatorAsanaAuthProvider::getAsanaProvider();
     if (!$provider) {
         return;
     }
     $accounts = id(new PhabricatorExternalAccountQuery())->setViewer($viewer)->withUserPHIDs(array($viewer->getPHID()))->withAccountTypes(array($provider->getProviderType()))->withAccountDomains(array($provider->getProviderDomain()))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->execute();
     if (!$accounts) {
         return $this->didFailOnMissingLink();
     }
     // TODO: If the user has several linked Asana accounts, we just pick the
     // first one arbitrarily. We might want to try using all of them or do
     // something with more finesse. There's no UI way to link multiple accounts
     // right now so this is currently moot.
     $account = head($accounts);
     $token = $provider->getOAuthAccessToken($account);
     if (!$token) {
         return;
     }
     $template = id(new PhutilAsanaFuture())->setAccessToken($token);
     $futures = array();
     foreach ($id_map as $key => $id) {
         $futures[$key] = id(clone $template)->setRawAsanaQuery("tasks/{$id}");
     }
     $results = array();
     $failed = array();
     foreach (new FutureIterator($futures) as $key => $future) {
         try {
             $results[$key] = $future->resolve();
         } catch (Exception $ex) {
             if ($ex instanceof HTTPFutureResponseStatus && $ex->getStatusCode() == 404) {
                 // This indicates that the object has been deleted (or never existed,
                 // or isn't visible to the current user) but it's a successful sync of
                 // an object which isn't visible.
             } else {
                 // This is something else, so consider it a synchronization failure.
                 phlog($ex);
                 $failed[$key] = $ex;
             }
         }
     }
     foreach ($refs as $ref) {
         $ref->setAttribute('name', pht('Asana Task %s', $ref->getObjectID()));
         $did_fail = idx($failed, $ref->getObjectKey());
         if ($did_fail) {
             $ref->setSyncFailed(true);
             continue;
         }
         $result = idx($results, $ref->getObjectKey());
         if (!$result) {
             continue;
         }
         $ref->setIsVisible(true);
         $ref->setAttribute('asana.data', $result);
         $ref->setAttribute('fullname', pht('Asana: %s', $result['name']));
         $ref->setAttribute('title', $result['name']);
         $ref->setAttribute('description', $result['notes']);
         $obj = $ref->getExternalObject();
         if ($obj->getID()) {
             continue;
         }
         $this->fillObjectFromData($obj, $result);
         $this->saveExternalObject($ref, $obj);
     }
 }
 private function lookupAsanaUserIDs($all_phids)
 {
     $phid_map = array();
     $all_phids = array_unique(array_filter($all_phids));
     if (!$all_phids) {
         return $phid_map;
     }
     $provider = PhabricatorAsanaAuthProvider::getAsanaProvider();
     $accounts = id(new PhabricatorExternalAccountQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withUserPHIDs($all_phids)->withAccountTypes(array($provider->getProviderType()))->withAccountDomains(array($provider->getProviderDomain()))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->execute();
     foreach ($accounts as $account) {
         $phid_map[$account->getUserPHID()] = $account->getAccountID();
     }
     // Put this back in input order.
     $phid_map = array_select_keys($phid_map, $all_phids);
     return $phid_map;
 }