GET PUT DELETE Rest endpoints for change Assignee field
changes/<change-id>/assignee GET returns an AccountInfo: { "_account_id": 1000000, "email": "user@gerrit.com", "username": "user" } PUT takes an account identifier: name-email, email, full name, "self" and returns an AccountInfo for the user that is assigned after the call. Change-Id: Icce1be90c6c9558950502fe24435317e8372bb64
This commit is contained in:

committed by
David Pursehouse

parent
c11657426a
commit
076b5c8309
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (C) 2016 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.extensions.api.changes;
|
||||||
|
|
||||||
|
import com.google.gerrit.extensions.restapi.DefaultInput;
|
||||||
|
|
||||||
|
public class AssigneeInput {
|
||||||
|
@DefaultInput
|
||||||
|
public String assignee;
|
||||||
|
}
|
@@ -28,6 +28,7 @@ public class ChangeInfo {
|
|||||||
public String project;
|
public String project;
|
||||||
public String branch;
|
public String branch;
|
||||||
public String topic;
|
public String topic;
|
||||||
|
public AccountInfo assignee;
|
||||||
public Collection<String> hashtags;
|
public Collection<String> hashtags;
|
||||||
public String changeId;
|
public String changeId;
|
||||||
public String subject;
|
public String subject;
|
||||||
|
@@ -101,6 +101,8 @@ import com.google.gerrit.server.api.accounts.GpgApiAdapter;
|
|||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
import com.google.gerrit.server.git.LabelNormalizer;
|
import com.google.gerrit.server.git.LabelNormalizer;
|
||||||
import com.google.gerrit.server.git.MergeUtil;
|
import com.google.gerrit.server.git.MergeUtil;
|
||||||
|
import com.google.gerrit.server.index.change.ChangeField;
|
||||||
|
import com.google.gerrit.server.index.change.ChangeIndexCollection;
|
||||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||||
import com.google.gerrit.server.notedb.ReviewerStateInternal;
|
import com.google.gerrit.server.notedb.ReviewerStateInternal;
|
||||||
import com.google.gerrit.server.patch.PatchListNotAvailableException;
|
import com.google.gerrit.server.patch.PatchListNotAvailableException;
|
||||||
@@ -171,6 +173,7 @@ public class ChangeJson {
|
|||||||
private final ChangeNotes.Factory notesFactory;
|
private final ChangeNotes.Factory notesFactory;
|
||||||
private final ChangeResource.Factory changeResourceFactory;
|
private final ChangeResource.Factory changeResourceFactory;
|
||||||
private final ChangeKindCache changeKindCache;
|
private final ChangeKindCache changeKindCache;
|
||||||
|
private final ChangeIndexCollection indexes;
|
||||||
|
|
||||||
private boolean lazyLoad = true;
|
private boolean lazyLoad = true;
|
||||||
private AccountLoader accountLoader;
|
private AccountLoader accountLoader;
|
||||||
@@ -201,6 +204,7 @@ public class ChangeJson {
|
|||||||
ChangeNotes.Factory notesFactory,
|
ChangeNotes.Factory notesFactory,
|
||||||
ChangeResource.Factory changeResourceFactory,
|
ChangeResource.Factory changeResourceFactory,
|
||||||
ChangeKindCache changeKindCache,
|
ChangeKindCache changeKindCache,
|
||||||
|
ChangeIndexCollection indexes,
|
||||||
@Assisted Set<ListChangesOption> options) {
|
@Assisted Set<ListChangesOption> options) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.labelNormalizer = ln;
|
this.labelNormalizer = ln;
|
||||||
@@ -223,6 +227,7 @@ public class ChangeJson {
|
|||||||
this.notesFactory = notesFactory;
|
this.notesFactory = notesFactory;
|
||||||
this.changeResourceFactory = changeResourceFactory;
|
this.changeResourceFactory = changeResourceFactory;
|
||||||
this.changeKindCache = changeKindCache;
|
this.changeKindCache = changeKindCache;
|
||||||
|
this.indexes = indexes;
|
||||||
this.options = options.isEmpty()
|
this.options = options.isEmpty()
|
||||||
? EnumSet.noneOf(ListChangesOption.class)
|
? EnumSet.noneOf(ListChangesOption.class)
|
||||||
: EnumSet.copyOf(options);
|
: EnumSet.copyOf(options);
|
||||||
@@ -436,6 +441,11 @@ public class ChangeJson {
|
|||||||
out.project = in.getProject().get();
|
out.project = in.getProject().get();
|
||||||
out.branch = in.getDest().getShortName();
|
out.branch = in.getDest().getShortName();
|
||||||
out.topic = in.getTopic();
|
out.topic = in.getTopic();
|
||||||
|
if (indexes.getSearchIndex().getSchema().hasField(ChangeField.ASSIGNEE)) {
|
||||||
|
if (cd.assignee().isPresent()) {
|
||||||
|
out.assignee = accountLoader.get(cd.assignee().get());
|
||||||
|
}
|
||||||
|
}
|
||||||
out.hashtags = cd.hashtags();
|
out.hashtags = cd.hashtags();
|
||||||
out.changeId = in.getKey().get();
|
out.changeId = in.getKey().get();
|
||||||
if (in.getStatus().isOpen()) {
|
if (in.getStatus().isOpen()) {
|
||||||
|
@@ -0,0 +1,130 @@
|
|||||||
|
// Copyright (C) 2016 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.change;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.gerrit.common.TimeUtil;
|
||||||
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
|
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.RestModifyView;
|
||||||
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
|
import com.google.gerrit.reviewdb.client.ChangeMessage;
|
||||||
|
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||||
|
import com.google.gerrit.server.ChangeMessagesUtil;
|
||||||
|
import com.google.gerrit.server.ChangeUtil;
|
||||||
|
import com.google.gerrit.server.change.DeleteAssignee.Input;
|
||||||
|
import com.google.gerrit.server.account.AccountInfoCacheFactory;
|
||||||
|
import com.google.gerrit.server.account.AccountJson;
|
||||||
|
import com.google.gerrit.server.config.AnonymousCowardName;
|
||||||
|
import com.google.gerrit.server.git.BatchUpdate;
|
||||||
|
import com.google.gerrit.server.git.BatchUpdate.ChangeContext;
|
||||||
|
import com.google.gerrit.server.git.UpdateException;
|
||||||
|
import com.google.gerrit.server.notedb.ChangeUpdate;
|
||||||
|
import com.google.gerrit.server.notedb.NotesMigration;
|
||||||
|
import com.google.gwtorm.server.OrmException;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class DeleteAssignee implements
|
||||||
|
RestModifyView<ChangeResource, Input> {
|
||||||
|
public static class Input {
|
||||||
|
|
||||||
|
}
|
||||||
|
private BatchUpdate.Factory batchUpdateFactory;
|
||||||
|
private final NotesMigration notesMigration;
|
||||||
|
private final ChangeMessagesUtil cmUtil;
|
||||||
|
private final Provider<ReviewDb> db;
|
||||||
|
private final AccountInfoCacheFactory.Factory accountInfos;
|
||||||
|
private final String anonymousCowardName;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
DeleteAssignee(NotesMigration notesMigration,
|
||||||
|
BatchUpdate.Factory batchUpdateFactory,
|
||||||
|
ChangeMessagesUtil cmUtil,
|
||||||
|
Provider<ReviewDb> db,
|
||||||
|
AccountInfoCacheFactory.Factory accountInfosFactory,
|
||||||
|
@AnonymousCowardName String anonymousCowardName) {
|
||||||
|
this.batchUpdateFactory = batchUpdateFactory;
|
||||||
|
this.notesMigration = notesMigration;
|
||||||
|
this.cmUtil = cmUtil;
|
||||||
|
this.db = db;
|
||||||
|
this.accountInfos = accountInfosFactory;
|
||||||
|
this.anonymousCowardName = anonymousCowardName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object apply(ChangeResource rsrc, Input input)
|
||||||
|
throws RestApiException, UpdateException
|
||||||
|
{
|
||||||
|
try (BatchUpdate bu = batchUpdateFactory.create(db.get(),
|
||||||
|
rsrc.getProject(),
|
||||||
|
rsrc.getUser(), TimeUtil.nowTs())) {
|
||||||
|
Op op = new Op();
|
||||||
|
bu.addOp(rsrc.getChange().getId(), op);
|
||||||
|
bu.execute();
|
||||||
|
if (op.getDeletedAssignee() == null) {
|
||||||
|
return Response.none();
|
||||||
|
}
|
||||||
|
return Response.ok(AccountJson.toAccountInfo(op.getDeletedAssignee()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Op extends BatchUpdate.Op {
|
||||||
|
private Account deletedAssignee;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean updateChange(ChangeContext ctx)
|
||||||
|
throws RestApiException, OrmException{
|
||||||
|
if (!notesMigration.readChanges()) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"Cannot add Assignee; NoteDb is disabled");
|
||||||
|
}
|
||||||
|
if (!ctx.getControl().canEditAssignee()) {
|
||||||
|
throw new AuthException("Delete Assignee not permitted");
|
||||||
|
}
|
||||||
|
ChangeUpdate update = ctx.getUpdate(ctx.getChange().currentPatchSetId());
|
||||||
|
Optional<Account.Id> currentAssigneeId = update.getNotes().getAssignee();
|
||||||
|
if (!currentAssigneeId.isPresent()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Account account = accountInfos.create().get(currentAssigneeId.get());
|
||||||
|
update.setAssignee(Optional.absent());
|
||||||
|
addMessage(ctx, update, account);
|
||||||
|
deletedAssignee = account;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Account getDeletedAssignee() {
|
||||||
|
return deletedAssignee;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addMessage(BatchUpdate.ChangeContext ctx,
|
||||||
|
ChangeUpdate update, Account deleted) throws OrmException {
|
||||||
|
ChangeMessage cmsg = new ChangeMessage(
|
||||||
|
new ChangeMessage.Key(
|
||||||
|
ctx.getChange().getId(),
|
||||||
|
ChangeUtil.messageUUID(ctx.getDb())),
|
||||||
|
ctx.getAccountId(), ctx.getWhen(),
|
||||||
|
ctx.getChange().currentPatchSetId());
|
||||||
|
cmsg.setMessage(
|
||||||
|
"Assignee deleted: " + deleted.getName(anonymousCowardName));
|
||||||
|
cmUtil.addChangeMessage(ctx.getDb(), update, cmsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (C) 2016 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.change;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.gerrit.extensions.common.AccountInfo;
|
||||||
|
import com.google.gerrit.extensions.restapi.Response;
|
||||||
|
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||||
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
|
import com.google.gerrit.server.account.AccountInfoCacheFactory;
|
||||||
|
import com.google.gerrit.server.account.AccountJson;
|
||||||
|
import com.google.gwtorm.server.OrmException;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class GetAssignee implements RestReadView<ChangeResource> {
|
||||||
|
private final AccountInfoCacheFactory.Factory accountInfo;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
GetAssignee(AccountInfoCacheFactory.Factory accountInfo) {
|
||||||
|
this.accountInfo = accountInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response<AccountInfo> apply(ChangeResource rsrc) throws OrmException {
|
||||||
|
|
||||||
|
Optional<Account.Id> assignee =
|
||||||
|
rsrc.getControl().getNotes().load().getAssignee();
|
||||||
|
if (assignee.isPresent()) {
|
||||||
|
Account account = accountInfo.create().get(assignee.get());
|
||||||
|
return Response.ok(AccountJson.toAccountInfo(account));
|
||||||
|
}
|
||||||
|
return Response.none();
|
||||||
|
}
|
||||||
|
}
|
@@ -53,6 +53,9 @@ public class Module extends RestApiModule {
|
|||||||
get(CHANGE_KIND, "detail").to(GetDetail.class);
|
get(CHANGE_KIND, "detail").to(GetDetail.class);
|
||||||
get(CHANGE_KIND, "topic").to(GetTopic.class);
|
get(CHANGE_KIND, "topic").to(GetTopic.class);
|
||||||
get(CHANGE_KIND, "in").to(IncludedIn.class);
|
get(CHANGE_KIND, "in").to(IncludedIn.class);
|
||||||
|
get(CHANGE_KIND, "assignee").to(GetAssignee.class);
|
||||||
|
put(CHANGE_KIND, "assignee").to(PutAssignee.class);
|
||||||
|
delete(CHANGE_KIND, "assignee").to(DeleteAssignee.class);
|
||||||
get(CHANGE_KIND, "hashtags").to(GetHashtags.class);
|
get(CHANGE_KIND, "hashtags").to(GetHashtags.class);
|
||||||
get(CHANGE_KIND, "comments").to(ListChangeComments.class);
|
get(CHANGE_KIND, "comments").to(ListChangeComments.class);
|
||||||
get(CHANGE_KIND, "drafts").to(ListChangeDrafts.class);
|
get(CHANGE_KIND, "drafts").to(ListChangeDrafts.class);
|
||||||
@@ -139,6 +142,7 @@ public class Module extends RestApiModule {
|
|||||||
factory(PatchSetInserter.Factory.class);
|
factory(PatchSetInserter.Factory.class);
|
||||||
factory(RebaseChangeOp.Factory.class);
|
factory(RebaseChangeOp.Factory.class);
|
||||||
factory(ReviewerResource.Factory.class);
|
factory(ReviewerResource.Factory.class);
|
||||||
|
factory(SetAssigneeOp.Factory.class);
|
||||||
factory(SetHashtagsOp.Factory.class);
|
factory(SetHashtagsOp.Factory.class);
|
||||||
factory(ChangeResource.Factory.class);
|
factory(ChangeResource.Factory.class);
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,60 @@
|
|||||||
|
// Copyright (C) 2016 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.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.common.TimeUtil;
|
||||||
|
import com.google.gerrit.extensions.api.changes.AssigneeInput;
|
||||||
|
import com.google.gerrit.extensions.common.AccountInfo;
|
||||||
|
import com.google.gerrit.extensions.restapi.Response;
|
||||||
|
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||||
|
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||||
|
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||||
|
import com.google.gerrit.server.account.AccountJson;
|
||||||
|
import com.google.gerrit.server.git.BatchUpdate;
|
||||||
|
import com.google.gerrit.server.git.UpdateException;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class PutAssignee
|
||||||
|
implements RestModifyView<ChangeResource, AssigneeInput> {
|
||||||
|
|
||||||
|
private SetAssigneeOp.Factory assigneeFactory;
|
||||||
|
private BatchUpdate.Factory batchUpdateFactory;
|
||||||
|
private Provider<ReviewDb> db;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
PutAssignee(SetAssigneeOp.Factory assigneeFactory,
|
||||||
|
BatchUpdate.Factory batchUpdateFactory,
|
||||||
|
Provider<ReviewDb> db) {
|
||||||
|
this.assigneeFactory = assigneeFactory;
|
||||||
|
this.batchUpdateFactory = batchUpdateFactory;
|
||||||
|
this.db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response<AccountInfo> apply(ChangeResource rsrc, AssigneeInput input)
|
||||||
|
throws RestApiException, UpdateException {
|
||||||
|
try (BatchUpdate bu = batchUpdateFactory.create(db.get(),
|
||||||
|
rsrc.getChange().getProject(), rsrc.getControl().getUser(),
|
||||||
|
TimeUtil.nowTs())) {
|
||||||
|
SetAssigneeOp op = assigneeFactory.create(input);
|
||||||
|
bu.addOp(rsrc.getId(), op);
|
||||||
|
bu.execute();
|
||||||
|
return Response.ok(AccountJson.toAccountInfo(op.getNewAssignee()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,136 @@
|
|||||||
|
// Copyright (C) 2016 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.change;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.gerrit.extensions.api.changes.AssigneeInput;
|
||||||
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
|
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.ChangeMessage;
|
||||||
|
import com.google.gerrit.server.ChangeMessagesUtil;
|
||||||
|
import com.google.gerrit.server.ChangeUtil;
|
||||||
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
|
import com.google.gerrit.server.account.AccountInfoCacheFactory;
|
||||||
|
import com.google.gerrit.server.account.AccountsCollection;
|
||||||
|
import com.google.gerrit.server.config.AnonymousCowardName;
|
||||||
|
import com.google.gerrit.server.git.BatchUpdate;
|
||||||
|
import com.google.gerrit.server.notedb.ChangeUpdate;
|
||||||
|
import com.google.gerrit.server.notedb.NotesMigration;
|
||||||
|
import com.google.gwtorm.server.OrmException;
|
||||||
|
import com.google.inject.assistedinject.Assisted;
|
||||||
|
import com.google.inject.assistedinject.AssistedInject;
|
||||||
|
|
||||||
|
public class SetAssigneeOp extends BatchUpdate.Op {
|
||||||
|
public interface Factory {
|
||||||
|
SetAssigneeOp create(AssigneeInput input);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final AssigneeInput input;
|
||||||
|
private final AccountsCollection accounts;
|
||||||
|
private final ChangeMessagesUtil cmUtil;
|
||||||
|
private final AccountInfoCacheFactory.Factory accountInfosFactory;
|
||||||
|
private final NotesMigration notesMigration;
|
||||||
|
private final String anonymousCowardName;
|
||||||
|
private Account newAssignee;
|
||||||
|
|
||||||
|
@AssistedInject
|
||||||
|
SetAssigneeOp(AccountsCollection accounts,
|
||||||
|
NotesMigration notesMigration,
|
||||||
|
ChangeMessagesUtil cmUtil,
|
||||||
|
AccountInfoCacheFactory.Factory accountInfosFactory,
|
||||||
|
@AnonymousCowardName String anonymousCowardName,
|
||||||
|
@Assisted AssigneeInput input) {
|
||||||
|
this.accounts = accounts;
|
||||||
|
this.notesMigration = notesMigration;
|
||||||
|
this.cmUtil = cmUtil;
|
||||||
|
this.accountInfosFactory = accountInfosFactory;
|
||||||
|
this.anonymousCowardName = anonymousCowardName;
|
||||||
|
this.input = input;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean updateChange(BatchUpdate.ChangeContext ctx)
|
||||||
|
throws OrmException, RestApiException {
|
||||||
|
if (!notesMigration.readChanges()) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"Cannot add Assignee; NoteDb is disabled");
|
||||||
|
}
|
||||||
|
if (!ctx.getControl().canEditAssignee()) {
|
||||||
|
throw new AuthException("Changing Assignee not permitted");
|
||||||
|
}
|
||||||
|
ChangeUpdate update = ctx.getUpdate(ctx.getChange().currentPatchSetId());
|
||||||
|
Optional<Account.Id> oldAssigneeId = update.getNotes().getAssignee();
|
||||||
|
if (input.assignee == null) {
|
||||||
|
if (oldAssigneeId != null && oldAssigneeId.isPresent()) {
|
||||||
|
throw new AuthException("Cannot set Assignee to empty");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Account oldAssignee = null;
|
||||||
|
if (oldAssigneeId != null && oldAssigneeId.isPresent()) {
|
||||||
|
oldAssignee = accountInfosFactory.create().get(oldAssigneeId.get());
|
||||||
|
}
|
||||||
|
IdentifiedUser newAssigneeUser = accounts.parse(input.assignee);
|
||||||
|
if (oldAssigneeId != null &&
|
||||||
|
oldAssigneeId.equals(newAssigneeUser.getAccountId())) {
|
||||||
|
newAssignee = oldAssignee;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!newAssigneeUser.getAccount().isActive()) {
|
||||||
|
throw new UnprocessableEntityException(String.format(
|
||||||
|
"Account of %s is not active", newAssigneeUser.getUserName()));
|
||||||
|
}
|
||||||
|
if (!ctx.getControl().forUser(newAssigneeUser).isRefVisible()) {
|
||||||
|
throw new AuthException(String.format(
|
||||||
|
"Change %s is not visible to %s.",
|
||||||
|
ctx.getChange().getChangeId(),
|
||||||
|
newAssigneeUser.getUserName()));
|
||||||
|
}
|
||||||
|
update.setAssignee(Optional.fromNullable(newAssigneeUser.getAccountId()));
|
||||||
|
this.newAssignee = newAssigneeUser.getAccount();
|
||||||
|
addMessage(ctx, update, oldAssignee);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addMessage(BatchUpdate.ChangeContext ctx, ChangeUpdate update,
|
||||||
|
Account previousAssignee) throws OrmException {
|
||||||
|
StringBuilder msg = new StringBuilder();
|
||||||
|
msg.append("Assignee ");
|
||||||
|
if (previousAssignee == null) {
|
||||||
|
msg.append("added: ");
|
||||||
|
msg.append(newAssignee.getName(anonymousCowardName));
|
||||||
|
} else {
|
||||||
|
msg.append("changed from: ");
|
||||||
|
msg.append(previousAssignee.getName(anonymousCowardName));
|
||||||
|
msg.append(" to: ");
|
||||||
|
msg.append(newAssignee.getName(anonymousCowardName));
|
||||||
|
}
|
||||||
|
ChangeMessage cmsg = new ChangeMessage(
|
||||||
|
new ChangeMessage.Key(
|
||||||
|
ctx.getChange().getId(),
|
||||||
|
ChangeUtil.messageUUID(ctx.getDb())),
|
||||||
|
ctx.getAccountId(), ctx.getWhen(),
|
||||||
|
ctx.getChange().currentPatchSetId());
|
||||||
|
cmsg.setMessage(msg.toString());
|
||||||
|
cmUtil.addChangeMessage(ctx.getDb(), update, cmsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Account getNewAssignee() {
|
||||||
|
return newAssignee;
|
||||||
|
}
|
||||||
|
}
|
@@ -137,7 +137,7 @@ class ChangeNotesParser {
|
|||||||
private String branch;
|
private String branch;
|
||||||
private Change.Status status;
|
private Change.Status status;
|
||||||
private String topic;
|
private String topic;
|
||||||
private Account.Id assignee;
|
private Optional<Account.Id> assignee;
|
||||||
private Set<String> hashtags;
|
private Set<String> hashtags;
|
||||||
private Timestamp createdOn;
|
private Timestamp createdOn;
|
||||||
private Timestamp lastUpdatedOn;
|
private Timestamp lastUpdatedOn;
|
||||||
@@ -212,7 +212,7 @@ class ChangeNotesParser {
|
|||||||
submissionId,
|
submissionId,
|
||||||
status,
|
status,
|
||||||
|
|
||||||
assignee,
|
assignee != null ? assignee.orNull() : null,
|
||||||
hashtags,
|
hashtags,
|
||||||
patchSets,
|
patchSets,
|
||||||
buildApprovals(),
|
buildApprovals(),
|
||||||
@@ -484,9 +484,14 @@ class ChangeNotesParser {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String assigneeValue = parseOneFooter(commit, FOOTER_ASSIGNEE);
|
String assigneeValue = parseOneFooter(commit, FOOTER_ASSIGNEE);
|
||||||
if (assigneeValue != null) {
|
if (assigneeValue == null){
|
||||||
|
//footer not found
|
||||||
|
} else if (assigneeValue.equals("")) {
|
||||||
|
// empty footer found, assignee deleted
|
||||||
|
assignee = Optional.absent();
|
||||||
|
} else {
|
||||||
PersonIdent ident = RawParseUtils.parsePersonIdent(assigneeValue);
|
PersonIdent ident = RawParseUtils.parsePersonIdent(assigneeValue);
|
||||||
assignee = noteUtil.parseIdent(ident, id);
|
assignee = Optional.fromNullable(noteUtil.parseIdent(ident, id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -125,7 +125,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
|||||||
private String submissionId;
|
private String submissionId;
|
||||||
private String topic;
|
private String topic;
|
||||||
private String commit;
|
private String commit;
|
||||||
private Account.Id assignee;
|
private Optional<Account.Id> assignee;
|
||||||
private Set<String> hashtags;
|
private Set<String> hashtags;
|
||||||
private String changeMessage;
|
private String changeMessage;
|
||||||
private String tag;
|
private String tag;
|
||||||
@@ -378,7 +378,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
|||||||
this.hashtags = hashtags;
|
this.hashtags = hashtags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAssignee(Account.Id assignee) {
|
public void setAssignee(Optional<Account.Id> assignee) {
|
||||||
this.assignee = assignee;
|
this.assignee = assignee;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,8 +551,12 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (assignee != null) {
|
if (assignee != null) {
|
||||||
addFooter(msg, FOOTER_ASSIGNEE);
|
if (assignee.isPresent()) {
|
||||||
addIdent(msg, assignee).append('\n');
|
addFooter(msg, FOOTER_ASSIGNEE);
|
||||||
|
addIdent(msg, assignee.get()).append('\n');
|
||||||
|
} else {
|
||||||
|
addFooter(msg, FOOTER_ASSIGNEE).append('\n');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Joiner comma = Joiner.on(',');
|
Joiner comma = Joiner.on(',');
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.query.change;
|
package com.google.gerrit.server.query.change;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.gerrit.reviewdb.client.Account;
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
import com.google.gerrit.server.index.change.ChangeField;
|
import com.google.gerrit.server.index.change.ChangeField;
|
||||||
import com.google.gwtorm.server.OrmException;
|
import com.google.gwtorm.server.OrmException;
|
||||||
@@ -29,9 +30,10 @@ class AssigneePredicate extends ChangeIndexPredicate {
|
|||||||
@Override
|
@Override
|
||||||
public boolean match(final ChangeData object) throws OrmException {
|
public boolean match(final ChangeData object) throws OrmException {
|
||||||
if (id.get() == ChangeField.NO_ASSIGNEE) {
|
if (id.get() == ChangeField.NO_ASSIGNEE) {
|
||||||
return object.notes().load().getAssignee() == null;
|
Optional<Account.Id> assignee = object.notes().load().getAssignee();
|
||||||
|
return assignee == null || !assignee.isPresent();
|
||||||
}
|
}
|
||||||
return id.equals(object.notes().load().getAssignee());
|
return id.equals(object.notes().load().getAssignee().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -24,6 +24,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
|||||||
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
|
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Throwables;
|
import com.google.common.base.Throwables;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableListMultimap;
|
import com.google.common.collect.ImmutableListMultimap;
|
||||||
@@ -565,7 +566,7 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
|
|||||||
public void assigneeCommit() throws Exception {
|
public void assigneeCommit() throws Exception {
|
||||||
Change c = newChange();
|
Change c = newChange();
|
||||||
ChangeUpdate update = newUpdate(c, changeOwner);
|
ChangeUpdate update = newUpdate(c, changeOwner);
|
||||||
update.setAssignee(otherUserId);
|
update.setAssignee(Optional.fromNullable(otherUserId));
|
||||||
ObjectId result = update.commit();
|
ObjectId result = update.commit();
|
||||||
assertThat(result).isNotNull();
|
assertThat(result).isNotNull();
|
||||||
try (RevWalk rw = new RevWalk(repo)) {
|
try (RevWalk rw = new RevWalk(repo)) {
|
||||||
@@ -587,14 +588,14 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
|
|||||||
public void assigneeChangeNotes() throws Exception {
|
public void assigneeChangeNotes() throws Exception {
|
||||||
Change c = newChange();
|
Change c = newChange();
|
||||||
ChangeUpdate update = newUpdate(c, changeOwner);
|
ChangeUpdate update = newUpdate(c, changeOwner);
|
||||||
update.setAssignee(otherUserId);
|
update.setAssignee(Optional.fromNullable(otherUserId));
|
||||||
update.commit();
|
update.commit();
|
||||||
|
|
||||||
ChangeNotes notes = newNotes(c);
|
ChangeNotes notes = newNotes(c);
|
||||||
assertThat(notes.getAssignee().get()).isEqualTo(otherUserId);
|
assertThat(notes.getAssignee().get()).isEqualTo(otherUserId);
|
||||||
|
|
||||||
update = newUpdate(c, changeOwner);
|
update = newUpdate(c, changeOwner);
|
||||||
update.setAssignee(changeOwner.getAccountId());
|
update.setAssignee(Optional.fromNullable(changeOwner.getAccountId()));
|
||||||
update.commit();
|
update.commit();
|
||||||
|
|
||||||
notes = newNotes(c);
|
notes = newNotes(c);
|
||||||
|
Reference in New Issue
Block a user