All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gerrit.server.change.ActionJson Maven / Gradle / Ivy

The newest version!
// Copyright (C) 2015 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 static java.util.Objects.requireNonNull;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.api.changes.ActionVisitor;
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.registration.DynamicSet;
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.logging.Metadata;
import com.google.gerrit.server.logging.TraceContext;
import com.google.gerrit.server.logging.TraceContext.TraceTimer;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Singleton
public class ActionJson {
  private final DynamicMap> revisionViews;
  private final ChangeJson.Factory changeJsonFactory;
  private final ChangeResource.Factory changeResourceFactory;
  private final UiActions uiActions;
  private final DynamicMap> changeViews;
  private final DynamicSet visitorSet;
  private final Provider userProvider;

  @Inject
  ActionJson(
      DynamicMap> views,
      ChangeJson.Factory changeJsonFactory,
      ChangeResource.Factory changeResourceFactory,
      UiActions uiActions,
      DynamicMap> changeViews,
      DynamicSet visitorSet,
      Provider userProvider) {
    this.revisionViews = views;
    this.changeJsonFactory = changeJsonFactory;
    this.changeResourceFactory = changeResourceFactory;
    this.uiActions = uiActions;
    this.changeViews = changeViews;
    this.visitorSet = visitorSet;
    this.userProvider = userProvider;
  }

  public Map format(RevisionResource rsrc) {
    ChangeInfo changeInfo = null;
    RevisionInfo revisionInfo = null;
    List visitors = visitors();
    if (!visitors.isEmpty()) {
      changeInfo = changeJson().format(rsrc);
      revisionInfo = requireNonNull(Iterables.getOnlyElement(changeInfo.revisions.values()));
      changeInfo.revisions = null;
    }
    return toActionMap(rsrc, visitors, changeInfo, revisionInfo);
  }

  private ChangeJson changeJson() {
    return changeJsonFactory.noOptions();
  }

  private ArrayList visitors() {
    return Lists.newArrayList(visitorSet);
  }

  void addChangeActions(ChangeInfo to, ChangeData changeData) {
    List visitors = visitors();
    to.actions = toActionMap(changeData, visitors, copy(visitors, to));
  }

  void addRevisionActions(@Nullable ChangeInfo changeInfo, RevisionInfo to, RevisionResource rsrc) {
    List visitors = visitors();
    if (!visitors.isEmpty()) {
      if (changeInfo != null) {
        changeInfo = copy(visitors, changeInfo);
      } else {
        changeInfo = changeJson().format(rsrc);
      }
    }
    to.actions = toActionMap(rsrc, visitors, changeInfo, copy(visitors, to));
  }

  @Nullable
  private ChangeInfo copy(List visitors, ChangeInfo changeInfo) {
    if (visitors.isEmpty()) {
      return null;
    }
    // Include all fields from ChangeJson#toChangeInfoImpl that are not protected by any
    // ListChangesOptions.
    ChangeInfo copy = new ChangeInfo();
    copy.project = changeInfo.project;
    copy.branch = changeInfo.branch;
    copy.topic = changeInfo.topic;
    copy.attentionSet =
        changeInfo.attentionSet == null ? null : ImmutableMap.copyOf(changeInfo.attentionSet);
    copy.removedFromAttentionSet =
        changeInfo.removedFromAttentionSet == null
            ? null
            : ImmutableMap.copyOf(changeInfo.removedFromAttentionSet);
    copy.customKeyedValues =
        changeInfo.customKeyedValues == null
            ? null
            : ImmutableMap.copyOf(changeInfo.customKeyedValues);
    copy.hashtags = changeInfo.hashtags;
    copy.changeId = changeInfo.changeId;
    copy.submitType = changeInfo.submitType;
    copy.mergeable = changeInfo.mergeable;
    copy.insertions = changeInfo.insertions;
    copy.deletions = changeInfo.deletions;
    copy.hasReviewStarted = changeInfo.hasReviewStarted;
    copy.isPrivate = changeInfo.isPrivate;
    copy.subject = changeInfo.subject;
    copy.status = changeInfo.status;
    copy.owner = changeInfo.owner;
    copy.created = changeInfo.created;
    copy.updated = changeInfo.updated;
    copy._number = changeInfo._number;
    copy.requirements = changeInfo.requirements;
    copy.revertOf = changeInfo.revertOf;
    copy.submissionId = changeInfo.submissionId;
    copy.starred = changeInfo.starred;
    copy.submitted = changeInfo.submitted;
    copy.submitter = changeInfo.submitter;
    copy.unresolvedCommentCount = changeInfo.unresolvedCommentCount;
    copy.workInProgress = changeInfo.workInProgress;
    copy.id = changeInfo.id;
    copy.tripletId = changeInfo.tripletId;
    copy.cherryPickOfChange = changeInfo.cherryPickOfChange;
    copy.cherryPickOfPatchSet = changeInfo.cherryPickOfPatchSet;
    return copy;
  }

  @Nullable
  private RevisionInfo copy(List visitors, RevisionInfo revisionInfo) {
    if (visitors.isEmpty()) {
      return null;
    }
    // Include all fields from RevisionJson#toRevisionInfo that are not protected by any
    // ListChangesOptions.
    RevisionInfo copy = new RevisionInfo();
    copy.isCurrent = revisionInfo.isCurrent;
    copy._number = revisionInfo._number;
    copy.ref = revisionInfo.ref;
    copy.branch = revisionInfo.branch;
    copy.created = revisionInfo.created;
    copy.uploader = revisionInfo.uploader;
    copy.realUploader = revisionInfo.realUploader;
    copy.fetch = revisionInfo.fetch;
    copy.kind = revisionInfo.kind;
    copy.description = revisionInfo.description;
    return copy;
  }

  private Map toActionMap(
      ChangeData changeData, List visitors, ChangeInfo changeInfo) {
    try (TraceTimer timer =
        TraceContext.newTimer(
            "Get actions",
            Metadata.builder().changeId(changeData.change().getId().get()).build())) {
      CurrentUser user = userProvider.get();
      Map out = new LinkedHashMap<>();
      if (!user.isIdentifiedUser()) {
        return out;
      }

      Iterable descs =
          uiActions.from(changeViews, changeResourceFactory.create(changeData, user));

      // The followup action is a client-side only operation that does not
      // have a server side handler. It must be manually registered into the
      // resulting action map.
      if (!changeData.change().isAbandoned()) {
        UiAction.Description descr = new UiAction.Description();
        PrivateInternals_UiActionDescription.setId(descr, "followup");
        PrivateInternals_UiActionDescription.setMethod(descr, "POST");
        descr.setTitle("Create follow-up change");
        descr.setLabel("Follow-Up");
        descs = Iterables.concat(descs, Collections.singleton(descr));
      }

      ACTION:
      for (UiAction.Description d : descs) {
        ActionInfo actionInfo = new ActionInfo(d);
        for (ActionVisitor visitor : visitors) {
          if (!visitor.visit(d.getId(), actionInfo, changeInfo)) {
            continue ACTION;
          }
        }
        out.put(d.getId(), actionInfo);
      }
      return out;
    }
  }

  private ImmutableMap toActionMap(
      RevisionResource rsrc,
      List visitors,
      ChangeInfo changeInfo,
      RevisionInfo revisionInfo) {
    if (!rsrc.getUser().isIdentifiedUser()) {
      return ImmutableMap.of();
    }

    Map out = new LinkedHashMap<>();
    ACTION:
    for (UiAction.Description d : uiActions.from(revisionViews, rsrc)) {
      ActionInfo actionInfo = new ActionInfo(d);
      for (ActionVisitor visitor : visitors) {
        if (!visitor.visit(d.getId(), actionInfo, changeInfo, revisionInfo)) {
          continue ACTION;
        }
      }
      out.put(d.getId(), actionInfo);
    }
    return ImmutableMap.copyOf(out);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy