/components/server-activity-streams/src/main/java/org/marvelution/jji/streams/JenkinsStreamsActivityProvider.java
Java | 295 lines | 221 code | 23 blank | 51 comment | 9 complexity | e41ecc4464dfbe43fc7affdcfd368e02 MD5 | raw file
- /*
- * Copyright (c) 2012-present Marvelution Holding B.V.
- *
- * 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 org.marvelution.jji.streams;
- import java.io.*;
- import java.net.*;
- import java.util.*;
- import java.util.concurrent.atomic.*;
- import java.util.stream.*;
- import javax.inject.*;
- import org.marvelution.jji.api.*;
- import org.marvelution.jji.data.services.api.*;
- import org.marvelution.jji.model.*;
- import com.atlassian.jira.project.*;
- import com.atlassian.jira.security.*;
- import com.atlassian.plugin.spring.scanner.annotation.imports.*;
- import com.atlassian.plugin.webresource.*;
- import com.atlassian.sal.api.message.*;
- import com.atlassian.streams.api.*;
- import com.atlassian.streams.api.common.*;
- import com.atlassian.streams.spi.*;
- import com.atlassian.templaterenderer.*;
- import com.google.common.collect.*;
- import org.apache.commons.lang3.*;
- import org.joda.time.*;
- import org.slf4j.*;
- import static com.atlassian.jira.permission.ProjectPermissions.*;
- import static com.atlassian.plugin.webresource.UrlMode.*;
- import static com.atlassian.streams.api.StreamsEntry.ActivityObject.*;
- import static com.atlassian.streams.api.common.ImmutableNonEmptyList.*;
- import static com.atlassian.streams.api.common.Option.*;
- import static com.atlassian.streams.spi.StandardStreamsFilterOption.*;
- import static java.util.stream.Collectors.*;
- import static javax.ws.rs.core.UriBuilder.*;
- /**
- * {@link StreamsActivityProvider} for Jenkins Builds
- *
- * @author Mark Rekveld
- * @since 1.0.0
- */
- public class JenkinsStreamsActivityProvider
- implements StreamsActivityProvider
- {
- private static final Logger LOGGER = LoggerFactory.getLogger(JenkinsStreamsActivityProvider.class);
- private final AddonHelper addonHelper;
- private final IssueLinkService issueLinkService;
- private final ProjectManager projectManager;
- private final PermissionManager permissionManager;
- private final JiraAuthenticationContext authenticationContext;
- private final I18nResolver i18nResolver;
- private final TemplateRenderer templateRenderer;
- private final WebResourceUrlProvider urlProvider;
- @Inject
- public JenkinsStreamsActivityProvider(
- AddonHelper addonHelper,
- IssueLinkService issueLinkService,
- @ComponentImport ProjectManager projectManager,
- @ComponentImport PermissionManager permissionManager,
- @ComponentImport JiraAuthenticationContext authenticationContext,
- @ComponentImport I18nResolver i18nResolver,
- @ComponentImport @Named("templateRenderer") TemplateRenderer templateRenderer,
- @ComponentImport WebResourceUrlProvider urlProvider)
- {
- this.addonHelper = addonHelper;
- this.issueLinkService = issueLinkService;
- this.projectManager = projectManager;
- this.permissionManager = permissionManager;
- this.authenticationContext = authenticationContext;
- this.i18nResolver = i18nResolver;
- this.templateRenderer = templateRenderer;
- this.urlProvider = urlProvider;
- }
- @Override
- public CancellableTask<StreamsFeed> getActivityFeed(final ActivityRequest activityRequest)
- {
- final IssueLinkService.LinkRequest filter = getLinkRequest(activityRequest);
- LOGGER.debug("Streams filter: {}", filter);
- return new CancellableTask<StreamsFeed>()
- {
- private final AtomicBoolean cancelled = new AtomicBoolean(false);
- @Override
- public StreamsFeed call()
- {
- Iterable<StreamsEntry> entries = new ArrayList<>();
- if (!filter.getInProjectKeys().isEmpty())
- {
- Iterable<Build> builds = issueLinkService.getBuildsForLinkRequest(filter, activityRequest.getMaxResults());
- if (cancelled.get())
- {
- throw new CancelledException();
- }
- LOGGER.debug("Found build entries for stream: {}", builds);
- entries = transformEntries(builds, cancelled);
- }
- return new StreamsFeed(i18nResolver.getText("jenkins.streams.feed.title"), entries, none());
- }
- @Override
- public CancellableTask.Result cancel()
- {
- cancelled.set(true);
- return CancellableTask.Result.CANCELLED;
- }
- };
- }
- /**
- * @since 3.3.0
- */
- IssueLinkService.LinkRequest getLinkRequest(ActivityRequest activityRequest)
- {
- IssueLinkService.LinkRequest request = new IssueLinkService.LinkRequest();
- Multimap<String, Pair<StreamsFilterType.Operator, Iterable<String>>> standardFilters = activityRequest.getStandardFilters();
- // We cannot take user filters into account, so if filtering for specific users, then don't load any builds.
- if (Filters.getIsValues(standardFilters.get(USER.getKey())).isEmpty())
- {
- request.setInProjectKeys(getInProjectsByPermission(Filters.getIsValues(standardFilters.get(PROJECT_KEY))));
- request.setNotInProjectKeys(Filters.getNotValues(standardFilters.get(PROJECT_KEY)));
- request.setInIssueKeys(Filters.getIsValues(standardFilters.get(ISSUE_KEY.getKey())));
- request.setNotInIssueKeys(Filters.getNotValues(standardFilters.get(ISSUE_KEY.getKey())));
- }
- return request;
- }
- /**
- * Transform the given Builds to StreamEntries
- *
- * @param builds the Builds to transform
- * @param cancelled cancelled flag
- * @return the stream entries
- */
- private Iterable<StreamsEntry> transformEntries(
- Iterable<Build> builds,
- AtomicBoolean cancelled)
- {
- Set<Build> processed = new HashSet<>();
- List<StreamsEntry> entries = new ArrayList<>();
- for (Build build : builds)
- {
- if (cancelled.get())
- {
- throw new CancelledException();
- }
- if (!processed.contains(build))
- {
- try
- {
- entries.add(toStreamEntry(build));
- }
- catch (Exception e)
- {
- LOGGER.warn("Unable to get Streams Entry for build {}: {}", build, e.getMessage());
- LOGGER.debug("toStreamEntry error", e);
- }
- processed.add(build);
- }
- }
- return entries;
- }
- /**
- * Transform a {@link Build} to a {@link StreamsEntry}
- *
- * @param build the {@link Build} to transform
- * @return the {@link StreamsEntry}
- */
- private StreamsEntry toStreamEntry(final Build build)
- {
- final Job job = build.getJob();
- final Site site = job.getSite();
- StreamsEntry.ActivityObject activityObject = new StreamsEntry.ActivityObject(
- params().id(String.valueOf(build.getId())).alternateLinkUri(build.getDisplayUrl()));
- StreamsEntry.Renderer renderer = new StreamsEntry.Renderer()
- {
- @Override
- public Html renderTitleAsHtml(StreamsEntry streamsEntry)
- {
- Map<String, Object> context = new HashMap<>();
- String displayName = build.getDisplayName();
- if (StringUtils.isBlank(displayName))
- {
- displayName = job.getDisplayName() + " > #" + build.getNumber();
- }
- context.put("build_display_name", displayName);
- context.put("build_url", build.getDisplayUrl());
- context.put("build_deleted", build.isDeleted() || job.isDeleted());
- context.put("build_result", build.getResult().key());
- return new Html(renderTemplate("/templates/streams/stream-title.vm", context));
- }
- @Override
- public Option<Html> renderSummaryAsHtml(StreamsEntry streamsEntry)
- {
- return none();
- }
- @Override
- public Option<Html> renderContentAsHtml(StreamsEntry streamsEntry)
- {
- Map<String, Object> context = new HashMap<>();
- context.put("build_duration", build.getFormattedDuration());
- context.put("build_cause", build.getCause());
- context.put("node", build.getBuiltOn());
- return Option.some(new Html(renderTemplate("/templates/streams/stream-content.vm", context)));
- }
- };
- URI icon = fromUri(urlProvider.getStaticPluginResourceUrl(addonHelper.getCompleteModuleKey("images"), "images", ABSOLUTE)).path(
- "/icon96_{siteType}.png").build(site.getType().value());
- NonEmptyIterable<UserProfile> authors = of(new UserProfile.Builder(site.getName()).profilePictureUri(option(icon))
- .profilePageUri(option(site.getDisplayUrl()))
- .build());
- return new StreamsEntry(StreamsEntry.params()
- .id(build.getDisplayUrl())
- .postedDate(new DateTime(build.getTimestamp()))
- .authors(authors)
- .addActivityObject(activityObject)
- .verb(ActivityVerbs.post())
- .alternateLinkUri(build.getDisplayUrl())
- .renderer(renderer)
- .applicationType("org.marvelution.jenkins"), i18nResolver);
- }
- /**
- * Get all the Project keys where the user has view source permissions for
- *
- * @param inProjectKeys {@link Set} of project keys set in the gadget
- * @return the {@link Set} of projects to include in the filter
- */
- private Set<String> getInProjectsByPermission(Set<String> inProjectKeys)
- {
- Stream<Project> projects;
- if (inProjectKeys.isEmpty())
- {
- projects = projectManager.getProjectObjects().stream();
- }
- else
- {
- projects = inProjectKeys.stream().map(projectManager::getProjectObjByKey);
- }
- return projects.filter(project -> permissionManager.hasPermission(VIEW_DEV_TOOLS, project, authenticationContext.getLoggedInUser()))
- .map(Project::getKey)
- .collect(toSet());
- }
- /**
- * Render the given template using the given context
- *
- * @param template the template name
- * @param context the context {@link Map}
- * @return the rendered template
- */
- private String renderTemplate(
- String template,
- Map<String, Object> context)
- {
- StringWriter writer = new StringWriter();
- try
- {
- templateRenderer.render(template, context, writer);
- }
- catch (IOException e)
- {
- LOGGER.warn(e.getMessage());
- LOGGER.debug("Failed to render template: {}", template, e);
- }
- return writer.toString();
- }
- }