StreamEventsApiListener: Emit event on deletion of vote

Bug: Issue 6745
Change-Id: Idc9756c305cae57e93bb4f48468e273208467644
This commit is contained in:
David Pursehouse
2017-07-19 16:19:41 +09:00
parent f29d92a82f
commit 94b76cf24c
6 changed files with 97 additions and 10 deletions

View File

@@ -281,6 +281,24 @@ oldTopic:: Topic name before it was changed.
eventCreatedOn:: Time in seconds since the UNIX epoch when this event was eventCreatedOn:: Time in seconds since the UNIX epoch when this event was
created. created.
=== Vote Deleted
Sent when a vote was removed from a change.
type:: "vote-deleted"
change:: link:json.html#change[change attribute]
patchSet:: link:json.html#patchSet[patchSet attribute]
reviewer:: user whose vote was removed as link:json.html#account[account attribute]
remover:: user who removed the vote as link:json.html#account[account attribute]
approvals:: all votes as link:json.html#approval[approval attributes]
comment:: Review comment cover message.
== SEE ALSO == SEE ALSO
* link:json.html[JSON Data Formats] * link:json.html[JSON Data Formats]

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.extensions.events; package com.google.gerrit.extensions.events;
import com.google.gerrit.extensions.annotations.ExtensionPoint; import com.google.gerrit.extensions.annotations.ExtensionPoint;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ApprovalInfo; import com.google.gerrit.extensions.common.ApprovalInfo;
import java.util.Map; import java.util.Map;
@@ -27,6 +28,8 @@ public interface VoteDeletedListener {
Map<String, ApprovalInfo> getApprovals(); Map<String, ApprovalInfo> getApprovals();
String getMessage(); String getMessage();
AccountInfo getReviewer();
} }
void onVoteDeleted(Event event); void onVoteDeleted(Event event);

View File

@@ -116,7 +116,7 @@ public class DeleteVote implements RestModifyView<VoteResource, DeleteVoteInput>
try (BatchUpdate bu = try (BatchUpdate bu =
batchUpdateFactory.create( batchUpdateFactory.create(
db.get(), change.getProject(), r.getControl().getUser(), TimeUtil.nowTs())) { db.get(), change.getProject(), r.getControl().getUser(), TimeUtil.nowTs())) {
bu.addOp(change.getId(), new Op(r.getReviewerUser().getAccountId(), rsrc.getLabel(), input)); bu.addOp(change.getId(), new Op(r.getReviewerUser().getAccount(), rsrc.getLabel(), input));
bu.execute(); bu.execute();
} }
@@ -124,7 +124,7 @@ public class DeleteVote implements RestModifyView<VoteResource, DeleteVoteInput>
} }
private class Op implements BatchUpdateOp { private class Op implements BatchUpdateOp {
private final Account.Id accountId; private final Account account;
private final String label; private final String label;
private final DeleteVoteInput input; private final DeleteVoteInput input;
private ChangeMessage changeMessage; private ChangeMessage changeMessage;
@@ -133,8 +133,8 @@ public class DeleteVote implements RestModifyView<VoteResource, DeleteVoteInput>
private Map<String, Short> newApprovals = new HashMap<>(); private Map<String, Short> newApprovals = new HashMap<>();
private Map<String, Short> oldApprovals = new HashMap<>(); private Map<String, Short> oldApprovals = new HashMap<>();
private Op(Account.Id accountId, String label, DeleteVoteInput input) { private Op(Account account, String label, DeleteVoteInput input) {
this.accountId = accountId; this.account = account;
this.label = label; this.label = label;
this.input = input; this.input = input;
} }
@@ -150,7 +150,8 @@ public class DeleteVote implements RestModifyView<VoteResource, DeleteVoteInput>
boolean found = false; boolean found = false;
LabelTypes labelTypes = ctx.getControl().getLabelTypes(); LabelTypes labelTypes = ctx.getControl().getLabelTypes();
for (PatchSetApproval a : approvalsUtil.byPatchSetUser(ctx.getDb(), ctl, psId, accountId)) { for (PatchSetApproval a :
approvalsUtil.byPatchSetUser(ctx.getDb(), ctl, psId, account.getId())) {
if (labelTypes.byLabel(a.getLabelId()) == null) { if (labelTypes.byLabel(a.getLabelId()) == null) {
continue; // Ignore undefined labels. continue; // Ignore undefined labels.
} else if (!a.getLabel().equals(label)) { } else if (!a.getLabel().equals(label)) {
@@ -172,13 +173,13 @@ public class DeleteVote implements RestModifyView<VoteResource, DeleteVoteInput>
throw new ResourceNotFoundException(); throw new ResourceNotFoundException();
} }
ctx.getUpdate(psId).removeApprovalFor(accountId, label); ctx.getUpdate(psId).removeApprovalFor(account.getId(), label);
ctx.getDb().patchSetApprovals().upsert(Collections.singleton(deletedApproval(ctx))); ctx.getDb().patchSetApprovals().upsert(Collections.singleton(deletedApproval(ctx)));
StringBuilder msg = new StringBuilder(); StringBuilder msg = new StringBuilder();
msg.append("Removed "); msg.append("Removed ");
LabelVote.appendTo(msg, label, checkNotNull(oldApprovals.get(label))); LabelVote.appendTo(msg, label, checkNotNull(oldApprovals.get(label)));
msg.append(" by ").append(userFactory.create(accountId).getNameEmail()).append("\n"); msg.append(" by ").append(userFactory.create(account.getId()).getNameEmail()).append("\n");
changeMessage = changeMessage =
ChangeMessagesUtil.newMessage(ctx, msg.toString(), ChangeMessagesUtil.TAG_DELETE_VOTE); ChangeMessagesUtil.newMessage(ctx, msg.toString(), ChangeMessagesUtil.TAG_DELETE_VOTE);
cmUtil.addChangeMessage(ctx.getDb(), ctx.getUpdate(psId), changeMessage); cmUtil.addChangeMessage(ctx.getDb(), ctx.getUpdate(psId), changeMessage);
@@ -191,7 +192,7 @@ public class DeleteVote implements RestModifyView<VoteResource, DeleteVoteInput>
// set the real user; this preserves the calling user as the NoteDb // set the real user; this preserves the calling user as the NoteDb
// committer. // committer.
return new PatchSetApproval( return new PatchSetApproval(
new PatchSetApproval.Key(ps.getId(), accountId, new LabelId(label)), new PatchSetApproval.Key(ps.getId(), account.getId(), new LabelId(label)),
(short) 0, (short) 0,
ctx.getWhen()); ctx.getWhen());
} }
@@ -219,6 +220,7 @@ public class DeleteVote implements RestModifyView<VoteResource, DeleteVoteInput>
voteDeleted.fire( voteDeleted.fire(
change, change,
ps, ps,
account,
newApprovals, newApprovals,
oldApprovals, oldApprovals,
input.notify, input.notify,

View File

@@ -37,6 +37,7 @@ import com.google.gerrit.extensions.events.ReviewerAddedListener;
import com.google.gerrit.extensions.events.ReviewerDeletedListener; import com.google.gerrit.extensions.events.ReviewerDeletedListener;
import com.google.gerrit.extensions.events.RevisionCreatedListener; import com.google.gerrit.extensions.events.RevisionCreatedListener;
import com.google.gerrit.extensions.events.TopicEditedListener; import com.google.gerrit.extensions.events.TopicEditedListener;
import com.google.gerrit.extensions.events.VoteDeletedListener;
import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
@@ -84,7 +85,8 @@ public class StreamEventsApiListener
ReviewerAddedListener, ReviewerAddedListener,
ReviewerDeletedListener, ReviewerDeletedListener,
RevisionCreatedListener, RevisionCreatedListener,
TopicEditedListener { TopicEditedListener,
VoteDeletedListener {
private static final Logger log = LoggerFactory.getLogger(StreamEventsApiListener.class); private static final Logger log = LoggerFactory.getLogger(StreamEventsApiListener.class);
public static class Module extends AbstractModule { public static class Module extends AbstractModule {
@@ -104,6 +106,7 @@ public class StreamEventsApiListener
DynamicSet.bind(binder(), ReviewerDeletedListener.class).to(StreamEventsApiListener.class); DynamicSet.bind(binder(), ReviewerDeletedListener.class).to(StreamEventsApiListener.class);
DynamicSet.bind(binder(), RevisionCreatedListener.class).to(StreamEventsApiListener.class); DynamicSet.bind(binder(), RevisionCreatedListener.class).to(StreamEventsApiListener.class);
DynamicSet.bind(binder(), TopicEditedListener.class).to(StreamEventsApiListener.class); DynamicSet.bind(binder(), TopicEditedListener.class).to(StreamEventsApiListener.class);
DynamicSet.bind(binder(), VoteDeletedListener.class).to(StreamEventsApiListener.class);
} }
} }
@@ -473,4 +476,24 @@ public class StreamEventsApiListener
log.error("Failed to dispatch event", e); log.error("Failed to dispatch event", e);
} }
} }
@Override
public void onVoteDeleted(VoteDeletedListener.Event ev) {
try {
ChangeNotes notes = getNotes(ev.getChange());
Change change = notes.getChange();
VoteDeletedEvent event = new VoteDeletedEvent(change);
event.change = changeAttributeSupplier(change);
event.patchSet = patchSetAttributeSupplier(change, psUtil.current(db.get(), notes));
event.comment = ev.getMessage();
event.reviewer = accountAttributeSupplier(ev.getReviewer());
event.remover = accountAttributeSupplier(ev.getWho());
event.approvals = approvalsAttributeSupplier(change, ev.getApprovals(), ev.getOldApprovals());
dispatcher.get().postEvent(change, event);
} catch (OrmException e) {
log.error("Failed to dispatch event", e);
}
}
} }

View File

@@ -0,0 +1,32 @@
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.data.AccountAttribute;
import com.google.gerrit.server.data.ApprovalAttribute;
public class VoteDeletedEvent extends PatchSetEvent {
static final String TYPE = "vote-deleted";
public Supplier<AccountAttribute> reviewer;
public Supplier<AccountAttribute> remover;
public Supplier<ApprovalAttribute[]> approvals;
public String comment;
public VoteDeletedEvent(Change change) {
super(TYPE, change);
}
}

View File

@@ -49,6 +49,7 @@ public class VoteDeleted {
public void fire( public void fire(
Change change, Change change,
PatchSet ps, PatchSet ps,
Account reviewer,
Map<String, Short> approvals, Map<String, Short> approvals,
Map<String, Short> oldApprovals, Map<String, Short> oldApprovals,
NotifyHandling notify, NotifyHandling notify,
@@ -63,6 +64,7 @@ public class VoteDeleted {
new Event( new Event(
util.changeInfo(change), util.changeInfo(change),
util.revisionInfo(change.getProject(), ps), util.revisionInfo(change.getProject(), ps),
util.accountInfo(reviewer),
util.approvals(remover, approvals, when), util.approvals(remover, approvals, when),
util.approvals(remover, oldApprovals, when), util.approvals(remover, oldApprovals, when),
notify, notify,
@@ -82,7 +84,7 @@ public class VoteDeleted {
} }
private static class Event extends AbstractRevisionEvent implements VoteDeletedListener.Event { private static class Event extends AbstractRevisionEvent implements VoteDeletedListener.Event {
private final AccountInfo reviewer;
private final Map<String, ApprovalInfo> approvals; private final Map<String, ApprovalInfo> approvals;
private final Map<String, ApprovalInfo> oldApprovals; private final Map<String, ApprovalInfo> oldApprovals;
private final String message; private final String message;
@@ -90,6 +92,7 @@ public class VoteDeleted {
Event( Event(
ChangeInfo change, ChangeInfo change,
RevisionInfo revision, RevisionInfo revision,
AccountInfo reviewer,
Map<String, ApprovalInfo> approvals, Map<String, ApprovalInfo> approvals,
Map<String, ApprovalInfo> oldApprovals, Map<String, ApprovalInfo> oldApprovals,
NotifyHandling notify, NotifyHandling notify,
@@ -97,6 +100,7 @@ public class VoteDeleted {
AccountInfo remover, AccountInfo remover,
Timestamp when) { Timestamp when) {
super(change, revision, remover, when, notify); super(change, revision, remover, when, notify);
this.reviewer = reviewer;
this.approvals = approvals; this.approvals = approvals;
this.oldApprovals = oldApprovals; this.oldApprovals = oldApprovals;
this.message = message; this.message = message;
@@ -116,5 +120,10 @@ public class VoteDeleted {
public String getMessage() { public String getMessage() {
return message; return message;
} }
@Override
public AccountInfo getReviewer() {
return reviewer;
}
} }
} }