Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/doorkeeper/bridge/DoorkeeperBridgeJIRA.php
12256 views
1
<?php
2
3
final class DoorkeeperBridgeJIRA extends DoorkeeperBridge {
4
5
const APPTYPE_JIRA = 'jira';
6
const OBJTYPE_ISSUE = 'jira:issue';
7
8
public function canPullRef(DoorkeeperObjectRef $ref) {
9
if ($ref->getApplicationType() != self::APPTYPE_JIRA) {
10
return false;
11
}
12
13
$types = array(
14
self::OBJTYPE_ISSUE => true,
15
);
16
17
return isset($types[$ref->getObjectType()]);
18
}
19
20
public function pullRefs(array $refs) {
21
22
$id_map = mpull($refs, 'getObjectID', 'getObjectKey');
23
$viewer = $this->getViewer();
24
25
$provider = PhabricatorJIRAAuthProvider::getJIRAProvider();
26
if (!$provider) {
27
return;
28
}
29
30
$accounts = id(new PhabricatorExternalAccountQuery())
31
->setViewer($viewer)
32
->withUserPHIDs(array($viewer->getPHID()))
33
->withProviderConfigPHIDs(
34
array(
35
$provider->getProviderConfigPHID(),
36
))
37
->requireCapabilities(
38
array(
39
PhabricatorPolicyCapability::CAN_VIEW,
40
PhabricatorPolicyCapability::CAN_EDIT,
41
))
42
->execute();
43
44
if (!$accounts) {
45
return $this->didFailOnMissingLink();
46
}
47
48
// TODO: When we support multiple JIRA instances, we need to disambiguate
49
// issues (perhaps with additional configuration) or cast a wide net
50
// (by querying all instances). For now, just query the one instance.
51
$account = head($accounts);
52
53
$timeout = $this->getTimeout();
54
55
$futures = array();
56
foreach ($id_map as $key => $id) {
57
$future = $provider->newJIRAFuture(
58
$account,
59
'rest/api/2/issue/'.phutil_escape_uri($id),
60
'GET');
61
62
if ($timeout !== null) {
63
$future->setTimeout($timeout);
64
}
65
66
$futures[$key] = $future;
67
}
68
69
$results = array();
70
$failed = array();
71
foreach (new FutureIterator($futures) as $key => $future) {
72
try {
73
$results[$key] = $future->resolveJSON();
74
} catch (Exception $ex) {
75
if (($ex instanceof HTTPFutureResponseStatus) &&
76
($ex->getStatusCode() == 404)) {
77
// This indicates that the object has been deleted (or never existed,
78
// or isn't visible to the current user) but it's a successful sync of
79
// an object which isn't visible.
80
} else {
81
// This is something else, so consider it a synchronization failure.
82
phlog($ex);
83
$failed[$key] = $ex;
84
}
85
}
86
}
87
88
foreach ($refs as $ref) {
89
$ref->setAttribute('name', pht('JIRA %s', $ref->getObjectID()));
90
91
$did_fail = idx($failed, $ref->getObjectKey());
92
if ($did_fail) {
93
$ref->setSyncFailed(true);
94
continue;
95
}
96
97
$result = idx($results, $ref->getObjectKey());
98
if (!$result) {
99
continue;
100
}
101
102
$fields = idx($result, 'fields', array());
103
104
$ref->setIsVisible(true);
105
$ref->setAttribute(
106
'fullname',
107
pht('JIRA %s %s', $result['key'], idx($fields, 'summary')));
108
109
$ref->setAttribute('title', idx($fields, 'summary'));
110
$ref->setAttribute('description', idx($result, 'description'));
111
$ref->setAttribute('shortname', $result['key']);
112
113
$obj = $ref->getExternalObject();
114
if ($obj->getID()) {
115
continue;
116
}
117
118
$this->fillObjectFromData($obj, $result);
119
$this->saveExternalObject($ref, $obj);
120
}
121
}
122
123
public function fillObjectFromData(DoorkeeperExternalObject $obj, $result) {
124
// Convert the "self" URI, which points at the REST endpoint, into a
125
// browse URI.
126
$self = idx($result, 'self');
127
$object_id = $obj->getObjectID();
128
129
$uri = self::getJIRAIssueBrowseURIFromJIRARestURI($self, $object_id);
130
if ($uri !== null) {
131
$obj->setObjectURI($uri);
132
}
133
}
134
135
public static function getJIRAIssueBrowseURIFromJIRARestURI(
136
$uri,
137
$object_id) {
138
139
$uri = new PhutilURI($uri);
140
141
// The JIRA install might not be at the domain root, so we may need to
142
// keep an initial part of the path, like "/jira/". Find the API specific
143
// part of the URI, strip it off, then replace it with the web version.
144
$path = $uri->getPath();
145
$pos = strrpos($path, 'rest/api/2/issue/');
146
if ($pos === false) {
147
return null;
148
}
149
150
$path = substr($path, 0, $pos);
151
$path = $path.'browse/'.$object_id;
152
$uri->setPath($path);
153
154
return (string)$uri;
155
}
156
157
}
158
159