Add new CHANGE_ACTIONS option to /changes/X/detail REST API call This will move action related JSON processing into the ActionJson class as well. Change-Id: I291727762d2f08d00484ca8ce8805624042ab4e8
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt index 115cee5..284cc83 100644 --- a/Documentation/rest-api-changes.txt +++ b/Documentation/rest-api-changes.txt
@@ -281,8 +281,15 @@ [[actions]] -- * `CURRENT_ACTIONS`: include information on available actions - for the change and its current revision. The caller must be - authenticated to obtain the available actions. + for the change and its current revision. Ignored if the caller + is not authenticated. +-- + +[[change-actions]] +-- +* `CHANGE_ACTIONS`: include information on available + change actions for the change. Ignored if the caller + is not authenticated. -- [[reviewed]]
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListChangesOption.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListChangesOption.java index 1049d6a..54617a7 100644 --- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListChangesOption.java +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListChangesOption.java
@@ -55,7 +55,10 @@ WEB_LINKS(14), /** Include consistency check results. */ - CHECK(15); + CHECK(15), + + /** Include allowed change actions client could perform. */ + CHANGE_ACTIONS(16); private final int value;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ActionJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ActionJson.java index 24837aab..023173e 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ActionJson.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ActionJson.java
@@ -15,9 +15,15 @@ package com.google.gerrit.server.change; import com.google.gerrit.extensions.common.ActionInfo; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.common.RevisionInfo; +import com.google.gerrit.extensions.registration.DynamicMap; +import com.google.gerrit.extensions.restapi.RestView; +import com.google.gerrit.extensions.webui.PrivateInternals_UiActionDescription; import com.google.gerrit.extensions.webui.UiAction; import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.extensions.webui.UiActions; +import com.google.gerrit.server.project.ChangeControl; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; @@ -29,16 +35,55 @@ @Singleton public class ActionJson { private final Revisions revisions; + private final DynamicMap<RestView<ChangeResource>> changeViews; @Inject - ActionJson(Revisions revisions) { + ActionJson( + Revisions revisions, + DynamicMap<RestView<ChangeResource>> changeViews) { this.revisions = revisions; + this.changeViews = changeViews; } public Map<String, ActionInfo> format(RevisionResource rsrc) { return toActionMap(rsrc); } + public ChangeInfo addChangeActions(ChangeInfo to, ChangeControl ctl) { + to.actions = toActionMap(ctl); + return to; + } + + public RevisionInfo addRevisionActions(RevisionInfo to, + RevisionResource rsrc) { + to.actions = toActionMap(rsrc); + return to; + } + + private Map<String, ActionInfo> toActionMap(ChangeControl ctl) { + Map<String, ActionInfo> out = new LinkedHashMap<>(); + if (!ctl.getCurrentUser().isIdentifiedUser()) { + return out; + } + + Provider<CurrentUser> userProvider = Providers.of(ctl.getCurrentUser()); + for (UiAction.Description d : UiActions.from( + changeViews, + new ChangeResource(ctl), + userProvider)) { + out.put(d.getId(), new ActionInfo(d)); + } + // TODO(sbeller): why do we need to treat followup specially here? + if (ctl.getChange().getStatus().isOpen()) { + UiAction.Description descr = new UiAction.Description(); + PrivateInternals_UiActionDescription.setId(descr, "followup"); + PrivateInternals_UiActionDescription.setMethod(descr, "POST"); + descr.setTitle("Create follow-up change"); + out.put(descr.getId(), new ActionInfo(descr)); + } + return out; + } + private Map<String, ActionInfo> toActionMap(RevisionResource rsrc) { Map<String, ActionInfo> out = new LinkedHashMap<>(); if (rsrc.getControl().getCurrentUser().isIdentifiedUser()) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java index 662406a..86a50a6 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -17,6 +17,7 @@ import static com.google.gerrit.extensions.client.ListChangesOption.ALL_COMMITS; import static com.google.gerrit.extensions.client.ListChangesOption.ALL_FILES; import static com.google.gerrit.extensions.client.ListChangesOption.ALL_REVISIONS; +import static com.google.gerrit.extensions.client.ListChangesOption.CHANGE_ACTIONS; import static com.google.gerrit.extensions.client.ListChangesOption.CHECK; import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_ACTIONS; import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_COMMIT; @@ -59,7 +60,6 @@ import com.google.gerrit.extensions.api.changes.FixInput; import com.google.gerrit.extensions.client.ListChangesOption; import com.google.gerrit.extensions.common.AccountInfo; -import com.google.gerrit.extensions.common.ActionInfo; import com.google.gerrit.extensions.common.ApprovalInfo; import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.extensions.common.ChangeMessageInfo; @@ -73,10 +73,7 @@ import com.google.gerrit.extensions.config.DownloadCommand; import com.google.gerrit.extensions.config.DownloadScheme; import com.google.gerrit.extensions.registration.DynamicMap; -import com.google.gerrit.extensions.restapi.RestView; import com.google.gerrit.extensions.restapi.Url; -import com.google.gerrit.extensions.webui.PrivateInternals_UiActionDescription; -import com.google.gerrit.extensions.webui.UiAction; import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.ChangeMessage; @@ -95,7 +92,6 @@ import com.google.gerrit.server.PatchLineCommentsUtil; import com.google.gerrit.server.WebLinks; import com.google.gerrit.server.account.AccountLoader; -import com.google.gerrit.server.extensions.webui.UiActions; import com.google.gerrit.server.git.LabelNormalizer; import com.google.gerrit.server.notedb.ChangeNotes; import com.google.gerrit.server.patch.PatchListNotAvailableException; @@ -140,13 +136,12 @@ private final AccountLoader.Factory accountLoaderFactory; private final DynamicMap<DownloadScheme> downloadSchemes; private final DynamicMap<DownloadCommand> downloadCommands; - private final DynamicMap<RestView<ChangeResource>> changeViews; - private final Revisions revisions; private final WebLinks webLinks; private final EnumSet<ListChangesOption> options; private final ChangeMessagesUtil cmUtil; private final PatchLineCommentsUtil plcUtil; private final Provider<ConsistencyChecker> checkerProvider; + private final ActionJson actionJson; private AccountLoader accountLoader; private FixInput fix; @@ -164,12 +159,11 @@ AccountLoader.Factory ailf, DynamicMap<DownloadScheme> downloadSchemes, DynamicMap<DownloadCommand> downloadCommands, - DynamicMap<RestView<ChangeResource>> changeViews, - Revisions revisions, WebLinks webLinks, ChangeMessagesUtil cmUtil, PatchLineCommentsUtil plcUtil, - Provider<ConsistencyChecker> checkerProvider) { + Provider<ConsistencyChecker> checkerProvider, + ActionJson actionJson) { this.db = db; this.labelNormalizer = ln; this.userProvider = user; @@ -181,12 +175,11 @@ this.accountLoaderFactory = ailf; this.downloadSchemes = downloadSchemes; this.downloadCommands = downloadCommands; - this.changeViews = changeViews; - this.revisions = revisions; this.webLinks = webLinks; this.cmUtil = cmUtil; this.plcUtil = plcUtil; this.checkerProvider = checkerProvider; + this.actionJson = actionJson; options = EnumSet.noneOf(ListChangesOption.class); } @@ -419,22 +412,8 @@ } } - if (has(CURRENT_ACTIONS) && userProvider.get().isIdentifiedUser()) { - out.actions = Maps.newTreeMap(); - for (UiAction.Description d : UiActions.from( - changeViews, - new ChangeResource(ctl), - userProvider)) { - out.actions.put(d.getId(), new ActionInfo(d)); - } - if (userProvider.get().isIdentifiedUser() - && in.getStatus().isOpen()) { - UiAction.Description descr = new UiAction.Description(); - PrivateInternals_UiActionDescription.setId(descr, "followup"); - PrivateInternals_UiActionDescription.setMethod(descr, "POST"); - descr.setTitle("Create follow-up change"); - out.actions.put(descr.getId(), new ActionInfo(descr)); - } + if (has(CURRENT_ACTIONS) || has(CHANGE_ACTIONS)) { + actionJson.addChangeActions(out, ctl); } return out; @@ -907,13 +886,9 @@ if ((out.isCurrent || (out.draft != null && out.draft)) && has(CURRENT_ACTIONS) && userProvider.get().isIdentifiedUser()) { - out.actions = Maps.newTreeMap(); - for (UiAction.Description d : UiActions.from( - revisions, - new RevisionResource(new ChangeResource(ctl), in), - userProvider)) { - out.actions.put(d.getId(), new ActionInfo(d)); - } + + actionJson.addRevisionActions(out, + new RevisionResource(new ChangeResource(ctl), in)); } if (has(DRAFT_COMMENTS)