diff --git a/api/src/org/labkey/api/Constants.java b/api/src/org/labkey/api/Constants.java index 8440d771b1f..ce29f4e5405 100644 --- a/api/src/org/labkey/api/Constants.java +++ b/api/src/org/labkey/api/Constants.java @@ -56,7 +56,7 @@ public static double getEarliestUpgradeVersion() */ public static String getDocumentationVersion() { - return "26.7"; + return "26.11"; } /** diff --git a/api/src/org/labkey/api/reports/Report.java b/api/src/org/labkey/api/reports/Report.java index c5cbd0e8da8..eb938be47b7 100644 --- a/api/src/org/labkey/api/reports/Report.java +++ b/api/src/org/labkey/api/reports/Report.java @@ -53,7 +53,7 @@ public interface Report extends AttachmentParent, ThumbnailProvider /** * Render this report in the specified context */ - HttpView renderReport(ViewContext context) throws Exception; + HttpView renderReport(ViewContext context) throws Exception; /** * Return the data view (if any) for this report. Many reports are created from a source diff --git a/api/src/org/labkey/api/reports/report/DockerScriptReport.java b/api/src/org/labkey/api/reports/report/DockerScriptReport.java index 69978e25211..a88bab4ef10 100644 --- a/api/src/org/labkey/api/reports/report/DockerScriptReport.java +++ b/api/src/org/labkey/api/reports/report/DockerScriptReport.java @@ -21,15 +21,11 @@ import org.labkey.api.query.JavaScriptExportScriptFactory; import org.labkey.api.query.JavaScriptExportScriptModel; import org.labkey.api.query.QueryView; -import org.labkey.api.reports.report.r.ParamReplacement; import org.labkey.api.settings.AppProps; import org.labkey.api.view.ViewContext; import org.labkey.vfs.FileLike; -import javax.script.ScriptException; -import java.io.File; import java.util.List; -import java.util.Map; /** * This is a base class for Reports that encapsulate their report executing in a Docker container, for security and/or configuration control. @@ -43,15 +39,9 @@ */ abstract public class DockerScriptReport extends ScriptProcessReport { - protected DockerScriptReport(String reportType, String defaultDescriptorType) + protected DockerScriptReport(String defaultDescriptorType) { - super(reportType, defaultDescriptorType); - } - - @Override - public String runScript(ViewContext context, List outputSubst, File inputDataTsv, Map inputParameters) throws ScriptException - { - return "I'm abstract"; + super(defaultDescriptorType); } protected JSONObject createReportConfig(ViewContext context, FileLike ipynb) diff --git a/api/src/org/labkey/api/reports/report/ExternalScriptEngineReport.java b/api/src/org/labkey/api/reports/report/ExternalScriptEngineReport.java index 2f85fa265e3..6c1639d0d7c 100644 --- a/api/src/org/labkey/api/reports/report/ExternalScriptEngineReport.java +++ b/api/src/org/labkey/api/reports/report/ExternalScriptEngineReport.java @@ -188,6 +188,30 @@ public Thumbnail render(List parameters) throws IOException } } + private Thumbnail getThumbnail(List parameters) throws IOException + { + return handleParameters(this, parameters, new ParameterHandler<>() + { + private Thumbnail _thumbnail = null; + + @Override + public boolean handleParameter(ViewContext context, Report report, ParamReplacement param, List sectionNames) throws IOException + { + _thumbnail = param.renderThumbnail(context); + + // Return true (keep iterating) if we can't render this output as a thumbnail + return null == _thumbnail; + } + + @Override + public Thumbnail cleanup(ContainerUser context) + { + // TODO: Delete file? + return _thumbnail; + } + }); + } + interface Renderer { diff --git a/api/src/org/labkey/api/reports/report/JavaScriptReport.java b/api/src/org/labkey/api/reports/report/JavaScriptReport.java index acf0578ddcc..e9a1378da70 100644 --- a/api/src/org/labkey/api/reports/report/JavaScriptReport.java +++ b/api/src/org/labkey/api/reports/report/JavaScriptReport.java @@ -67,7 +67,7 @@ public String getDefaultScript() { try { - return (new JspTemplate("/org/labkey/api/reports/report/view/javaScriptReportExample.jsp")).render(); + return (new JspTemplate<>("/org/labkey/api/reports/report/view/javaScriptReportExample.jsp")).render(); } catch (Exception e) { diff --git a/api/src/org/labkey/api/reports/report/ScriptEngineReport.java b/api/src/org/labkey/api/reports/report/ScriptEngineReport.java index 19c13863c78..936a7448d5f 100644 --- a/api/src/org/labkey/api/reports/report/ScriptEngineReport.java +++ b/api/src/org/labkey/api/reports/report/ScriptEngineReport.java @@ -58,7 +58,6 @@ import org.labkey.api.reports.report.r.view.SvgOutput; import org.labkey.api.reports.report.r.view.TextOutput; import org.labkey.api.reports.report.r.view.TsvOutput; -import org.labkey.api.thumbnail.Thumbnail; import org.labkey.api.util.FileUtil; import org.labkey.api.util.UnexpectedException; import org.labkey.api.view.HttpView; @@ -444,7 +443,7 @@ public boolean handleParameter(ViewContext context, Report report, ParamReplacem } @Override - public List cleanup(ScriptEngineReport report, ContainerUser context) + public List cleanup(ContainerUser context) { if (report.shouldCleanup()) FileUtil.deleteDir(report.getReportDirFileLike(context.getContainer().getId()).toNioPathForWrite(), null); @@ -472,7 +471,7 @@ public boolean handleParameter(ViewContext context, Report report, ParamReplacem } @Override - public HttpView cleanup(ScriptEngineReport report, ContainerUser context) + public HttpView cleanup(ContainerUser context) { if (report.shouldCleanup()) view.addView(new TempFileCleanup(report.getReportDirFileLike(context.getContainer().getId()))); @@ -487,42 +486,15 @@ public boolean shouldCleanup() return !BooleanUtils.toBoolean(getDescriptor().getProperty(ScriptReportDescriptor.Prop.runInBackground)); } - - public Thumbnail getThumbnail(List parameters) throws IOException - { - return handleParameters(this, parameters, new ParameterHandler<>() - { - private Thumbnail _thumbnail = null; - - @Override - public boolean handleParameter(ViewContext context, Report report, ParamReplacement param, List sectionNames) throws IOException - { - _thumbnail = param.renderThumbnail(context); - - // Return true (keep iterating) if we can't render this output as a thumbnail - return null == _thumbnail; - } - - @Override - public Thumbnail cleanup(ScriptEngineReport report, ContainerUser context) - { - // TODO: Delete file? - return _thumbnail; - } - }); - } - - - private static K handleParameters(ScriptEngineReport report, Collection parameters, ParameterHandler handler) throws IOException + protected static K handleParameters(ScriptEngineReport report, Collection parameters, ParameterHandler handler) throws IOException { - String sections = HttpView.currentContext().getString(renderParam.showSection.name()); + ViewContext context = HttpView.currentContext(); + String sections = context.getString(renderParam.showSection.name()); List sectionNames = Collections.emptyList(); if (sections != null) sectionNames = Arrays.asList(sections.split("&")); - ViewContext context = HttpView.currentContext(); - for (ParamReplacement param : parameters) { if (isViewable(param, sectionNames)) @@ -534,18 +506,16 @@ private static K handleParameters(ScriptEngineReport report, Collection + protected interface ParameterHandler { boolean handleParameter(ViewContext context, Report report, ParamReplacement param, List sectionNames) throws IOException; - K cleanup(ScriptEngineReport report, ContainerUser context); + K cleanup(ContainerUser context); } - protected static boolean isViewable(ParamReplacement param, List sectionNames) { for (FileLike data : param.getFiles()) @@ -567,7 +537,6 @@ protected String createScript(ScriptEngine engine, ViewContext context, List outputSubst, FileLike inputDataTsv, Map inputParameters, boolean isRStudio) throws Exception { @@ -616,14 +585,6 @@ protected String processOutputReplacements(ScriptEngine engine, String script, L return ParamReplacementSvc.get().processParamReplacement(script, reportDir, null, replacements, isRStudio); } - - @Override - public ScriptReportDescriptor getDescriptor() - { - return super.getDescriptor(); - } - - @Override protected String getDefaultExtension(FolderExportContext context) { diff --git a/api/src/org/labkey/api/reports/report/ScriptProcessReport.java b/api/src/org/labkey/api/reports/report/ScriptProcessReport.java index 0d0b7a95f63..08f9a98673f 100644 --- a/api/src/org/labkey/api/reports/report/ScriptProcessReport.java +++ b/api/src/org/labkey/api/reports/report/ScriptProcessReport.java @@ -16,44 +16,17 @@ package org.labkey.api.reports.report; import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.labkey.api.admin.FolderExportContext; -import org.labkey.api.data.Container; import org.labkey.api.data.Results; -import org.labkey.api.reader.Readers; import org.labkey.api.reports.Report; -import org.labkey.api.reports.report.r.ParamReplacement; -import org.labkey.api.reports.report.r.ParamReplacementSvc; import org.labkey.api.reports.report.r.RReportJob; -import org.labkey.api.security.SessionApiKeyManager; -import org.labkey.api.security.User; -import org.labkey.api.thumbnail.Thumbnail; import org.labkey.api.util.FileUtil; -import org.labkey.api.view.HttpView; import org.labkey.api.view.ViewContext; -import org.labkey.api.writer.ContainerUser; import org.labkey.vfs.FileLike; -import javax.script.ScriptEngine; -import javax.script.ScriptException; -import java.io.BufferedReader; -import java.io.File; import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static org.labkey.api.reports.report.ScriptEngineReport.INPUT_FILE_TSV; /** - * - * User: Matthew Bellew - * Date: May 2022 - * * A Report implementation that uses an external process or script interpreter to execute the associated script. * * See Also ScriptEngineReport. @@ -63,32 +36,12 @@ */ public abstract class ScriptProcessReport extends ScriptReport implements Report.ResultSetGenerator { - final String reportType; final String defaultDescriptorType; private FileLike workingDirectory; - /* this is where we gather the context that will be passed to the script runner as a json file */ - public static class ReportContext + ScriptProcessReport(String defaultDescriptorType) { - User user; - Container container; - String apiKey; - - public static ReportContext from(ViewContext vc, Report r) - { - ReportContext rc = new ReportContext(); - rc.user = vc.getUser(); - rc.container = vc.getContainer(); - rc.apiKey = SessionApiKeyManager.get().getApiKey(vc.getRequest(), r.getClass().getName()); - return rc; - } - } - - - ScriptProcessReport(String reportType, String defaultDescriptorType) - { - this.reportType = reportType; this.defaultDescriptorType = defaultDescriptorType; } @@ -155,174 +108,4 @@ protected FileLike getReportDir(@NotNull String executingContainerId, boolean is } return workingDirectory; } - - - public Thumbnail getThumbnail(List parameters) throws IOException - { - return handleParameters(this, parameters, new ParameterHandler<>() - { - private Thumbnail _thumbnail = null; - - @Override - public boolean handleParameter(ViewContext context, Report report, ParamReplacement param, List sectionNames) throws IOException - { - _thumbnail = param.renderThumbnail(context); - - // Return true (keep iterating) if we can't render this output as a thumbnail - return null == _thumbnail; - } - - @Override - public Thumbnail cleanup(ScriptProcessReport report, ContainerUser context) - { - // TODO: Delete file? - return _thumbnail; - } - }); - } - - - private static K handleParameters(ScriptProcessReport report, Collection parameters, ParameterHandler handler) throws IOException - { - String sections = HttpView.currentContext().getString(renderParam.showSection.name()); - List sectionNames = Collections.emptyList(); - - if (sections != null) - sectionNames = Arrays.asList(sections.split("&")); - - ViewContext context = HttpView.currentContext(); - - for (ParamReplacement param : parameters) - { - if (isViewable(param, sectionNames)) - { - boolean keepGoing = handler.handleParameter(context, report, param, sectionNames); - - if (!keepGoing) - break; - } - } - - return handler.cleanup(report, context); - } - - - private interface ParameterHandler - { - boolean handleParameter(ViewContext context, Report report, ParamReplacement param, List sectionNames) throws IOException; - K cleanup(ScriptProcessReport report, ContainerUser context); - } - - - protected static boolean isViewable(ParamReplacement param, List sectionNames) - { - for (FileLike data : param.getFiles()) - { - if (data.exists()) - { - if (!sectionNames.isEmpty()) - return sectionNames.contains(param.getName()); - return true; - } - } - return false; - } - - public abstract String runScript(ViewContext context, List outputSubst, File inputDataTsv, Map inputParameters) throws ScriptException; - - /** - * Takes a script source, adds a prolog, processes any input and output replacement parameters - */ - protected String processScript(ScriptEngine engine, ViewContext context, String script, File inputFile, List outputSubst, Map inputParameters, boolean includeProlog, boolean isRStudio) throws Exception - { - if (!StringUtils.isEmpty(script) && isRStudio) - script = ParamReplacementSvc.get().transformInlineReplacements(script); // transform old inline syntax to comment syntax - if (includeProlog && (!StringUtils.isEmpty(script) || isRStudio)) - script = concatScriptProlog(engine, context, script == null ? "" : script, inputFile, inputParameters); - if (!StringUtils.isEmpty(script)) - { - if (inputFile != null || isRStudio) - script = processInputReplacement(script, inputFile, isRStudio); - script = processOutputReplacements(script, outputSubst, context, isRStudio); - } - return script; - } - - protected String getScriptProlog(ScriptEngine engine, ViewContext context, File inputFile, Map inputParameters) - { - return null; - } - - protected String concatScriptProlog(ScriptEngine engine, ViewContext context, String script, File inputFile, Map inputParameters) - { - return StringUtils.defaultString(getScriptProlog(engine, context, inputFile, inputParameters)) + script; - } - - protected String processInputReplacement(String script, @Nullable File inputFile, boolean isRStudio) - { - return ParamReplacementSvc.get().processInputReplacement(script, INPUT_FILE_TSV, inputFile == null ? null : inputFile.getAbsolutePath().replaceAll("\\\\", "/"), isRStudio, null); - } - - protected String processOutputReplacements(String script, List replacements, @NotNull ContainerUser context, boolean isRStudio) throws Exception - { - return ParamReplacementSvc.get().processParamReplacement(script, getReportDir(context.getContainer().getId()), null, replacements, isRStudio); - } - - - @Override - public ScriptReportDescriptor getDescriptor() - { - return super.getDescriptor(); - } - - - @Override - protected String getSerializedScriptFileName() - { - return getSerializedScriptFileName(null); - } - - - @Override - protected String getSerializedScriptFileName(FolderExportContext context) - { - String extension = "script"; - String reportName; - - ReportNameContext rnc = context.getContext(ReportNameContext.class); - reportName = rnc.getSerializedName(); - - return FileUtil.makeLegalName(String.format("%s.%s", reportName, extension)); - } - - @Override - public void afterDeserializeFromFile(File reportFile) throws IOException - { - if (reportFile.exists()) - { - // check to see if there is a separate script file on the disk, a separate - // script file takes precedence over any meta-data based script. - - File scriptFile = new File(reportFile.getParent(), getSerializedScriptFileName()); - - if (scriptFile.exists()) - { - StringBuilder sb = new StringBuilder(); - - try (BufferedReader br = Readers.getReader(scriptFile)) - { - String l; - - while ((l = br.readLine()) != null) - { - sb.append(l); - sb.append('\n'); - } - - getDescriptor().setProperty(ScriptReportDescriptor.Prop.script, sb.toString()); - } - } - } - } - } diff --git a/api/src/org/labkey/api/reports/report/ScriptReport.java b/api/src/org/labkey/api/reports/report/ScriptReport.java index 47e189eea8e..78d58bbb870 100644 --- a/api/src/org/labkey/api/reports/report/ScriptReport.java +++ b/api/src/org/labkey/api/reports/report/ScriptReport.java @@ -82,10 +82,6 @@ import java.util.List; /* -* User: adam -* Date: Dec 21, 2010 -* Time: 7:57:11 PM -* * This is a simple base class that represents reports that are defined by a text file (editable or static module file). * The subclass ScriptEngineReport is the base class for reports that use a ScriptEngine to interpret/execute this file. */ @@ -520,5 +516,4 @@ public void afterDeserializeFromFile(File reportFile) throws IOException } } } - } diff --git a/api/src/org/labkey/api/reports/report/python/IpynbReport.java b/api/src/org/labkey/api/reports/report/python/IpynbReport.java index f5b4e9dbedd..be938644e0e 100644 --- a/api/src/org/labkey/api/reports/report/python/IpynbReport.java +++ b/api/src/org/labkey/api/reports/report/python/IpynbReport.java @@ -106,12 +106,7 @@ public record Env(String env, String header) {} public IpynbReport() { - this(TYPE, IpynbReportDescriptor.DESCRIPTOR_TYPE); - } - - IpynbReport(String reportType, String defaultDescriptorType) - { - super(reportType, defaultDescriptorType); + super(IpynbReportDescriptor.DESCRIPTOR_TYPE); } @Override @@ -272,13 +267,6 @@ private static void logFiles(FileLike parentDir, String label) } - @Override - protected JSONObject createReportConfig(ViewContext context, FileLike scriptFile) - { - return super.createReportConfig(context, scriptFile); - } - - @NotNull URL getServiceAddress(Container c) throws ConfigurationException {