Update Set Review API to behave in line with RFC 7231
This CL updates the implementation of PostReview to replace all instances of raising UnprocessableEntityException (HTTP 422) with failed Additions instead. This matches the docs for Set Reviewer, which no longer mention 422 being a valid response code. This also falls in line with RFC 7231, which promotes HTTP 400s with detailed bodies over 422s. It also updates the documentation to be clearer about how these API functions work. Bug: issue 6016 Change-Id: I1adad98107ba021132293ec47c6a6da01787556e
This commit is contained in:

committed by
David Pursehouse

parent
0beb6d9540
commit
8c650215eb
@@ -2745,16 +2745,16 @@ returned that describes the newly added reviewers.
|
||||
|
||||
)]}'
|
||||
{
|
||||
"input": "john.doe@example.com",
|
||||
"reviewers": [
|
||||
{
|
||||
"input": "john.doe@example.com",
|
||||
"_account_id": 1000096,
|
||||
"name": "John Doe",
|
||||
"email": "john.doe@example.com"
|
||||
"approvals": {
|
||||
"Verified": " 0",
|
||||
"Code-Review": " 0"
|
||||
},
|
||||
"_account_id": 1000096,
|
||||
"name": "John Doe",
|
||||
"email": "john.doe@example.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3387,6 +3387,11 @@ Sets a review on a revision.
|
||||
The review must be provided in the request body as a
|
||||
link:#review-input[ReviewInput] entity.
|
||||
|
||||
A review cannot be set on a change edit. Trying to post a review for a
|
||||
change edit fails with `409 Conflict`.
|
||||
|
||||
This API method can be used to set labels:
|
||||
|
||||
.Request
|
||||
----
|
||||
POST /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/674ac754f91e64a0efb8087e59a176484bd534d1/review HTTP/1.0
|
||||
@@ -3423,7 +3428,8 @@ link:#review-input[ReviewInput] entity.
|
||||
----
|
||||
|
||||
As response a link:#review-result[ReviewResult] entity is returned that
|
||||
describes the applied labels.
|
||||
describes the applied labels and any added reviewers (e.g. yourself,
|
||||
if you set a label but weren't previously a reviewer on this CL).
|
||||
|
||||
.Response
|
||||
----
|
||||
@@ -3439,11 +3445,8 @@ describes the applied labels.
|
||||
}
|
||||
----
|
||||
|
||||
A review cannot be set on a change edit. Trying to post a review for a
|
||||
change edit fails with `409 Conflict`.
|
||||
|
||||
It is also possible to add one or more reviewers to a change simultaneously
|
||||
with a review.
|
||||
It is also possible to add one or more reviewers or CCs
|
||||
to a change simultaneously with a review.
|
||||
|
||||
.Request
|
||||
----
|
||||
@@ -3451,16 +3454,17 @@ with a review.
|
||||
Content-Type: application/json; charset=UTF-8
|
||||
|
||||
{
|
||||
"message": "Looks good to me, but Jane and John should also take a look.",
|
||||
"labels": {
|
||||
"Code-Review": 1
|
||||
},
|
||||
"message": "I don't have context here. Jane and maybe John and the project leads should take a look.",
|
||||
"reviewers": [
|
||||
{
|
||||
"reviewer": "jane.roe@example.com"
|
||||
},
|
||||
{
|
||||
"reviewer": "john.doe@example.com"
|
||||
"reviewer": "john.doe@example.com",
|
||||
"state": "CC"
|
||||
}
|
||||
{
|
||||
"reviewer": "MyProjectVerifiers",
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3468,8 +3472,8 @@ with a review.
|
||||
|
||||
Each element of the `reviewers` list is an instance of
|
||||
link:#reviewer-input[ReviewerInput]. The corresponding result of
|
||||
adding each reviewer will be returned in a list of
|
||||
link:#add-reviewer-result[AddReviewerResult].
|
||||
adding each reviewer will be returned in a map of inputs to
|
||||
link:#add-reviewer-result[AddReviewerResult]s.
|
||||
|
||||
.Response
|
||||
----
|
||||
@@ -3479,36 +3483,66 @@ link:#add-reviewer-result[AddReviewerResult].
|
||||
|
||||
)]}'
|
||||
{
|
||||
"labels": {
|
||||
"Code-Review": 1
|
||||
},
|
||||
"reviewers": {
|
||||
"jane.roe@example.com": {
|
||||
"input": "jane.roe@example.com",
|
||||
"reviewers": [
|
||||
{
|
||||
"input": "jane.roe@example.com",
|
||||
"approvals": {
|
||||
"Verified": " 0",
|
||||
"Code-Review": " 0"
|
||||
},
|
||||
"_account_id": 1000097,
|
||||
"name": "Jane Roe",
|
||||
"email": "jane.roe@example.com"
|
||||
},
|
||||
{
|
||||
"input": "john.doe@example.com",
|
||||
"approvals": {
|
||||
"Verified": " 0",
|
||||
"Code-Review": " 0"
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
"john.doe@example.com": {
|
||||
"input": "john.doe@example.com",
|
||||
"ccs": [
|
||||
{
|
||||
"_account_id": 1000096,
|
||||
"name": "John Doe",
|
||||
"email": "john.doe@example.com"
|
||||
"approvals": {
|
||||
"Verified": " 0",
|
||||
"Code-Review": " 0"
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
"MyProjectVerifiers": {
|
||||
"input": "MyProjectVerifiers",
|
||||
"reviewers": [
|
||||
{
|
||||
"_account_id": 1000098,
|
||||
"name": "Alice Ansel",
|
||||
"email": "alice.ansel@example.com"
|
||||
"approvals": {
|
||||
"Verified": " 0",
|
||||
"Code-Review": " 0"
|
||||
},
|
||||
},
|
||||
{
|
||||
"_account_id": 1000099,
|
||||
"name": "Bob Bollard",
|
||||
"email": "bob.bollard@example.com"
|
||||
"approvals": {
|
||||
"Verified": " 0",
|
||||
"Code-Review": " 0"
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
If there are any errors returned for reviewers, the entire review request will
|
||||
be rejected with `400 Bad Request`.
|
||||
be rejected with `400 Bad Request`. None of the entries will have the
|
||||
`reviewers` or `ccs` field set, and those which specifically failed will have
|
||||
the `errors` field set containing details of why they failed.
|
||||
|
||||
.Error Response
|
||||
----
|
||||
@@ -3519,6 +3553,13 @@ be rejected with `400 Bad Request`.
|
||||
)]}'
|
||||
{
|
||||
"reviewers": {
|
||||
"jane.roe@example.com": {
|
||||
"input": "jane.roe@example.com",
|
||||
"error": "Account of jane.roe@example.com is inactive."
|
||||
},
|
||||
"john.doe@example.com": {
|
||||
"input": "john.doe@example.com"
|
||||
},
|
||||
"MyProjectVerifiers": {
|
||||
"input": "MyProjectVerifiers",
|
||||
"error": "The group My Group has 15 members. Do you want to add them all as reviewers?",
|
||||
|
@@ -54,6 +54,7 @@ import com.google.gerrit.common.TimeUtil;
|
||||
import com.google.gerrit.common.data.LabelType;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.extensions.api.changes.AddReviewerInput;
|
||||
import com.google.gerrit.extensions.api.changes.AddReviewerResult;
|
||||
import com.google.gerrit.extensions.api.changes.DeleteReviewerInput;
|
||||
import com.google.gerrit.extensions.api.changes.DeleteVoteInput;
|
||||
import com.google.gerrit.extensions.api.changes.NotifyHandling;
|
||||
@@ -90,7 +91,6 @@ import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.Branch;
|
||||
@@ -1057,23 +1057,27 @@ public class ChangeIT extends AbstractDaemonTest {
|
||||
setApiUser(admin);
|
||||
AddReviewerInput in = new AddReviewerInput();
|
||||
in.reviewer = user.email;
|
||||
exception.expect(UnprocessableEntityException.class);
|
||||
exception.expectMessage("Change not visible to " + user.email);
|
||||
gApi.changes().id(result.getChangeId()).addReviewer(in);
|
||||
AddReviewerResult r = gApi.changes().id(result.getChangeId()).addReviewer(in);
|
||||
|
||||
assertThat(r.input).isEqualTo(user.email);
|
||||
assertThat(r.error).contains("does not have permission to see this change");
|
||||
assertThat(r.reviewers).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addReviewerThatIsInactive() throws Exception {
|
||||
PushOneCommit.Result r = createChange();
|
||||
PushOneCommit.Result result = createChange();
|
||||
|
||||
String username = name("new-user");
|
||||
gApi.accounts().create(username).setActive(false);
|
||||
|
||||
AddReviewerInput in = new AddReviewerInput();
|
||||
in.reviewer = username;
|
||||
exception.expect(UnprocessableEntityException.class);
|
||||
exception.expectMessage("Account of " + username + " is inactive.");
|
||||
gApi.changes().id(r.getChangeId()).addReviewer(in);
|
||||
AddReviewerResult r = gApi.changes().id(result.getChangeId()).addReviewer(in);
|
||||
|
||||
assertThat(r.input).isEqualTo(username);
|
||||
assertThat(r.error).contains("identifies an inactive account");
|
||||
assertThat(r.reviewers).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@@ -24,6 +24,7 @@ import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||
import com.google.gerrit.acceptance.NoHttpd;
|
||||
import com.google.gerrit.acceptance.PushOneCommit;
|
||||
import com.google.gerrit.extensions.api.changes.AddReviewerInput;
|
||||
import com.google.gerrit.extensions.api.changes.AddReviewerResult;
|
||||
import com.google.gerrit.extensions.api.changes.ReviewInput;
|
||||
import com.google.gerrit.extensions.api.projects.ConfigInput;
|
||||
import com.google.gerrit.extensions.client.InheritableBoolean;
|
||||
@@ -31,8 +32,6 @@ import com.google.gerrit.extensions.client.ListChangesOption;
|
||||
import com.google.gerrit.extensions.client.ReviewerState;
|
||||
import com.google.gerrit.extensions.common.AccountInfo;
|
||||
import com.google.gerrit.extensions.common.ChangeInfo;
|
||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
|
||||
import com.google.gerrit.server.mail.Address;
|
||||
import com.google.gerrit.testutil.FakeEmailSender.Message;
|
||||
import java.util.EnumSet;
|
||||
@@ -271,9 +270,9 @@ public class ChangeReviewersByEmailIT extends AbstractDaemonTest {
|
||||
assume().that(notesMigration.readChanges()).isTrue();
|
||||
PushOneCommit.Result r = createChange();
|
||||
|
||||
exception.expect(UnprocessableEntityException.class);
|
||||
exception.expectMessage("email invalid");
|
||||
gApi.changes().id(r.getChangeId()).addReviewer("");
|
||||
AddReviewerResult result = gApi.changes().id(r.getChangeId()).addReviewer("");
|
||||
assertThat(result.error).isEqualTo(" is not a valid user identifier");
|
||||
assertThat(result.reviewers).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -281,9 +280,9 @@ public class ChangeReviewersByEmailIT extends AbstractDaemonTest {
|
||||
assume().that(notesMigration.readChanges()).isTrue();
|
||||
PushOneCommit.Result r = createChange();
|
||||
|
||||
exception.expect(UnprocessableEntityException.class);
|
||||
exception.expectMessage("email invalid");
|
||||
gApi.changes().id(r.getChangeId()).addReviewer("Foo Bar <foo.bar@");
|
||||
AddReviewerResult result = gApi.changes().id(r.getChangeId()).addReviewer("Foo Bar <foo.bar@");
|
||||
assertThat(result.error).isEqualTo("Foo Bar <foo.bar@ is not a valid user identifier");
|
||||
assertThat(result.reviewers).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -291,9 +290,12 @@ public class ChangeReviewersByEmailIT extends AbstractDaemonTest {
|
||||
assume().that(notesMigration.readChanges()).isTrue();
|
||||
PushOneCommit.Result r = createDraftChange();
|
||||
|
||||
exception.expect(BadRequestException.class);
|
||||
exception.expectMessage("change is not publicly visible");
|
||||
AddReviewerResult result =
|
||||
gApi.changes().id(r.getChangeId()).addReviewer("Foo Bar <foo.bar@gerritcodereview.com>");
|
||||
assertThat(result.error)
|
||||
.isEqualTo(
|
||||
"Foo Bar <foo.bar@gerritcodereview.com> does not have permission to see this change");
|
||||
assertThat(result.reviewers).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -306,10 +308,12 @@ public class ChangeReviewersByEmailIT extends AbstractDaemonTest {
|
||||
|
||||
PushOneCommit.Result r = createChange();
|
||||
|
||||
exception.expect(UnprocessableEntityException.class);
|
||||
exception.expectMessage(
|
||||
"Foo Bar <foo.bar@gerritcodereview.com> does not identify a registered user or group");
|
||||
AddReviewerResult result =
|
||||
gApi.changes().id(r.getChangeId()).addReviewer("Foo Bar <foo.bar@gerritcodereview.com>");
|
||||
assertThat(result.error)
|
||||
.isEqualTo(
|
||||
"Foo Bar <foo.bar@gerritcodereview.com> does not identify a registered user or group");
|
||||
assertThat(result.reviewers).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@@ -131,9 +131,9 @@ public interface ChangeApi {
|
||||
|
||||
IncludedInInfo includedIn() throws RestApiException;
|
||||
|
||||
void addReviewer(AddReviewerInput in) throws RestApiException;
|
||||
AddReviewerResult addReviewer(AddReviewerInput in) throws RestApiException;
|
||||
|
||||
void addReviewer(String in) throws RestApiException;
|
||||
AddReviewerResult addReviewer(String in) throws RestApiException;
|
||||
|
||||
SuggestedReviewersRequest suggestReviewers() throws RestApiException;
|
||||
|
||||
@@ -359,12 +359,12 @@ public interface ChangeApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReviewer(AddReviewerInput in) {
|
||||
public AddReviewerResult addReviewer(AddReviewerInput in) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReviewer(String in) {
|
||||
public AddReviewerResult addReviewer(String in) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
@@ -17,6 +17,7 @@ package com.google.gerrit.server.api.changes;
|
||||
import com.google.gerrit.common.errors.EmailException;
|
||||
import com.google.gerrit.extensions.api.changes.AbandonInput;
|
||||
import com.google.gerrit.extensions.api.changes.AddReviewerInput;
|
||||
import com.google.gerrit.extensions.api.changes.AddReviewerResult;
|
||||
import com.google.gerrit.extensions.api.changes.AssigneeInput;
|
||||
import com.google.gerrit.extensions.api.changes.ChangeApi;
|
||||
import com.google.gerrit.extensions.api.changes.ChangeEditApi;
|
||||
@@ -406,16 +407,16 @@ class ChangeApiImpl implements ChangeApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReviewer(String reviewer) throws RestApiException {
|
||||
public AddReviewerResult addReviewer(String reviewer) throws RestApiException {
|
||||
AddReviewerInput in = new AddReviewerInput();
|
||||
in.reviewer = reviewer;
|
||||
addReviewer(in);
|
||||
return addReviewer(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReviewer(AddReviewerInput in) throws RestApiException {
|
||||
public AddReviewerResult addReviewer(AddReviewerInput in) throws RestApiException {
|
||||
try {
|
||||
postReviewers.apply(change, in);
|
||||
return postReviewers.apply(change, in);
|
||||
} catch (OrmException | IOException | UpdateException | PermissionBackendException e) {
|
||||
throw new RestApiException("Cannot add change reviewer", e);
|
||||
}
|
||||
|
@@ -23,6 +23,10 @@ public class ChangeMessages extends TranslationBundle {
|
||||
}
|
||||
|
||||
public String revertChangeDefaultMessage;
|
||||
|
||||
public String reviewerCantSeeChange;
|
||||
public String reviewerInactive;
|
||||
public String reviewerInvalid;
|
||||
public String reviewerNotFoundUser;
|
||||
public String reviewerNotFoundUserOrGroup;
|
||||
|
||||
|
@@ -168,20 +168,33 @@ public class PostReviewers implements RestModifyView<ChangeResource, AddReviewer
|
||||
|
||||
public Addition prepareApplication(
|
||||
ChangeResource rsrc, AddReviewerInput input, boolean allowGroup)
|
||||
throws OrmException, RestApiException, IOException, PermissionBackendException {
|
||||
throws OrmException, IOException, PermissionBackendException {
|
||||
String reviewer = input.reviewer;
|
||||
ReviewerState state = input.state();
|
||||
NotifyHandling notify = input.notify;
|
||||
ListMultimap<RecipientType, Account.Id> accountsToNotify = null;
|
||||
try {
|
||||
accountsToNotify = notifyUtil.resolveAccounts(input.notifyDetails);
|
||||
} catch (BadRequestException e) {
|
||||
return fail(reviewer, e.getMessage());
|
||||
}
|
||||
boolean confirmed = input.confirmed();
|
||||
boolean allowByEmail = projectCache.checkedGet(rsrc.getProject()).isEnableReviewerByEmail();
|
||||
|
||||
Addition byAccountId = addByAccountId(rsrc, input, allowGroup, allowByEmail);
|
||||
Addition byAccountId =
|
||||
addByAccountId(reviewer, rsrc, state, notify, accountsToNotify, allowGroup, allowByEmail);
|
||||
if (byAccountId != null) {
|
||||
return byAccountId;
|
||||
}
|
||||
|
||||
Addition wholeGroup = addWholeGroup(rsrc, input, allowGroup, allowByEmail);
|
||||
Addition wholeGroup =
|
||||
addWholeGroup(
|
||||
reviewer, rsrc, state, notify, accountsToNotify, confirmed, allowGroup, allowByEmail);
|
||||
if (wholeGroup != null) {
|
||||
return wholeGroup;
|
||||
}
|
||||
|
||||
return addByEmail(rsrc, input);
|
||||
return addByEmail(reviewer, rsrc, state, notify, accountsToNotify);
|
||||
}
|
||||
|
||||
Addition ccCurrentUser(CurrentUser user, RevisionResource revision) {
|
||||
@@ -197,117 +210,72 @@ public class PostReviewers implements RestModifyView<ChangeResource, AddReviewer
|
||||
|
||||
@Nullable
|
||||
private Addition addByAccountId(
|
||||
ChangeResource rsrc, AddReviewerInput input, boolean allowGroup, boolean allowByEmail)
|
||||
throws OrmException, RestApiException, PermissionBackendException {
|
||||
Account.Id accountId = null;
|
||||
try {
|
||||
accountId = accounts.parse(input.reviewer).getAccountId();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
if (!allowGroup && !allowByEmail) {
|
||||
throw new UnprocessableEntityException(
|
||||
MessageFormat.format(ChangeMessages.get().reviewerNotFoundUser, input.reviewer));
|
||||
}
|
||||
}
|
||||
if (accountId != null) {
|
||||
return putAccount(
|
||||
input.reviewer,
|
||||
reviewerFactory.create(rsrc, accountId),
|
||||
input.state(),
|
||||
input.notify,
|
||||
notifyUtil.resolveAccounts(input.notifyDetails));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Addition addWholeGroup(
|
||||
ChangeResource rsrc, AddReviewerInput input, boolean allowGroup, boolean allowByEmail)
|
||||
throws OrmException, RestApiException, IOException, PermissionBackendException {
|
||||
if (!allowGroup) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return putGroup(rsrc, input);
|
||||
} catch (UnprocessableEntityException e) {
|
||||
if (!allowByEmail) {
|
||||
throw new UnprocessableEntityException(
|
||||
MessageFormat.format(ChangeMessages.get().reviewerNotFoundUserOrGroup, input.reviewer));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Addition addByEmail(ChangeResource rsrc, AddReviewerInput input)
|
||||
throws OrmException, RestApiException {
|
||||
return putAccountByEmail(
|
||||
input.reviewer,
|
||||
rsrc,
|
||||
input.state(),
|
||||
input.notify,
|
||||
notifyUtil.resolveAccounts(input.notifyDetails));
|
||||
}
|
||||
|
||||
private Addition putAccount(
|
||||
String reviewer,
|
||||
ReviewerResource rsrc,
|
||||
ReviewerState state,
|
||||
NotifyHandling notify,
|
||||
ListMultimap<RecipientType, Account.Id> accountsToNotify)
|
||||
throws UnprocessableEntityException, PermissionBackendException {
|
||||
Account member = rsrc.getReviewerUser().getAccount();
|
||||
PermissionBackend.ForRef perm =
|
||||
permissionBackend.user(rsrc.getReviewerUser()).ref(rsrc.getChange().getDest());
|
||||
if (isValidReviewer(member, perm)) {
|
||||
return new Addition(
|
||||
reviewer,
|
||||
rsrc.getChangeResource(),
|
||||
ImmutableSet.of(member.getId()),
|
||||
null,
|
||||
state,
|
||||
notify,
|
||||
accountsToNotify);
|
||||
}
|
||||
if (member.isActive()) {
|
||||
throw new UnprocessableEntityException(String.format("Change not visible to %s", reviewer));
|
||||
}
|
||||
throw new UnprocessableEntityException(String.format("Account of %s is inactive.", reviewer));
|
||||
}
|
||||
|
||||
private Addition putAccountByEmail(
|
||||
String reviewer,
|
||||
ChangeResource rsrc,
|
||||
ReviewerState state,
|
||||
NotifyHandling notify,
|
||||
ListMultimap<RecipientType, Account.Id> accountsToNotify)
|
||||
throws UnprocessableEntityException, OrmException, BadRequestException {
|
||||
if (!rsrc.getControl().forUser(anonymousProvider.get()).isVisible(dbProvider.get())) {
|
||||
throw new BadRequestException("change is not publicly visible");
|
||||
}
|
||||
if (!migration.readChanges()) {
|
||||
throw new BadRequestException("feature only supported in NoteDb");
|
||||
}
|
||||
Address adr;
|
||||
ListMultimap<RecipientType, Account.Id> accountsToNotify,
|
||||
boolean allowGroup,
|
||||
boolean allowByEmail)
|
||||
throws OrmException, PermissionBackendException {
|
||||
Account.Id accountId = null;
|
||||
try {
|
||||
adr = Address.parse(reviewer);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnprocessableEntityException(String.format("email invalid %s", reviewer));
|
||||
accountId = accounts.parse(reviewer).getAccountId();
|
||||
} catch (UnprocessableEntityException | AuthException e) {
|
||||
// AuthException won't occur since the user is authenticated at this point.
|
||||
if (!allowGroup && !allowByEmail) {
|
||||
// Only return failure if we aren't going to try other interpretations.
|
||||
return fail(
|
||||
reviewer, MessageFormat.format(ChangeMessages.get().reviewerNotFoundUser, reviewer));
|
||||
}
|
||||
if (!validator.isValid(adr.getEmail())) {
|
||||
throw new UnprocessableEntityException(String.format("email invalid %s", reviewer));
|
||||
}
|
||||
return new Addition(
|
||||
reviewer, rsrc, null, ImmutableList.of(adr), state, notify, accountsToNotify);
|
||||
return null;
|
||||
}
|
||||
|
||||
ReviewerResource rrsrc = reviewerFactory.create(rsrc, accountId);
|
||||
Account member = rrsrc.getReviewerUser().getAccount();
|
||||
PermissionBackend.ForRef perm =
|
||||
permissionBackend.user(rrsrc.getReviewerUser()).ref(rrsrc.getChange().getDest());
|
||||
if (isValidReviewer(member, perm)) {
|
||||
return new Addition(
|
||||
reviewer, rsrc, ImmutableSet.of(member.getId()), null, state, notify, accountsToNotify);
|
||||
}
|
||||
if (!member.isActive()) {
|
||||
return fail(reviewer, MessageFormat.format(ChangeMessages.get().reviewerInactive, reviewer));
|
||||
}
|
||||
return fail(
|
||||
reviewer, MessageFormat.format(ChangeMessages.get().reviewerCantSeeChange, reviewer));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Addition addWholeGroup(
|
||||
String reviewer,
|
||||
ChangeResource rsrc,
|
||||
ReviewerState state,
|
||||
NotifyHandling notify,
|
||||
ListMultimap<RecipientType, Account.Id> accountsToNotify,
|
||||
boolean confirmed,
|
||||
boolean allowGroup,
|
||||
boolean allowByEmail)
|
||||
throws OrmException, IOException, PermissionBackendException {
|
||||
if (!allowGroup) {
|
||||
return null;
|
||||
}
|
||||
|
||||
GroupDescription.Basic group = null;
|
||||
try {
|
||||
group = groupsCollection.parseInternal(reviewer);
|
||||
} catch (UnprocessableEntityException e) {
|
||||
if (!allowByEmail) {
|
||||
return fail(
|
||||
reviewer,
|
||||
MessageFormat.format(ChangeMessages.get().reviewerNotFoundUserOrGroup, reviewer));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Addition putGroup(ChangeResource rsrc, AddReviewerInput input)
|
||||
throws RestApiException, OrmException, IOException, PermissionBackendException {
|
||||
GroupDescription.Basic group = groupsCollection.parseInternal(input.reviewer);
|
||||
if (!isLegalReviewerGroup(group.getGroupUUID())) {
|
||||
return fail(
|
||||
input.reviewer,
|
||||
MessageFormat.format(ChangeMessages.get().groupIsNotAllowed, group.getName()));
|
||||
reviewer, MessageFormat.format(ChangeMessages.get().groupIsNotAllowed, group.getName()));
|
||||
}
|
||||
|
||||
Set<Account.Id> reviewers = new HashSet<>();
|
||||
@@ -319,9 +287,11 @@ public class PostReviewers implements RestModifyView<ChangeResource, AddReviewer
|
||||
.create(control.getUser())
|
||||
.listAccounts(group.getGroupUUID(), control.getProject().getNameKey());
|
||||
} catch (NoSuchGroupException e) {
|
||||
throw new UnprocessableEntityException(e.getMessage());
|
||||
return fail(
|
||||
reviewer,
|
||||
MessageFormat.format(ChangeMessages.get().reviewerNotFoundUserOrGroup, group.getName()));
|
||||
} catch (NoSuchProjectException e) {
|
||||
throw new BadRequestException(e.getMessage());
|
||||
return fail(reviewer, e.getMessage());
|
||||
}
|
||||
|
||||
// if maxAllowed is set to 0, it is allowed to add any number of
|
||||
@@ -329,18 +299,16 @@ public class PostReviewers implements RestModifyView<ChangeResource, AddReviewer
|
||||
int maxAllowed = cfg.getInt("addreviewer", "maxAllowed", DEFAULT_MAX_REVIEWERS);
|
||||
if (maxAllowed > 0 && members.size() > maxAllowed) {
|
||||
return fail(
|
||||
input.reviewer,
|
||||
reviewer,
|
||||
MessageFormat.format(ChangeMessages.get().groupHasTooManyMembers, group.getName()));
|
||||
}
|
||||
|
||||
// if maxWithoutCheck is set to 0, we never ask for confirmation
|
||||
int maxWithoutConfirmation =
|
||||
cfg.getInt("addreviewer", "maxWithoutConfirmation", DEFAULT_MAX_REVIEWERS_WITHOUT_CHECK);
|
||||
if (!input.confirmed()
|
||||
&& maxWithoutConfirmation > 0
|
||||
&& members.size() > maxWithoutConfirmation) {
|
||||
if (!confirmed && maxWithoutConfirmation > 0 && members.size() > maxWithoutConfirmation) {
|
||||
return fail(
|
||||
input.reviewer,
|
||||
reviewer,
|
||||
true,
|
||||
MessageFormat.format(
|
||||
ChangeMessages.get().groupManyMembersConfirmation, group.getName(), members.size()));
|
||||
@@ -354,14 +322,32 @@ public class PostReviewers implements RestModifyView<ChangeResource, AddReviewer
|
||||
}
|
||||
}
|
||||
|
||||
return new Addition(reviewer, rsrc, reviewers, null, state, notify, accountsToNotify);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Addition addByEmail(
|
||||
String reviewer,
|
||||
ChangeResource rsrc,
|
||||
ReviewerState state,
|
||||
NotifyHandling notify,
|
||||
ListMultimap<RecipientType, Account.Id> accountsToNotify)
|
||||
throws OrmException {
|
||||
if (!rsrc.getControl().forUser(anonymousProvider.get()).isVisible(dbProvider.get())) {
|
||||
return fail(
|
||||
reviewer, MessageFormat.format(ChangeMessages.get().reviewerCantSeeChange, reviewer));
|
||||
}
|
||||
if (!migration.readChanges()) {
|
||||
// addByEmail depends on NoteDb.
|
||||
return fail(
|
||||
reviewer, MessageFormat.format(ChangeMessages.get().reviewerNotFoundUser, reviewer));
|
||||
}
|
||||
Address adr = Address.tryParse(reviewer);
|
||||
if (adr == null || !validator.isValid(adr.getEmail())) {
|
||||
return fail(reviewer, MessageFormat.format(ChangeMessages.get().reviewerInvalid, reviewer));
|
||||
}
|
||||
return new Addition(
|
||||
input.reviewer,
|
||||
rsrc,
|
||||
reviewers,
|
||||
null,
|
||||
input.state(),
|
||||
input.notify,
|
||||
notifyUtil.resolveAccounts(input.notifyDetails));
|
||||
reviewer, rsrc, null, ImmutableList.of(adr), state, notify, accountsToNotify);
|
||||
}
|
||||
|
||||
private boolean isValidReviewer(Account member, PermissionBackend.ForRef perm)
|
||||
|
@@ -108,7 +108,7 @@ public class PutAssignee
|
||||
}
|
||||
|
||||
private Addition addAssigneeAsCC(ChangeResource rsrc, String assignee)
|
||||
throws OrmException, RestApiException, IOException, PermissionBackendException {
|
||||
throws OrmException, IOException, PermissionBackendException {
|
||||
AddReviewerInput reviewerInput = new AddReviewerInput();
|
||||
reviewerInput.reviewer = assignee;
|
||||
reviewerInput.state = ReviewerState.CC;
|
||||
|
@@ -1,6 +1,10 @@
|
||||
# Changes to this file should also be made in
|
||||
# gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeMessages.properties
|
||||
revertChangeDefaultMessage = Revert \"{0}\"\n\nThis reverts commit {1}.
|
||||
|
||||
reviewerCantSeeChange = {0} does not have permission to see this change
|
||||
reviewerInactive = {0} identifies an inactive account
|
||||
reviewerInvalid = {0} is not a valid user identifier
|
||||
reviewerNotFoundUser = {0} does not identify a registered user
|
||||
reviewerNotFoundUserOrGroup = {0} does not identify a registered user or group
|
||||
|
||||
|
Reference in New Issue
Block a user