1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-28 01:32:42 +01:00
phorge-phorge/src/applications/doorkeeper/bridge/DoorkeeperBridgeJIRA.php
epriestley 825fb9c85a Add JIRA doorkeeper and remarkup support
Summary:
Ref T3687. Adds a Doorkeeper bridge for JIRA issues, plus remarkup support. In particular:

  - The Asana and JIRA remarkup rules shared most of their implementation, so I refactored what I could into a base class.
  - Actual bridge implementation is straightforward and similar to Asana, although probably not similar enough to really justify refactoring.

Test Plan:
  - When logged in as a JIRA-connected user, pasted a JIRA issue link and saw it enriched at rendering time.
  - Logged in and out with JIRA.
  - Tested an Asana link, too (seems I haven't broken anything).

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T3687

Differential Revision: https://secure.phabricator.com/D6878
2013-09-03 17:27:38 -07:00

119 lines
3.2 KiB
PHP

<?php
final class DoorkeeperBridgeJIRA extends DoorkeeperBridge {
const APPTYPE_JIRA = 'jira';
const OBJTYPE_ISSUE = 'jira:issue';
public function canPullRef(DoorkeeperObjectRef $ref) {
if ($ref->getApplicationType() != self::APPTYPE_JIRA) {
return false;
}
$types = array(
self::OBJTYPE_ISSUE => true,
);
return isset($types[$ref->getObjectType()]);
}
public function pullRefs(array $refs) {
$id_map = mpull($refs, 'getObjectID', 'getObjectKey');
$viewer = $this->getViewer();
$provider = PhabricatorAuthProviderOAuth1JIRA::getJIRAProvider();
if (!$provider) {
return;
}
$accounts = id(new PhabricatorExternalAccountQuery())
->setViewer($viewer)
->withUserPHIDs(array($viewer->getPHID()))
->withAccountTypes(array($provider->getProviderType()))
->execute();
if (!$accounts) {
return;
}
// TODO: When we support multiple JIRA instances, we need to disambiguate
// issues (perhaps with additional configuration) or cast a wide net
// (by querying all instances). For now, just query the one instance.
$account = head($accounts);
$futures = array();
foreach ($id_map as $key => $id) {
$futures[$key] = $provider->newJIRAFuture(
$account,
'rest/api/2/issue/'.phutil_escape_uri($id),
'GET');
}
$results = array();
$failed = array();
foreach (Futures($futures) as $key => $future) {
try {
$results[$key] = $future->resolveJSON();
} 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('JIRA %s', $ref->getObjectID()));
$did_fail = idx($failed, $ref->getObjectKey());
if ($did_fail) {
$ref->setSyncFailed(true);
continue;
}
$result = idx($results, $ref->getObjectKey());
if (!$result) {
continue;
}
$fields = idx($result, 'fields', array());
$ref->setIsVisible(true);
$ref->setAttribute(
'fullname',
pht('JIRA %s %s', $result['key'], idx($fields, 'summary')));
$ref->setAttribute('title', idx($fields, 'summary'));
$ref->setAttribute('description', idx($result, 'description'));
$obj = $ref->getExternalObject();
if ($obj->getID()) {
continue;
}
$this->fillObjectFromData($obj, $result);
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$obj->save();
unset($unguarded);
}
}
public function fillObjectFromData(DoorkeeperExternalObject $obj, $result) {
// Convert the "self" URI, which points at the REST endpoint, into a
// browse URI.
$self = idx($result, 'self');
$uri = new PhutilURI($self);
$uri->setPath('browse/'.$obj->getObjectID());
$obj->setObjectURI((string)$uri);
}
}