mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-22 21:40: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:
parent
f54a5d8087
commit
e723b7e119
7 changed files with 244 additions and 9 deletions
|
@ -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',
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
23
src/applications/doorkeeper/bridge/DoorkeeperBridge.php
Normal file
23
src/applications/doorkeeper/bridge/DoorkeeperBridge.php
Normal 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);
|
||||
|
||||
}
|
79
src/applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php
Normal file
79
src/applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
109
src/applications/doorkeeper/engine/DoorkeeperObjectRef.php
Normal file
109
src/applications/doorkeeper/engine/DoorkeeperObjectRef.php
Normal 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue