Path: blob/master/src/applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php
12256 views
<?php12final class DoorkeeperBridgeAsana extends DoorkeeperBridge {34const APPTYPE_ASANA = 'asana';5const APPDOMAIN_ASANA = 'asana.com';6const OBJTYPE_TASK = 'asana:task';78public function canPullRef(DoorkeeperObjectRef $ref) {9if ($ref->getApplicationType() != self::APPTYPE_ASANA) {10return false;11}1213if ($ref->getApplicationDomain() != self::APPDOMAIN_ASANA) {14return false;15}1617$types = array(18self::OBJTYPE_TASK => true,19);2021return isset($types[$ref->getObjectType()]);22}2324public function pullRefs(array $refs) {2526$id_map = mpull($refs, 'getObjectID', 'getObjectKey');27$viewer = $this->getViewer();2829$provider = PhabricatorAsanaAuthProvider::getAsanaProvider();30if (!$provider) {31return;32}3334$accounts = id(new PhabricatorExternalAccountQuery())35->setViewer($viewer)36->withUserPHIDs(array($viewer->getPHID()))37->withProviderConfigPHIDs(38array(39$provider->getProviderConfigPHID(),40))41->requireCapabilities(42array(43PhabricatorPolicyCapability::CAN_VIEW,44PhabricatorPolicyCapability::CAN_EDIT,45))46->execute();4748if (!$accounts) {49return $this->didFailOnMissingLink();50}5152// TODO: If the user has several linked Asana accounts, we just pick the53// first one arbitrarily. We might want to try using all of them or do54// something with more finesse. There's no UI way to link multiple accounts55// right now so this is currently moot.56$account = head($accounts);5758$token = $provider->getOAuthAccessToken($account);59if (!$token) {60return;61}6263$template = id(new PhutilAsanaFuture())64->setAccessToken($token);6566$timeout = $this->getTimeout();67if ($timeout !== null) {68$template->setTimeout($timeout);69}7071$futures = array();72foreach ($id_map as $key => $id) {73$futures[$key] = id(clone $template)74->setRawAsanaQuery("tasks/{$id}");75}7677$results = array();78$failed = array();79foreach (new FutureIterator($futures) as $key => $future) {80try {81$results[$key] = $future->resolve();82} catch (Exception $ex) {83if (($ex instanceof HTTPFutureResponseStatus) &&84($ex->getStatusCode() == 404)) {85// This indicates that the object has been deleted (or never existed,86// or isn't visible to the current user) but it's a successful sync of87// an object which isn't visible.88} else {89// This is something else, so consider it a synchronization failure.90phlog($ex);91$failed[$key] = $ex;92}93}94}9596foreach ($refs as $ref) {97$ref->setAttribute('name', pht('Asana Task %s', $ref->getObjectID()));9899$did_fail = idx($failed, $ref->getObjectKey());100if ($did_fail) {101$ref->setSyncFailed(true);102continue;103}104105$result = idx($results, $ref->getObjectKey());106if (!$result) {107continue;108}109110$ref->setIsVisible(true);111$ref->setAttribute('asana.data', $result);112$ref->setAttribute('fullname', pht('Asana: %s', $result['name']));113$ref->setAttribute('title', $result['name']);114$ref->setAttribute('description', $result['notes']);115116$obj = $ref->getExternalObject();117if ($obj->getID()) {118continue;119}120121$this->fillObjectFromData($obj, $result);122$this->saveExternalObject($ref, $obj);123}124}125126public function fillObjectFromData(DoorkeeperExternalObject $obj, $result) {127$gid = $result['gid'];128$uri = urisprintf(129'https://app.asana.com/0/%s/%s',130$gid,131$gid);132$obj->setObjectURI($uri);133}134135}136137138