Skip to content

Commit 81fa847

Browse files
author
epriestley
committedApr 2, 2014
Make "JIRA Issues" field work better with noncredentialed accounts
Summary: Currently, users get an error when making any changes to this field if they don't have a linked JIRA account. Instead: - We should only raise an error if they're trying to //add// issues, and only on the new issues. It's always fine to remove issues, and existing issues the author can't see are also fine. - When we can't add things because there's no account (vs because there's a permissions error or they don't exist), raise a more tailored exception. Test Plan: - As JIRA and non-JIRA users, made various edits to this field. - Got appropriate exceptions, including better tailoring. Reviewers: btrahan Reviewed By: btrahan Subscribers: mbishopim3, epriestley Differential Revision: https://secure.phabricator.com/D8676
1 parent b50426a commit 81fa847

7 files changed

+68
-11
lines changed
 

‎src/__phutil_library_map__.php

+2
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@
622622
'DoorkeeperFeedWorkerAsana' => 'applications/doorkeeper/worker/DoorkeeperFeedWorkerAsana.php',
623623
'DoorkeeperFeedWorkerJIRA' => 'applications/doorkeeper/worker/DoorkeeperFeedWorkerJIRA.php',
624624
'DoorkeeperImportEngine' => 'applications/doorkeeper/engine/DoorkeeperImportEngine.php',
625+
'DoorkeeperMissingLinkException' => 'applications/doorkeeper/exception/DoorkeeperMissingLinkException.php',
625626
'DoorkeeperObjectRef' => 'applications/doorkeeper/engine/DoorkeeperObjectRef.php',
626627
'DoorkeeperRemarkupRule' => 'applications/doorkeeper/remarkup/DoorkeeperRemarkupRule.php',
627628
'DoorkeeperRemarkupRuleAsana' => 'applications/doorkeeper/remarkup/DoorkeeperRemarkupRuleAsana.php',
@@ -3196,6 +3197,7 @@
31963197
'DoorkeeperFeedWorkerAsana' => 'DoorkeeperFeedWorker',
31973198
'DoorkeeperFeedWorkerJIRA' => 'DoorkeeperFeedWorker',
31983199
'DoorkeeperImportEngine' => 'Phobject',
3200+
'DoorkeeperMissingLinkException' => 'Exception',
31993201
'DoorkeeperObjectRef' => 'Phobject',
32003202
'DoorkeeperRemarkupRule' => 'PhutilRemarkupRule',
32013203
'DoorkeeperRemarkupRuleAsana' => 'DoorkeeperRemarkupRule',

‎src/applications/differential/customfield/DifferentialJIRAIssuesField.php

+32-9
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,11 @@ public function renderEditControl(array $handles) {
116116
}
117117

118118
public function getOldValueForApplicationTransactions() {
119-
return nonempty($this->getValue(), array());
119+
return array_unique(nonempty($this->getValue(), array()));
120120
}
121121

122122
public function getNewValueForApplicationTransactions() {
123-
return nonempty($this->getValue(), array());
123+
return array_unique(nonempty($this->getValue(), array()));
124124
}
125125

126126
public function validateApplicationTransactions(
@@ -137,12 +137,36 @@ public function validateApplicationTransactions(
137137

138138
$transaction = null;
139139
foreach ($xactions as $xaction) {
140-
$value = $xaction->getNewValue();
140+
$old = $xaction->getOldValue();
141+
$new = $xaction->getNewValue();
141142

142-
$refs = id(new DoorkeeperImportEngine())
143-
->setViewer($this->getViewer())
144-
->setRefs($this->buildDoorkeeperRefs($value))
145-
->execute();
143+
$add = array_diff($new, $old);
144+
if (!$add) {
145+
continue;
146+
}
147+
148+
// Only check that the actor can see newly added JIRA refs. You're
149+
// allowed to remove refs or make no-op changes even if you aren't
150+
// linked to JIRA.
151+
152+
try {
153+
$refs = id(new DoorkeeperImportEngine())
154+
->setViewer($this->getViewer())
155+
->setRefs($this->buildDoorkeeperRefs($add))
156+
->setThrowOnMissingLink(true)
157+
->execute();
158+
} catch (DoorkeeperMissingLinkException $ex) {
159+
$this->error = pht('Not Linked');
160+
$errors[] = new PhabricatorApplicationTransactionValidationError(
161+
$type,
162+
pht('Not Linked'),
163+
pht(
164+
'You can not add JIRA issues (%s) to this revision because your '.
165+
'Phabricator account is not linked to a JIRA account.',
166+
implode(', ', $add)),
167+
$xaction);
168+
continue;
169+
}
146170

147171
$bad = array();
148172
foreach ($refs as $ref) {
@@ -155,15 +179,14 @@ public function validateApplicationTransactions(
155179
$bad = implode(', ', $bad);
156180
$this->error = pht('Invalid');
157181

158-
$error = new PhabricatorApplicationTransactionValidationError(
182+
$errors[] = new PhabricatorApplicationTransactionValidationError(
159183
$type,
160184
pht('Invalid'),
161185
pht(
162186
"Some JIRA issues could not be loaded. They may not exist, or ".
163187
"you may not have permission to view them: %s",
164188
$bad),
165189
$xaction);
166-
$errors[] = $error;
167190
}
168191
}
169192

‎src/applications/doorkeeper/bridge/DoorkeeperBridge.php

+15
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
abstract class DoorkeeperBridge extends Phobject {
44

55
private $viewer;
6+
private $throwOnMissingLink;
7+
8+
public function setThrowOnMissingLink($throw_on_missing_link) {
9+
$this->throwOnMissingLink = $throw_on_missing_link;
10+
return $this;
11+
}
612

713
final public function setViewer($viewer) {
814
$this->viewer = $viewer;
@@ -21,6 +27,15 @@ abstract public function canPullRef(DoorkeeperObjectRef $ref);
2127
abstract public function pullRefs(array $refs);
2228

2329
public function fillObjectFromData(DoorkeeperExternalObject $obj, $result) {
30+
return;
31+
}
32+
33+
public function didFailOnMissingLink() {
34+
if ($this->throwOnMissingLink) {
35+
throw new DoorkeeperMissingLinkException();
36+
}
37+
38+
return null;
2439
}
2540

2641
}

‎src/applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function pullRefs(array $refs) {
4040
->execute();
4141

4242
if (!$accounts) {
43-
return;
43+
return $this->didFailOnMissingLink();
4444
}
4545

4646
// TODO: If the user has several linked Asana accounts, we just pick the

‎src/applications/doorkeeper/bridge/DoorkeeperBridgeJIRA.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public function pullRefs(array $refs) {
3434
->execute();
3535

3636
if (!$accounts) {
37-
return;
37+
return $this->didFailOnMissingLink();
3838
}
3939

4040
// TODO: When we support multiple JIRA instances, we need to disambiguate

‎src/applications/doorkeeper/engine/DoorkeeperImportEngine.php

+12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ final class DoorkeeperImportEngine extends Phobject {
66
private $refs = array();
77
private $phids = array();
88
private $localOnly;
9+
private $throwOnMissingLink;
910

1011
public function setViewer(PhabricatorUser $viewer) {
1112
$this->viewer = $viewer;
@@ -36,6 +37,16 @@ public function needLocalOnly($local_only) {
3637
return $this;
3738
}
3839

40+
41+
/**
42+
* Configure behavior if remote refs can not be retrieved because an
43+
* authentication link is missing.
44+
*/
45+
public function setThrowOnMissingLink($throw) {
46+
$this->throwOnMissingLink = $throw;
47+
return $this;
48+
}
49+
3950
public function execute() {
4051
$refs = $this->getRefs();
4152
$viewer = $this->getViewer();
@@ -86,6 +97,7 @@ public function execute() {
8697
unset($bridges[$key]);
8798
}
8899
$bridge->setViewer($viewer);
100+
$bridge->setThrowOnMissingLink($this->throwOnMissingLink);
89101
}
90102

91103
$working_set = $refs;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
final class DoorkeeperMissingLinkException extends Exception {
4+
5+
}

0 commit comments

Comments
 (0)
Failed to load comments.