Hoist validation from SetAssigneeOp into PutAssignee
Performing validation of the new asignee inside the operation isn't necessary; it can be validated in the REST API handler as its parsing the input object and preparing the operation object. This signficantly cleans up the operation object, making it easier to follow the logic. This change also makes it easier to later refactor the check "can new assignee see the target branch", before the operation is even started. Change-Id: I3c8f3459300a670e8c76edff1262399de704933b
This commit is contained in:

committed by
David Pursehouse

parent
4778db67da
commit
8ca95f4e25
@@ -492,7 +492,7 @@ class ChangeApiImpl implements ChangeApi {
|
|||||||
@Override
|
@Override
|
||||||
public AccountInfo setAssignee(AssigneeInput input) throws RestApiException {
|
public AccountInfo setAssignee(AssigneeInput input) throws RestApiException {
|
||||||
try {
|
try {
|
||||||
return putAssignee.apply(change, input).value();
|
return putAssignee.apply(change, input);
|
||||||
} catch (UpdateException | IOException | OrmException e) {
|
} catch (UpdateException | IOException | OrmException e) {
|
||||||
throw new RestApiException("Cannot set assignee", e);
|
throw new RestApiException("Cannot set assignee", e);
|
||||||
}
|
}
|
||||||
|
@@ -22,12 +22,14 @@ import com.google.gerrit.extensions.client.ReviewerState;
|
|||||||
import com.google.gerrit.extensions.common.AccountInfo;
|
import com.google.gerrit.extensions.common.AccountInfo;
|
||||||
import com.google.gerrit.extensions.restapi.AuthException;
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
import com.google.gerrit.extensions.restapi.Response;
|
|
||||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||||
import com.google.gerrit.extensions.restapi.RestModifyView;
|
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||||
|
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
|
||||||
import com.google.gerrit.extensions.webui.UiAction;
|
import com.google.gerrit.extensions.webui.UiAction;
|
||||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||||
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
import com.google.gerrit.server.account.AccountLoader;
|
import com.google.gerrit.server.account.AccountLoader;
|
||||||
|
import com.google.gerrit.server.account.AccountsCollection;
|
||||||
import com.google.gerrit.server.change.PostReviewers.Addition;
|
import com.google.gerrit.server.change.PostReviewers.Addition;
|
||||||
import com.google.gerrit.server.update.BatchUpdate;
|
import com.google.gerrit.server.update.BatchUpdate;
|
||||||
import com.google.gerrit.server.update.UpdateException;
|
import com.google.gerrit.server.update.UpdateException;
|
||||||
@@ -41,6 +43,7 @@ import java.io.IOException;
|
|||||||
public class PutAssignee
|
public class PutAssignee
|
||||||
implements RestModifyView<ChangeResource, AssigneeInput>, UiAction<ChangeResource> {
|
implements RestModifyView<ChangeResource, AssigneeInput>, UiAction<ChangeResource> {
|
||||||
|
|
||||||
|
private final AccountsCollection accounts;
|
||||||
private final SetAssigneeOp.Factory assigneeFactory;
|
private final SetAssigneeOp.Factory assigneeFactory;
|
||||||
private final BatchUpdate.Factory batchUpdateFactory;
|
private final BatchUpdate.Factory batchUpdateFactory;
|
||||||
private final Provider<ReviewDb> db;
|
private final Provider<ReviewDb> db;
|
||||||
@@ -49,11 +52,13 @@ public class PutAssignee
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
PutAssignee(
|
PutAssignee(
|
||||||
|
AccountsCollection accounts,
|
||||||
SetAssigneeOp.Factory assigneeFactory,
|
SetAssigneeOp.Factory assigneeFactory,
|
||||||
BatchUpdate.Factory batchUpdateFactory,
|
BatchUpdate.Factory batchUpdateFactory,
|
||||||
Provider<ReviewDb> db,
|
Provider<ReviewDb> db,
|
||||||
PostReviewers postReviewers,
|
PostReviewers postReviewers,
|
||||||
AccountLoader.Factory accountLoaderFactory) {
|
AccountLoader.Factory accountLoaderFactory) {
|
||||||
|
this.accounts = accounts;
|
||||||
this.assigneeFactory = assigneeFactory;
|
this.assigneeFactory = assigneeFactory;
|
||||||
this.batchUpdateFactory = batchUpdateFactory;
|
this.batchUpdateFactory = batchUpdateFactory;
|
||||||
this.db = db;
|
this.db = db;
|
||||||
@@ -62,7 +67,7 @@ public class PutAssignee
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response<AccountInfo> apply(ChangeResource rsrc, AssigneeInput input)
|
public AccountInfo apply(ChangeResource rsrc, AssigneeInput input)
|
||||||
throws RestApiException, UpdateException, OrmException, IOException {
|
throws RestApiException, UpdateException, OrmException, IOException {
|
||||||
if (!rsrc.getControl().canEditAssignee()) {
|
if (!rsrc.getControl().canEditAssignee()) {
|
||||||
throw new AuthException("Changing Assignee not permitted");
|
throw new AuthException("Changing Assignee not permitted");
|
||||||
@@ -71,20 +76,30 @@ public class PutAssignee
|
|||||||
throw new BadRequestException("missing assignee field");
|
throw new BadRequestException("missing assignee field");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IdentifiedUser assignee = accounts.parse(input.assignee.trim());
|
||||||
|
if (!assignee.getAccount().isActive()) {
|
||||||
|
throw new UnprocessableEntityException(
|
||||||
|
String.format("Account of %s is not active", input.assignee));
|
||||||
|
}
|
||||||
|
if (!rsrc.getControl().forUser(assignee).isRefVisible()) {
|
||||||
|
throw new AuthException(
|
||||||
|
String.format("Change %s is not visible to %s.", rsrc.getId(), input.assignee));
|
||||||
|
}
|
||||||
|
|
||||||
try (BatchUpdate bu =
|
try (BatchUpdate bu =
|
||||||
batchUpdateFactory.create(
|
batchUpdateFactory.create(
|
||||||
db.get(),
|
db.get(),
|
||||||
rsrc.getChange().getProject(),
|
rsrc.getChange().getProject(),
|
||||||
rsrc.getControl().getUser(),
|
rsrc.getControl().getUser(),
|
||||||
TimeUtil.nowTs())) {
|
TimeUtil.nowTs())) {
|
||||||
SetAssigneeOp op = assigneeFactory.create(input.assignee);
|
SetAssigneeOp op = assigneeFactory.create(assignee);
|
||||||
bu.addOp(rsrc.getId(), op);
|
bu.addOp(rsrc.getId(), op);
|
||||||
|
|
||||||
PostReviewers.Addition reviewersAddition = addAssigneeAsCC(rsrc, input.assignee);
|
PostReviewers.Addition reviewersAddition = addAssigneeAsCC(rsrc, input.assignee);
|
||||||
bu.addOp(rsrc.getId(), reviewersAddition.op);
|
bu.addOp(rsrc.getId(), reviewersAddition.op);
|
||||||
|
|
||||||
bu.execute();
|
bu.execute();
|
||||||
return Response.ok(accountLoaderFactory.create(true).fillOne(op.getNewAssignee()));
|
return accountLoaderFactory.create(true).fillOne(assignee.getAccountId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,16 +17,12 @@ package com.google.gerrit.server.change;
|
|||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||||
import com.google.gerrit.extensions.restapi.AuthException;
|
|
||||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
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.Change;
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
import com.google.gerrit.reviewdb.client.ChangeMessage;
|
import com.google.gerrit.reviewdb.client.ChangeMessage;
|
||||||
import com.google.gerrit.server.ChangeMessagesUtil;
|
import com.google.gerrit.server.ChangeMessagesUtil;
|
||||||
import com.google.gerrit.server.IdentifiedUser;
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
import com.google.gerrit.server.account.AccountsCollection;
|
|
||||||
import com.google.gerrit.server.extensions.events.AssigneeChanged;
|
import com.google.gerrit.server.extensions.events.AssigneeChanged;
|
||||||
import com.google.gerrit.server.mail.send.SetAssigneeSender;
|
import com.google.gerrit.server.mail.send.SetAssigneeSender;
|
||||||
import com.google.gerrit.server.notedb.ChangeUpdate;
|
import com.google.gerrit.server.notedb.ChangeUpdate;
|
||||||
@@ -46,93 +42,74 @@ public class SetAssigneeOp implements BatchUpdateOp {
|
|||||||
private static final Logger log = LoggerFactory.getLogger(SetAssigneeOp.class);
|
private static final Logger log = LoggerFactory.getLogger(SetAssigneeOp.class);
|
||||||
|
|
||||||
public interface Factory {
|
public interface Factory {
|
||||||
SetAssigneeOp create(String assignee);
|
SetAssigneeOp create(IdentifiedUser assignee);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final AccountsCollection accounts;
|
|
||||||
private final ChangeMessagesUtil cmUtil;
|
private final ChangeMessagesUtil cmUtil;
|
||||||
private final DynamicSet<AssigneeValidationListener> validationListeners;
|
private final DynamicSet<AssigneeValidationListener> validationListeners;
|
||||||
private final String assignee;
|
private final IdentifiedUser newAssignee;
|
||||||
private final AssigneeChanged assigneeChanged;
|
private final AssigneeChanged assigneeChanged;
|
||||||
private final SetAssigneeSender.Factory setAssigneeSenderFactory;
|
private final SetAssigneeSender.Factory setAssigneeSenderFactory;
|
||||||
private final Provider<IdentifiedUser> user;
|
private final Provider<IdentifiedUser> user;
|
||||||
private final IdentifiedUser.GenericFactory userFactory;
|
private final IdentifiedUser.GenericFactory userFactory;
|
||||||
|
|
||||||
private Change change;
|
private Change change;
|
||||||
private Account newAssignee;
|
private IdentifiedUser oldAssignee;
|
||||||
private Account oldAssignee;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SetAssigneeOp(
|
SetAssigneeOp(
|
||||||
AccountsCollection accounts,
|
|
||||||
ChangeMessagesUtil cmUtil,
|
ChangeMessagesUtil cmUtil,
|
||||||
DynamicSet<AssigneeValidationListener> validationListeners,
|
DynamicSet<AssigneeValidationListener> validationListeners,
|
||||||
AssigneeChanged assigneeChanged,
|
AssigneeChanged assigneeChanged,
|
||||||
SetAssigneeSender.Factory setAssigneeSenderFactory,
|
SetAssigneeSender.Factory setAssigneeSenderFactory,
|
||||||
Provider<IdentifiedUser> user,
|
Provider<IdentifiedUser> user,
|
||||||
IdentifiedUser.GenericFactory userFactory,
|
IdentifiedUser.GenericFactory userFactory,
|
||||||
@Assisted String assignee) {
|
@Assisted IdentifiedUser newAssignee) {
|
||||||
this.accounts = accounts;
|
|
||||||
this.cmUtil = cmUtil;
|
this.cmUtil = cmUtil;
|
||||||
this.validationListeners = validationListeners;
|
this.validationListeners = validationListeners;
|
||||||
this.assigneeChanged = assigneeChanged;
|
this.assigneeChanged = assigneeChanged;
|
||||||
this.setAssigneeSenderFactory = setAssigneeSenderFactory;
|
this.setAssigneeSenderFactory = setAssigneeSenderFactory;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.userFactory = userFactory;
|
this.userFactory = userFactory;
|
||||||
this.assignee = checkNotNull(assignee);
|
this.newAssignee = checkNotNull(newAssignee, "assignee");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateChange(ChangeContext ctx) throws OrmException, RestApiException {
|
public boolean updateChange(ChangeContext ctx) throws OrmException, RestApiException {
|
||||||
change = ctx.getChange();
|
change = ctx.getChange();
|
||||||
ChangeUpdate update = ctx.getUpdate(change.currentPatchSetId());
|
if (newAssignee.getAccountId().equals(change.getAssignee())) {
|
||||||
IdentifiedUser newAssigneeUser = accounts.parse(assignee);
|
|
||||||
newAssignee = newAssigneeUser.getAccount();
|
|
||||||
IdentifiedUser oldAssigneeUser = null;
|
|
||||||
if (change.getAssignee() != null) {
|
|
||||||
oldAssigneeUser = userFactory.create(change.getAssignee());
|
|
||||||
oldAssignee = oldAssigneeUser.getAccount();
|
|
||||||
if (newAssignee.equals(oldAssignee)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!newAssignee.isActive()) {
|
|
||||||
throw new UnprocessableEntityException(
|
|
||||||
String.format("Account of %s is not active", assignee));
|
|
||||||
}
|
|
||||||
if (!ctx.getControl().forUser(newAssigneeUser).isRefVisible()) {
|
|
||||||
throw new AuthException(
|
|
||||||
String.format("Change %s is not visible to %s.", change.getChangeId(), assignee));
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
for (AssigneeValidationListener validator : validationListeners) {
|
for (AssigneeValidationListener validator : validationListeners) {
|
||||||
validator.validateAssignee(change, newAssignee);
|
validator.validateAssignee(change, newAssignee.getAccount());
|
||||||
}
|
}
|
||||||
} catch (ValidationException e) {
|
} catch (ValidationException e) {
|
||||||
throw new ResourceConflictException(e.getMessage());
|
throw new ResourceConflictException(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (change.getAssignee() != null) {
|
||||||
|
oldAssignee = userFactory.create(change.getAssignee());
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangeUpdate update = ctx.getUpdate(change.currentPatchSetId());
|
||||||
// notedb
|
// notedb
|
||||||
update.setAssignee(newAssignee.getId());
|
update.setAssignee(newAssignee.getAccountId());
|
||||||
// reviewdb
|
// reviewdb
|
||||||
change.setAssignee(newAssignee.getId());
|
change.setAssignee(newAssignee.getAccountId());
|
||||||
addMessage(ctx, update, oldAssigneeUser, newAssigneeUser);
|
addMessage(ctx, update);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMessage(
|
private void addMessage(ChangeContext ctx, ChangeUpdate update) throws OrmException {
|
||||||
ChangeContext ctx,
|
|
||||||
ChangeUpdate update,
|
|
||||||
IdentifiedUser previousAssignee,
|
|
||||||
IdentifiedUser newAssignee)
|
|
||||||
throws OrmException {
|
|
||||||
StringBuilder msg = new StringBuilder();
|
StringBuilder msg = new StringBuilder();
|
||||||
msg.append("Assignee ");
|
msg.append("Assignee ");
|
||||||
if (previousAssignee == null) {
|
if (oldAssignee == null) {
|
||||||
msg.append("added: ");
|
msg.append("added: ");
|
||||||
msg.append(newAssignee.getNameEmail());
|
msg.append(newAssignee.getNameEmail());
|
||||||
} else {
|
} else {
|
||||||
msg.append("changed from: ");
|
msg.append("changed from: ");
|
||||||
msg.append(previousAssignee.getNameEmail());
|
msg.append(oldAssignee.getNameEmail());
|
||||||
msg.append(" to: ");
|
msg.append(" to: ");
|
||||||
msg.append(newAssignee.getNameEmail());
|
msg.append(newAssignee.getNameEmail());
|
||||||
}
|
}
|
||||||
@@ -145,16 +122,17 @@ public class SetAssigneeOp implements BatchUpdateOp {
|
|||||||
public void postUpdate(Context ctx) throws OrmException {
|
public void postUpdate(Context ctx) throws OrmException {
|
||||||
try {
|
try {
|
||||||
SetAssigneeSender cm =
|
SetAssigneeSender cm =
|
||||||
setAssigneeSenderFactory.create(change.getProject(), change.getId(), newAssignee.getId());
|
setAssigneeSenderFactory.create(
|
||||||
|
change.getProject(), change.getId(), newAssignee.getAccountId());
|
||||||
cm.setFrom(user.get().getAccountId());
|
cm.setFrom(user.get().getAccountId());
|
||||||
cm.send();
|
cm.send();
|
||||||
} catch (Exception err) {
|
} catch (Exception err) {
|
||||||
log.error("Cannot send email to new assignee of change " + change.getId(), err);
|
log.error("Cannot send email to new assignee of change " + change.getId(), err);
|
||||||
}
|
}
|
||||||
assigneeChanged.fire(change, ctx.getAccount(), oldAssignee, ctx.getWhen());
|
assigneeChanged.fire(
|
||||||
}
|
change,
|
||||||
|
ctx.getAccount(),
|
||||||
public Account.Id getNewAssignee() {
|
oldAssignee != null ? oldAssignee.getAccount() : null,
|
||||||
return newAssignee != null ? newAssignee.getId() : null;
|
ctx.getWhen());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user