package se.bjurr.prnfb.service; import static com.google.common.base.Charsets.UTF_8; import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.base.Throwables.propagate; import static java.net.URLEncoder.encode; import static org.slf4j.LoggerFactory.getLogger; import static se.bjurr.prnfb.service.PrnfbRenderer.ENCODE_FOR.HTML; import static se.bjurr.prnfb.service.PrnfbRenderer.ENCODE_FOR.URL; import static se.bjurr.prnfb.service.PrnfbVariable.EVERYTHING_URL; import java.io.UnsupportedEncodingException; import java.util.Map; import org.apache.commons.lang3.StringEscapeUtils; import org.slf4j.Logger; import com.atlassian.bitbucket.pull.PullRequest; import com.atlassian.bitbucket.repository.RepositoryService; import com.atlassian.bitbucket.server.ApplicationPropertiesService; import com.atlassian.bitbucket.user.ApplicationUser; import com.atlassian.bitbucket.user.SecurityService; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Supplier; import se.bjurr.prnfb.http.ClientKeyStore; import se.bjurr.prnfb.listener.PrnfbPullRequestAction; import se.bjurr.prnfb.settings.PrnfbNotification; public class PrnfbRenderer { public enum ENCODE_FOR { NONE, URL, HTML } private static final Logger LOG = getLogger(PrnfbRenderer.class); private final ApplicationUser applicationUser; private final PrnfbNotification prnfbNotification; private final ApplicationPropertiesService propertiesService; private final PullRequest pullRequest; private final PrnfbPullRequestAction pullRequestAction; private final RepositoryService repositoryService; private final SecurityService securityService; /** * Contains special variables that are only available for specific events like {@link * PrnfbVariable#BUTTON_TRIGGER_TITLE} and {@link PrnfbVariable#PULL_REQUEST_COMMENT_TEXT}. */ private final Map<PrnfbVariable, Supplier<String>> variables; PrnfbRenderer( PullRequest pullRequest, PrnfbPullRequestAction pullRequestAction, ApplicationUser applicationUser, RepositoryService repositoryService, ApplicationPropertiesService propertiesService, PrnfbNotification prnfbNotification, Map<PrnfbVariable, Supplier<String>> variables, SecurityService securityService) { this.pullRequest = pullRequest; this.pullRequestAction = pullRequestAction; this.applicationUser = applicationUser; this.repositoryService = repositoryService; this.prnfbNotification = prnfbNotification; this.propertiesService = propertiesService; this.variables = variables; this.securityService = securityService; } private boolean containsVariable(String string, final String regExpStr) { if (isNullOrEmpty(string)) { return false; } return string.contains(regExpStr.replaceAll("\\\\", "")); } @VisibleForTesting String getRenderedStringResolved( String string, ENCODE_FOR encodeFor, final String regExpStr, String resolved) { String replaceWith = null; if (encodeFor == URL) { try { replaceWith = encode(resolved, UTF_8.name()); } catch (UnsupportedEncodingException e) { propagate(e); } } else if (encodeFor == HTML) { replaceWith = StringEscapeUtils.escapeHtml4(resolved); } else { replaceWith = resolved; } try { string = string.replaceAll(regExpStr, replaceWith); } catch (IllegalArgumentException e) { throw new RuntimeException("Tried to replace " + regExpStr + " with " + replaceWith, e); } return string; } @VisibleForTesting String regexp(PrnfbVariable variable) { return "\\$\\{" + variable.name() + "\\}"; } public String render( String string, ENCODE_FOR encodeFor, ClientKeyStore clientKeyStore, Boolean shouldAcceptAnyCertificate) { string = renderVariable( string, ENCODE_FOR.NONE, clientKeyStore, shouldAcceptAnyCertificate, EVERYTHING_URL); for (final PrnfbVariable variable : PrnfbVariable.values()) { string = renderVariable(string, encodeFor, clientKeyStore, shouldAcceptAnyCertificate, variable); } return string; } private String renderVariable( String string, ENCODE_FOR encodeFor, ClientKeyStore clientKeyStore, Boolean shouldAcceptAnyCertificate, final PrnfbVariable variable) { final String regExpStr = regexp(variable); if (containsVariable(string, regExpStr)) { String resolved = ""; try { resolved = variable.resolve( pullRequest, pullRequestAction, applicationUser, repositoryService, propertiesService, prnfbNotification, variables, clientKeyStore, shouldAcceptAnyCertificate, securityService); if (resolved == null) { resolved = ""; } } catch (Exception e) { LOG.error("Error when resolving " + variable, e); } return getRenderedStringResolved(string, encodeFor, regExpStr, resolved); } return string; } }