LCOV - code coverage report
Current view: top level - server/change - ActionJson.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 113 115 98.3 %
Date: 2022-11-19 15:00:39 Functions: 10 10 100.0 %

          Line data    Source code
       1             : // Copyright (C) 2015 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.server.change;
      16             : 
      17             : import static java.util.Objects.requireNonNull;
      18             : 
      19             : import com.google.common.collect.ImmutableMap;
      20             : import com.google.common.collect.Iterables;
      21             : import com.google.common.collect.Lists;
      22             : import com.google.gerrit.common.Nullable;
      23             : import com.google.gerrit.extensions.api.changes.ActionVisitor;
      24             : import com.google.gerrit.extensions.common.ActionInfo;
      25             : import com.google.gerrit.extensions.common.ChangeInfo;
      26             : import com.google.gerrit.extensions.common.RevisionInfo;
      27             : import com.google.gerrit.extensions.registration.DynamicMap;
      28             : import com.google.gerrit.extensions.registration.DynamicSet;
      29             : import com.google.gerrit.extensions.restapi.RestView;
      30             : import com.google.gerrit.extensions.webui.PrivateInternals_UiActionDescription;
      31             : import com.google.gerrit.extensions.webui.UiAction;
      32             : import com.google.gerrit.server.CurrentUser;
      33             : import com.google.gerrit.server.extensions.webui.UiActions;
      34             : import com.google.gerrit.server.query.change.ChangeData;
      35             : import com.google.inject.Inject;
      36             : import com.google.inject.Provider;
      37             : import com.google.inject.Singleton;
      38             : import java.util.ArrayList;
      39             : import java.util.Collections;
      40             : import java.util.LinkedHashMap;
      41             : import java.util.List;
      42             : import java.util.Map;
      43             : 
      44             : @Singleton
      45             : public class ActionJson {
      46             :   private final DynamicMap<RestView<RevisionResource>> revisionViews;
      47             :   private final ChangeJson.Factory changeJsonFactory;
      48             :   private final ChangeResource.Factory changeResourceFactory;
      49             :   private final UiActions uiActions;
      50             :   private final DynamicMap<RestView<ChangeResource>> changeViews;
      51             :   private final DynamicSet<ActionVisitor> visitorSet;
      52             :   private final Provider<CurrentUser> userProvider;
      53             : 
      54             :   @Inject
      55             :   ActionJson(
      56             :       DynamicMap<RestView<RevisionResource>> views,
      57             :       ChangeJson.Factory changeJsonFactory,
      58             :       ChangeResource.Factory changeResourceFactory,
      59             :       UiActions uiActions,
      60             :       DynamicMap<RestView<ChangeResource>> changeViews,
      61             :       DynamicSet<ActionVisitor> visitorSet,
      62         146 :       Provider<CurrentUser> userProvider) {
      63         146 :     this.revisionViews = views;
      64         146 :     this.changeJsonFactory = changeJsonFactory;
      65         146 :     this.changeResourceFactory = changeResourceFactory;
      66         146 :     this.uiActions = uiActions;
      67         146 :     this.changeViews = changeViews;
      68         146 :     this.visitorSet = visitorSet;
      69         146 :     this.userProvider = userProvider;
      70         146 :   }
      71             : 
      72             :   public Map<String, ActionInfo> format(RevisionResource rsrc) {
      73           6 :     ChangeInfo changeInfo = null;
      74           6 :     RevisionInfo revisionInfo = null;
      75           6 :     List<ActionVisitor> visitors = visitors();
      76           6 :     if (!visitors.isEmpty()) {
      77           1 :       changeInfo = changeJson().format(rsrc);
      78           1 :       revisionInfo = requireNonNull(Iterables.getOnlyElement(changeInfo.revisions.values()));
      79           1 :       changeInfo.revisions = null;
      80             :     }
      81           6 :     return toActionMap(rsrc, visitors, changeInfo, revisionInfo);
      82             :   }
      83             : 
      84             :   private ChangeJson changeJson() {
      85           1 :     return changeJsonFactory.noOptions();
      86             :   }
      87             : 
      88             :   private ArrayList<ActionVisitor> visitors() {
      89          57 :     return Lists.newArrayList(visitorSet);
      90             :   }
      91             : 
      92             :   void addChangeActions(ChangeInfo to, ChangeData changeData) {
      93          57 :     List<ActionVisitor> visitors = visitors();
      94          57 :     to.actions = toActionMap(changeData, visitors, copy(visitors, to));
      95          57 :   }
      96             : 
      97             :   void addRevisionActions(@Nullable ChangeInfo changeInfo, RevisionInfo to, RevisionResource rsrc) {
      98          57 :     List<ActionVisitor> visitors = visitors();
      99          57 :     if (!visitors.isEmpty()) {
     100           1 :       if (changeInfo != null) {
     101           1 :         changeInfo = copy(visitors, changeInfo);
     102             :       } else {
     103           0 :         changeInfo = changeJson().format(rsrc);
     104             :       }
     105             :     }
     106          57 :     to.actions = toActionMap(rsrc, visitors, changeInfo, copy(visitors, to));
     107          57 :   }
     108             : 
     109             :   @Nullable
     110             :   private ChangeInfo copy(List<ActionVisitor> visitors, ChangeInfo changeInfo) {
     111          57 :     if (visitors.isEmpty()) {
     112          57 :       return null;
     113             :     }
     114             :     // Include all fields from ChangeJson#toChangeInfoImpl that are not protected by any
     115             :     // ListChangesOptions.
     116           1 :     ChangeInfo copy = new ChangeInfo();
     117           1 :     copy.project = changeInfo.project;
     118           1 :     copy.branch = changeInfo.branch;
     119           1 :     copy.topic = changeInfo.topic;
     120           1 :     copy.attentionSet =
     121           1 :         changeInfo.attentionSet == null ? null : ImmutableMap.copyOf(changeInfo.attentionSet);
     122           1 :     copy.removedFromAttentionSet =
     123           1 :         changeInfo.removedFromAttentionSet == null
     124           1 :             ? null
     125           1 :             : ImmutableMap.copyOf(changeInfo.removedFromAttentionSet);
     126           1 :     copy.assignee = changeInfo.assignee;
     127           1 :     copy.hashtags = changeInfo.hashtags;
     128           1 :     copy.changeId = changeInfo.changeId;
     129           1 :     copy.submitType = changeInfo.submitType;
     130           1 :     copy.mergeable = changeInfo.mergeable;
     131           1 :     copy.insertions = changeInfo.insertions;
     132           1 :     copy.deletions = changeInfo.deletions;
     133           1 :     copy.hasReviewStarted = changeInfo.hasReviewStarted;
     134           1 :     copy.isPrivate = changeInfo.isPrivate;
     135           1 :     copy.subject = changeInfo.subject;
     136           1 :     copy.status = changeInfo.status;
     137           1 :     copy.owner = changeInfo.owner;
     138           1 :     copy.created = changeInfo.created;
     139           1 :     copy.updated = changeInfo.updated;
     140           1 :     copy._number = changeInfo._number;
     141           1 :     copy.requirements = changeInfo.requirements;
     142           1 :     copy.revertOf = changeInfo.revertOf;
     143           1 :     copy.submissionId = changeInfo.submissionId;
     144           1 :     copy.starred = changeInfo.starred;
     145           1 :     copy.stars = changeInfo.stars;
     146           1 :     copy.submitted = changeInfo.submitted;
     147           1 :     copy.submitter = changeInfo.submitter;
     148           1 :     copy.unresolvedCommentCount = changeInfo.unresolvedCommentCount;
     149           1 :     copy.workInProgress = changeInfo.workInProgress;
     150           1 :     copy.id = changeInfo.id;
     151           1 :     copy.cherryPickOfChange = changeInfo.cherryPickOfChange;
     152           1 :     copy.cherryPickOfPatchSet = changeInfo.cherryPickOfPatchSet;
     153           1 :     return copy;
     154             :   }
     155             : 
     156             :   @Nullable
     157             :   private RevisionInfo copy(List<ActionVisitor> visitors, RevisionInfo revisionInfo) {
     158          57 :     if (visitors.isEmpty()) {
     159          57 :       return null;
     160             :     }
     161             :     // Include all fields from RevisionJson#toRevisionInfo that are not protected by any
     162             :     // ListChangesOptions.
     163           1 :     RevisionInfo copy = new RevisionInfo();
     164           1 :     copy.isCurrent = revisionInfo.isCurrent;
     165           1 :     copy._number = revisionInfo._number;
     166           1 :     copy.ref = revisionInfo.ref;
     167           1 :     copy.created = revisionInfo.created;
     168           1 :     copy.uploader = revisionInfo.uploader;
     169           1 :     copy.fetch = revisionInfo.fetch;
     170           1 :     copy.kind = revisionInfo.kind;
     171           1 :     copy.description = revisionInfo.description;
     172           1 :     return copy;
     173             :   }
     174             : 
     175             :   private Map<String, ActionInfo> toActionMap(
     176             :       ChangeData changeData, List<ActionVisitor> visitors, ChangeInfo changeInfo) {
     177          57 :     CurrentUser user = userProvider.get();
     178          57 :     Map<String, ActionInfo> out = new LinkedHashMap<>();
     179          57 :     if (!user.isIdentifiedUser()) {
     180           5 :       return out;
     181             :     }
     182             : 
     183          57 :     Iterable<UiAction.Description> descs =
     184          57 :         uiActions.from(changeViews, changeResourceFactory.create(changeData, user));
     185             : 
     186             :     // The followup action is a client-side only operation that does not
     187             :     // have a server side handler. It must be manually registered into the
     188             :     // resulting action map.
     189          57 :     if (!changeData.change().isAbandoned()) {
     190          57 :       UiAction.Description descr = new UiAction.Description();
     191          57 :       PrivateInternals_UiActionDescription.setId(descr, "followup");
     192          57 :       PrivateInternals_UiActionDescription.setMethod(descr, "POST");
     193          57 :       descr.setTitle("Create follow-up change");
     194          57 :       descr.setLabel("Follow-Up");
     195          57 :       descs = Iterables.concat(descs, Collections.singleton(descr));
     196             :     }
     197             : 
     198             :     ACTION:
     199          57 :     for (UiAction.Description d : descs) {
     200          57 :       ActionInfo actionInfo = new ActionInfo(d);
     201          57 :       for (ActionVisitor visitor : visitors) {
     202           1 :         if (!visitor.visit(d.getId(), actionInfo, changeInfo)) {
     203           1 :           continue ACTION;
     204             :         }
     205           1 :       }
     206          57 :       out.put(d.getId(), actionInfo);
     207          57 :     }
     208          57 :     return out;
     209             :   }
     210             : 
     211             :   private ImmutableMap<String, ActionInfo> toActionMap(
     212             :       RevisionResource rsrc,
     213             :       List<ActionVisitor> visitors,
     214             :       ChangeInfo changeInfo,
     215             :       RevisionInfo revisionInfo) {
     216          57 :     if (!rsrc.getUser().isIdentifiedUser()) {
     217           0 :       return ImmutableMap.of();
     218             :     }
     219             : 
     220          57 :     Map<String, ActionInfo> out = new LinkedHashMap<>();
     221             :     ACTION:
     222          57 :     for (UiAction.Description d : uiActions.from(revisionViews, rsrc)) {
     223          57 :       ActionInfo actionInfo = new ActionInfo(d);
     224          57 :       for (ActionVisitor visitor : visitors) {
     225           1 :         if (!visitor.visit(d.getId(), actionInfo, changeInfo, revisionInfo)) {
     226           1 :           continue ACTION;
     227             :         }
     228           1 :       }
     229          57 :       out.put(d.getId(), actionInfo);
     230          57 :     }
     231          57 :     return ImmutableMap.copyOf(out);
     232             :   }
     233             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750