getApplicationType() != self::APPTYPE_ASANA) { return false; } if ($ref->getApplicationDomain() != self::APPDOMAIN_ASANA) { return false; } $types = array( self::OBJTYPE_TASK => true, ); return isset($types[$ref->getObjectType()]); } public function pullRefs(array $refs) { $id_map = mpull($refs, 'getObjectID', 'getObjectKey'); $viewer = $this->getViewer(); $provider = PhabricatorAuthProviderOAuthAsana::getAsanaProvider(); if (!$provider) { return; } $accounts = id(new PhabricatorExternalAccountQuery()) ->setViewer($viewer) ->withUserPHIDs(array($viewer->getPHID())) ->withAccountTypes(array($provider->getProviderType())) ->withAccountDomains(array($provider->getProviderDomain())) ->execute(); if (!$accounts) { return; } // 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 (Futures($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); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $obj->save(); unset($unguarded); } } public function fillObjectFromData(DoorkeeperExternalObject $obj, $result) { $id = $result['id']; $uri = "https://app.asana.com/0/{$id}/{$id}"; $obj->setObjectURI($uri); } }