blob: da5259690370efaf65df7cbd6947fb936e2867b7 [file] [log] [blame]
// Copyright (C) 2008 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.httpd.rpc.patch;
import com.google.gerrit.common.data.ReviewerResult;
import com.google.gerrit.common.data.ApprovalSummary;
import com.google.gerrit.common.data.ApprovalSummarySet;
import com.google.gerrit.common.data.ApprovalTypes;
import com.google.gerrit.common.data.PatchDetailService;
import com.google.gerrit.common.data.PatchScript;
import com.google.gerrit.common.errors.NoSuchEntityException;
import com.google.gerrit.httpd.rpc.BaseServiceImplementation;
import com.google.gerrit.httpd.rpc.Handler;
import com.google.gerrit.reviewdb.Account;
import com.google.gerrit.reviewdb.AccountDiffPreference;
import com.google.gerrit.reviewdb.AccountPatchReview;
import com.google.gerrit.reviewdb.ApprovalCategory;
import com.google.gerrit.reviewdb.ApprovalCategoryValue;
import com.google.gerrit.reviewdb.Change;
import com.google.gerrit.reviewdb.Patch;
import com.google.gerrit.reviewdb.PatchLineComment;
import com.google.gerrit.reviewdb.PatchSet;
import com.google.gerrit.reviewdb.PatchSetApproval;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.Patch.Key;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.AccountInfoCacheFactory;
import com.google.gerrit.server.patch.PublishComments;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.workflow.FunctionState;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwtjsonrpc.client.VoidResult;
import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
class PatchDetailServiceImpl extends BaseServiceImplementation implements
PatchDetailService {
private final ApprovalTypes approvalTypes;
private final AccountInfoCacheFactory.Factory accountInfoCacheFactory;
private final AddReviewer.Factory addReviewerFactory;
private final ChangeControl.Factory changeControlFactory;
private final RemoveReviewer.Factory removeReviewerFactory;
private final FunctionState.Factory functionStateFactory;
private final PublishComments.Factory publishCommentsFactory;
private final PatchScriptFactory.Factory patchScriptFactoryFactory;
private final SaveDraft.Factory saveDraftFactory;
@Inject
PatchDetailServiceImpl(final Provider<ReviewDb> schema,
final Provider<CurrentUser> currentUser,
final ApprovalTypes approvalTypes,
final AccountInfoCacheFactory.Factory accountInfoCacheFactory,
final AddReviewer.Factory addReviewerFactory,
final RemoveReviewer.Factory removeReviewerFactory,
final ChangeControl.Factory changeControlFactory,
final FunctionState.Factory functionStateFactory,
final PatchScriptFactory.Factory patchScriptFactoryFactory,
final PublishComments.Factory publishCommentsFactory,
final SaveDraft.Factory saveDraftFactory) {
super(schema, currentUser);
this.approvalTypes = approvalTypes;
this.accountInfoCacheFactory = accountInfoCacheFactory;
this.addReviewerFactory = addReviewerFactory;
this.removeReviewerFactory = removeReviewerFactory;
this.changeControlFactory = changeControlFactory;
this.functionStateFactory = functionStateFactory;
this.patchScriptFactoryFactory = patchScriptFactoryFactory;
this.publishCommentsFactory = publishCommentsFactory;
this.saveDraftFactory = saveDraftFactory;
}
public void patchScript(final Patch.Key patchKey, final PatchSet.Id psa,
final PatchSet.Id psb, final AccountDiffPreference dp,
final AsyncCallback<PatchScript> callback) {
if (psb == null) {
callback.onFailure(new NoSuchEntityException());
return;
}
patchScriptFactoryFactory.create(patchKey, psa, psb, dp).to(callback);
}
public void saveDraft(final PatchLineComment comment,
final AsyncCallback<PatchLineComment> callback) {
saveDraftFactory.create(comment).to(callback);
}
public void deleteDraft(final PatchLineComment.Key commentKey,
final AsyncCallback<VoidResult> callback) {
run(callback, new Action<VoidResult>() {
public VoidResult run(ReviewDb db) throws OrmException, Failure {
final PatchLineComment comment = db.patchComments().get(commentKey);
if (comment == null) {
throw new Failure(new NoSuchEntityException());
}
if (!getAccountId().equals(comment.getAuthor())) {
throw new Failure(new NoSuchEntityException());
}
if (comment.getStatus() != PatchLineComment.Status.DRAFT) {
throw new Failure(new IllegalStateException("Comment published"));
}
db.patchComments().delete(Collections.singleton(comment));
return VoidResult.INSTANCE;
}
});
}
public void publishComments(final PatchSet.Id psid, final String msg,
final Set<ApprovalCategoryValue.Id> tags,
final AsyncCallback<VoidResult> cb) {
Handler.wrap(publishCommentsFactory.create(psid, msg, tags)).to(cb);
}
/**
* Update the reviewed status for the file by user @code{account}
*/
public void setReviewedByCurrentUser(final Key patchKey,
final boolean reviewed, AsyncCallback<VoidResult> callback) {
run(callback, new Action<VoidResult>() {
public VoidResult run(ReviewDb db) throws OrmException {
Account.Id account = getAccountId();
AccountPatchReview.Key key =
new AccountPatchReview.Key(patchKey, account);
AccountPatchReview apr = db.accountPatchReviews().get(key);
if (apr == null && reviewed) {
db.accountPatchReviews().insert(
Collections.singleton(new AccountPatchReview(patchKey, account)));
} else if (apr != null && !reviewed) {
db.accountPatchReviews().delete(Collections.singleton(apr));
}
return VoidResult.INSTANCE;
}
});
}
public void addReviewers(final Change.Id id, final List<String> reviewers,
final AsyncCallback<ReviewerResult> callback) {
addReviewerFactory.create(id, reviewers).to(callback);
}
public void removeReviewer(final Change.Id id, final Account.Id reviewerId,
final AsyncCallback<ReviewerResult> callback) {
removeReviewerFactory.create(id, reviewerId).to(callback);
}
public void userApprovals(final Set<Change.Id> cids, final Account.Id aid,
final AsyncCallback<ApprovalSummarySet> callback) {
run(callback, new Action<ApprovalSummarySet>() {
public ApprovalSummarySet run(ReviewDb db) throws OrmException {
final Map<Change.Id, ApprovalSummary> approvals =
new HashMap<Change.Id, ApprovalSummary>();
final AccountInfoCacheFactory aicFactory =
accountInfoCacheFactory.create();
aicFactory.want(aid);
for (final Change.Id id : cids) {
try {
final ChangeControl cc = changeControlFactory.validateFor(id);
final Change change = cc.getChange();
final PatchSet.Id ps_id = change.currentPatchSetId();
final Map<ApprovalCategory.Id, PatchSetApproval> psas =
new HashMap<ApprovalCategory.Id, PatchSetApproval>();
final FunctionState fs =
functionStateFactory.create(change, ps_id, psas.values());
for (final PatchSetApproval ca : db.patchSetApprovals()
.byPatchSetUser(ps_id, aid)) {
final ApprovalCategory.Id category = ca.getCategoryId();
if (change.getStatus().isOpen()) {
fs.normalize(approvalTypes.getApprovalType(category), ca);
}
if (ca.getValue() == 0
|| ApprovalCategory.SUBMIT.equals(category)) {
continue;
}
psas.put(category, ca);
}
approvals.put(id, new ApprovalSummary(psas.values()));
} catch (NoSuchChangeException nsce) {
/*
* The user has no access to see this change, so we simply do not
* provide any details about it.
*/
}
}
return new ApprovalSummarySet(aicFactory.create(), approvals);
}
});
}
public void strongestApprovals(final Set<Change.Id> cids,
final AsyncCallback<ApprovalSummarySet> callback) {
run(callback, new Action<ApprovalSummarySet>() {
public ApprovalSummarySet run(ReviewDb db) throws OrmException {
final Map<Change.Id, ApprovalSummary> approvals =
new HashMap<Change.Id, ApprovalSummary>();
final AccountInfoCacheFactory aicFactory =
accountInfoCacheFactory.create();
for (final Change.Id id : cids) {
try {
final ChangeControl cc = changeControlFactory.validateFor(id);
final Change change = cc.getChange();
final PatchSet.Id ps_id = change.currentPatchSetId();
final Map<ApprovalCategory.Id, PatchSetApproval> psas =
new HashMap<ApprovalCategory.Id, PatchSetApproval>();
final FunctionState fs =
functionStateFactory.create(change, ps_id, psas.values());
for (PatchSetApproval ca : db.patchSetApprovals().byPatchSet(ps_id)) {
final ApprovalCategory.Id category = ca.getCategoryId();
if (change.getStatus().isOpen()) {
fs.normalize(approvalTypes.getApprovalType(category), ca);
}
if (ca.getValue() == 0
|| ApprovalCategory.SUBMIT.equals(category)) {
continue;
}
boolean keep = true;
if (psas.containsKey(category)) {
final short oldValue = psas.get(category).getValue();
final short newValue = ca.getValue();
keep =
(Math.abs(oldValue) < Math.abs(newValue))
|| ((Math.abs(oldValue) == Math.abs(newValue) && (newValue < oldValue)));
}
if (keep) {
aicFactory.want(ca.getAccountId());
psas.put(category, ca);
}
}
approvals.put(id, new ApprovalSummary(psas.values()));
} catch (NoSuchChangeException nsce) {
/*
* The user has no access to see this change, so we simply do not
* provide any details about it.
*/
}
}
return new ApprovalSummarySet(aicFactory.create(), approvals);
}
});
}
}