package com.atlassian.labs.speakeasy.ui;
import com.atlassian.labs.speakeasy.external.SpeakeasyService;
import com.atlassian.labs.speakeasy.external.UnauthorizedAccessException;
import com.atlassian.labs.speakeasy.commonjs.CommonJsModules;
import com.atlassian.labs.speakeasy.commonjs.CommonJsModulesAccessor;
import com.atlassian.labs.speakeasy.model.UserExtension;
import com.atlassian.labs.speakeasy.model.UserPlugins;
import com.atlassian.labs.speakeasy.product.ProductAccessor;
import com.atlassian.labs.speakeasy.proxy.ApplinkPanelRenderer;
import com.atlassian.plugin.Plugin;
import com.atlassian.plugin.PluginAccessor;
import com.atlassian.plugin.web.WebInterfaceManager;
import com.atlassian.plugin.webresource.UrlMode;
import com.atlassian.plugin.webresource.WebResourceManager;
import com.atlassian.sal.api.ApplicationProperties;
import com.atlassian.sal.api.user.UserManager;
import com.atlassian.sal.api.xsrf.XsrfTokenAccessor;
import com.atlassian.sal.api.xsrf.XsrfTokenValidator;
import com.atlassian.templaterenderer.TemplateRenderer;
import com.atlassian.templaterenderer.annotations.HtmlSafe;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import java.util.Collections;
import java.util.Map;
import static com.google.common.collect.Collections2.filter;
import static java.util.Collections.singletonMap;
/**
*
*/
@Component
public class UserProfileRenderer
{
private final TemplateRenderer templateRenderer;
private final SpeakeasyService speakeasyService;
private final UserManager userManager;
private final WebResourceManager webResourceManager;
private final CommonJsModulesAccessor commonJsModulesAccessor;
private final ProductAccessor productAccessor;
private final ApplicationProperties applicationProperties;
private final Plugin plugin;
private final WebInterfaceManager webInterfaceManager;
private final XsrfTokenAccessor xsrfTokenAccessor;
private final XsrfTokenValidator xsrfTokenValidator;
private final ApplinkPanelRenderer applinkPanelRenderer;
private final FirefoxXpi firefoxXpi;
@Autowired
public UserProfileRenderer(PluginAccessor pluginAccessor, TemplateRenderer templateRenderer, SpeakeasyService speakeasyService, UserManager userManager, WebResourceManager webResourceManager, ProductAccessor productAccessor, CommonJsModulesAccessor commonJsModulesAccessor, WebInterfaceManager webInterfaceManager, XsrfTokenAccessor xsrfTokenAccessor, XsrfTokenValidator xsrfTokenValidator, ApplicationProperties applicationProperties, FirefoxXpi firefoxXpi, ApplinkPanelRenderer applinkPanelRenderer)
{
this.templateRenderer = templateRenderer;
this.commonJsModulesAccessor = commonJsModulesAccessor;
this.webInterfaceManager = webInterfaceManager;
this.xsrfTokenAccessor = xsrfTokenAccessor;
this.xsrfTokenValidator = xsrfTokenValidator;
this.applicationProperties = applicationProperties;
this.firefoxXpi = firefoxXpi;
this.applinkPanelRenderer = applinkPanelRenderer;
this.plugin = pluginAccessor.getPlugin("com.atlassian.labs.speakeasy-plugin");
this.speakeasyService = speakeasyService;
this.userManager = userManager;
this.webResourceManager = webResourceManager;
this.productAccessor = productAccessor;
}
public boolean shouldRender(String userName)
{
return speakeasyService.canAccessSpeakeasy(userName);
}
public void render(HttpServletRequest req, HttpServletResponse resp, Writer output, boolean useUserProfileDecorator) throws IOException, UnauthorizedAccessException
{
String user = userManager.getRemoteUsername(req);
if (user == null)
{
throw new UnauthorizedAccessException(null, "Unauthorized - must be logged in and have access to Speakeasy");
}
webResourceManager.requireResource("com.atlassian.auiplugin:ajs");
webResourceManager.requireResourcesForContext("speakeasy.user-profile");
boolean devMode = speakeasyService.canAuthorExtensions(user);
final UserPlugins plugins = speakeasyService.getRemotePluginList(user);
render("templates/user" + (useUserProfileDecorator ? "-with-decorator" : "") + ".vm", ImmutableMap.<String, Object>builder().
put("accessList", speakeasyService.getRemotePluginList(user)).
put("user", user).
put("req", req).
put("baseUrl", applicationProperties.getBaseUrl()).
put("contextPath", req.getContextPath()).
put("enabledPlugins", filter(plugins.getPlugins(), new EnabledPluginsFilter())).
put("availablePlugins", filter(plugins.getPlugins(), new AvailablePluginsFilter())).
put("rowRenderer", new RowRenderer(req.getContextPath(), plugin)).
put("jsdocRenderer", new JsDocRenderer(plugin, commonJsModulesAccessor.getAllPublicCommonJsModules())).
put("staticResourcesPrefix", webResourceManager.getStaticResourcePrefix(UrlMode.RELATIVE)).
put("product", productAccessor.getSdkName()).
put("devmode", devMode).
put("canAuthor", speakeasyService.canAuthorExtensions(user)).
put("doesAnyGroupHaveAccess", speakeasyService.doesAnyGroupHaveAccess()).
put("webInterfaceManager", webInterfaceManager).
put("webInterfaceContext", Collections.<String, Object>emptyMap()).
put("xsrfToken", xsrfTokenAccessor.getXsrfToken(req, resp, true)).
put("xsrfTokenName", xsrfTokenValidator.getXsrfParameterName()).
put("applinksRenderer", applinkPanelRenderer).
put("firefoxXpi", firefoxXpi).
build(), output);
}
protected void render(final String template, final Map<String, Object> renderContext,
final Writer output)
throws IOException
{
templateRenderer.render(template, renderContext, output);
}
public static class RowRenderer
{
private final Template rowTemplate;
private final String contextPath;
public RowRenderer(String contextPath, Plugin plugin)
{
this.contextPath = contextPath;
this.rowTemplate = compile(plugin, "packages/user/speakeasy/user/row.mu");
}
@HtmlSafe
@com.atlassian.velocity.htmlsafe.HtmlSafe
public String render(UserExtension plugin)
{
plugin.getParams().put("screenshotUrl", contextPath + "/rest/speakeasy/1/plugins/screenshot/" + plugin.getKey() + ".png");
return rowTemplate.execute(plugin);
}
}
public static class JsDocRenderer
{
private final Template template;
private final Iterable<CommonJsModules> modules;
public JsDocRenderer(Plugin plugin, Iterable<CommonJsModules> modules)
{
this.modules = modules;
this.template = compile(plugin, "packages/user/speakeasy/user/jsdoc/tree-template.mu");
}
@HtmlSafe
@com.atlassian.velocity.htmlsafe.HtmlSafe
public String render()
{
return template.execute(singletonMap("pluginModules", modules));
}
}
private static Template compile(Plugin plugin, String path)
{
InputStream in = null;
try
{
in = plugin.getResourceAsStream(path);
return Mustache.compiler().standardsMode(true).compile(new InputStreamReader(in));
}
finally
{
IOUtils.closeQuietly(in);
}
}
private static class EnabledPluginsFilter implements Predicate<UserExtension>
{
public boolean apply(UserExtension input)
{
return input.isEnabled();
}
}
private static class AvailablePluginsFilter implements Predicate<UserExtension>
{
public boolean apply(UserExtension input)
{
return !input.isEnabled();
}
}
}