1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 05:50:55 +01:00

Add DoorkeeperObjectRef, DoorkeeperBridge, DoorkeeperBridgeAsana

Summary:
  - `DoorkeeperObjectRef` is a convenience object to keep track of `<applicationType, applicationDomain, objectType, objectID>` tuples.
  - `DoorkeeperBridge` provides pull/push between Phabricator and external systems.
  - `DoorkeeperBridgeAsana` is a bridge to Asana.

Test Plan:
Ran this snippet and got a task from Asana:

{P871}

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Differential Revision: https://secure.phabricator.com/D6273
This commit is contained in:
epriestley 2013-06-24 15:54:54 -07:00
parent f54a5d8087
commit e723b7e119
7 changed files with 244 additions and 9 deletions

View file

@ -533,8 +533,11 @@ phutil_register_library_map(array(
'DivinerRenderer' => 'applications/diviner/renderer/DivinerRenderer.php',
'DivinerStaticPublisher' => 'applications/diviner/publisher/DivinerStaticPublisher.php',
'DivinerWorkflow' => 'applications/diviner/workflow/DivinerWorkflow.php',
'DoorkeeperBridge' => 'applications/doorkeeper/bridge/DoorkeeperBridge.php',
'DoorkeeperBridgeAsana' => 'applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php',
'DoorkeeperDAO' => 'applications/doorkeeper/storage/DoorkeeperDAO.php',
'DoorkeeperExternalObject' => 'applications/doorkeeper/storage/DoorkeeperExternalObject.php',
'DoorkeeperObjectRef' => 'applications/doorkeeper/engine/DoorkeeperObjectRef.php',
'DrydockAllocatorWorker' => 'applications/drydock/worker/DrydockAllocatorWorker.php',
'DrydockApacheWebrootInterface' => 'applications/drydock/interface/webroot/DrydockApacheWebrootInterface.php',
'DrydockBlueprint' => 'applications/drydock/blueprint/DrydockBlueprint.php',
@ -2406,12 +2409,15 @@ phutil_register_library_map(array(
'DivinerRemarkupRuleSymbol' => 'PhutilRemarkupRule',
'DivinerStaticPublisher' => 'DivinerPublisher',
'DivinerWorkflow' => 'PhutilArgumentWorkflow',
'DoorkeeperBridge' => 'Phobject',
'DoorkeeperBridgeAsana' => 'DoorkeeperBridge',
'DoorkeeperDAO' => 'PhabricatorLiskDAO',
'DoorkeeperExternalObject' =>
array(
0 => 'DoorkeeperDAO',
1 => 'PhabricatorPolicyInterface',
),
'DoorkeeperObjectRef' => 'Phobject',
'DrydockAllocatorWorker' => 'PhabricatorWorker',
'DrydockApacheWebrootInterface' => 'DrydockWebrootInterface',
'DrydockCommandInterface' => 'DrydockInterface',

View file

@ -281,4 +281,12 @@ abstract class PhabricatorAuthProviderOAuth extends PhabricatorAuthProvider {
return parent::renderConfigPropertyTransactionTitle($xaction);
}
protected function willSaveAccount(PhabricatorExternalAccount $account) {
parent::willSaveAccount($account);
$oauth_token = $this->getAdapter()->getAccessToken();
$account->setProperty('oauth.token', $oauth_token);
}
}

View file

@ -35,4 +35,16 @@ final class PhabricatorAuthProviderOAuthAsana
return 'Asana';
}
public static function getAsanaProvider() {
$providers = self::getAllEnabledProviders();
foreach ($providers as $provider) {
if ($provider instanceof PhabricatorAuthProviderOAuthAsana) {
return $provider;
}
}
return null;
}
}

View file

@ -0,0 +1,23 @@
<?php
abstract class DoorkeeperBridge extends Phobject {
private $viewer;
final public function setViewer($viewer) {
$this->viewer = $viewer;
return $this;
}
final public function getViewer() {
return $this->viewer;
}
public function isEnabled() {
return true;
}
abstract public function canPullRef(DoorkeeperObjectRef $ref);
abstract public function pullRefs(array $refs);
}

View file

@ -0,0 +1,79 @@
<?php
final class DoorkeeperBridgeAsana extends DoorkeeperBridge {
public function canPullRef(DoorkeeperObjectRef $ref) {
return ($ref->getApplicationType() == 'asana') &&
($ref->getApplicationDomain() == 'asana.com') &&
($ref->getObjectType() == 'asana:task');
}
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();
// 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 = $account->getProperty('oauth.token');
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();
foreach (Futures($futures) as $key => $future) {
$results[$key] = $future->resolve();
}
foreach ($refs as $ref) {
$result = idx($results, $ref->getObjectKey());
if (!$result) {
continue;
}
$ref->setIsVisible(true);
$ref->setAttribute('asana.data', $result);
$ref->setAttribute('name', $result['name']);
$ref->setAttribute('description', $result['notes']);
$obj = $ref->getExternalObject();
if ($obj->getID()) {
continue;
}
$id = $result['id'];
$uri = "https://app.asana.com/0/{$id}/{$id}";
$obj->setObjectURI($uri);
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$obj->save();
unset($unguarded);
}
}
}

View file

@ -0,0 +1,109 @@
<?php
final class DoorkeeperObjectRef extends Phobject {
private $objectKey;
private $applicationType;
private $applicationDomain;
private $objectType;
private $objectID;
private $attributes = array();
private $isVisible;
private $externalObject;
public function newExternalObject() {
return id(new DoorkeeperExternalObject())
->setApplicationType($this->getApplicationType())
->setApplicationDomain($this->getApplicationDomain())
->setObjectType($this->getObjectType())
->setObjectID($this->getObjectID())
->setViewPolicy(PhabricatorPolicies::POLICY_USER);
}
public function attachExternalObject(
DoorkeeperExternalObject $external_object) {
$this->externalObject = $external_object;
return $this;
}
public function getExternalObject() {
if (!$this->externalObject) {
throw new Exception(
"Call attachExternalObject() before getExternalObject()!");
}
return $this->externalObject;
}
public function setIsVisible($is_visible) {
$this->isVisible = $is_visible;
return $this;
}
public function getIsVisible() {
return $this->isVisible;
}
public function getAttribute($key, $default = null) {
return idx($this->attribute, $key, $default);
}
public function setAttribute($key, $value) {
$this->attributes[$key] = $value;
return $this;
}
public function setObjectID($object_id) {
$this->objectID = $object_id;
return $this;
}
public function getObjectID() {
return $this->objectID;
}
public function setObjectType($object_type) {
$this->objectType = $object_type;
return $this;
}
public function getObjectType() {
return $this->objectType;
}
public function setApplicationDomain($application_domain) {
$this->applicationDomain = $application_domain;
return $this;
}
public function getApplicationDomain() {
return $this->applicationDomain;
}
public function setApplicationType($application_type) {
$this->applicationType = $application_type;
return $this;
}
public function getApplicationType() {
return $this->applicationType;
}
public function getObjectKey() {
if (!$this->objectKey) {
$this->objectKey = PhabricatorHash::digestForIndex(
implode(
':',
array(
$this->getApplicationType(),
$this->getApplicationDomain(),
$this->getObjectType(),
$this->getObjectID(),
)));
}
return $this->objectKey;
}
}

View file

@ -39,15 +39,12 @@ final class DoorkeeperExternalObject extends DoorkeeperDAO
public function getObjectKey() {
$key = parent::getObjectKey();
if ($key === null) {
$key = PhabricatorHash::digestForIndex(
implode(
':',
array(
$this->getApplicationType(),
$this->getApplicationDomain(),
$this->getObjectType(),
$this->getObjectID(),
)));
$key = id(new DoorkeeperObjectRef())
->setApplicationType($this->getApplicationType())
->setApplicationDomain($this->getApplicationDomain())
->setObjectType($this->getObjectType())
->setObjectID($this->getObjectID())
->getObjectKey();
}
return $key;
}
@ -56,6 +53,7 @@ final class DoorkeeperExternalObject extends DoorkeeperDAO
if (!$this->objectKey) {
$this->objectKey = $this->getObjectKey();
}
return parent::save();
}