mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-20 22:18:43 +00:00
CE-881 - Update RenderSavedReport process to stream results to a backend through new StorageAction.
This commit is contained in:
@ -24,13 +24,21 @@ package com.kingsrook.qqq.backend.core.model.savedreports;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.DefaultWidgetRenderer;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormatPossibleValueEnum;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaDataInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier;
|
||||
@ -42,17 +50,66 @@ import com.kingsrook.qqq.backend.core.processes.implementations.savedreports.Ren
|
||||
*******************************************************************************/
|
||||
public class SavedReportsMetaDataProvider
|
||||
{
|
||||
public static final String REPORT_STORAGE_TABLE_NAME = "reportStorage";
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void defineAll(QInstance instance, String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
|
||||
public void defineAll(QInstance instance, String recordTablesBackendName, String reportStorageBackendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
|
||||
{
|
||||
instance.addTable(defineSavedReportTable(backendName, backendDetailEnricher));
|
||||
instance.addTable(defineSavedReportTable(recordTablesBackendName, backendDetailEnricher));
|
||||
instance.addPossibleValueSource(QPossibleValueSource.newForTable(SavedReport.TABLE_NAME));
|
||||
instance.addPossibleValueSource(QPossibleValueSource.newForEnum(ReportFormatPossibleValueEnum.NAME, ReportFormatPossibleValueEnum.values()));
|
||||
instance.addProcess(new RenderSavedReportMetaDataProducer().produce(instance));
|
||||
|
||||
instance.addTable(defineReportStorageTable(reportStorageBackendName, backendDetailEnricher));
|
||||
|
||||
QProcessMetaData renderSavedReportProcess = new RenderSavedReportMetaDataProducer().produce(instance);
|
||||
instance.addProcess(renderSavedReportProcess);
|
||||
renderSavedReportProcess.getInputFields().stream()
|
||||
.filter(f -> RenderSavedReportMetaDataProducer.FIELD_NAME_STORAGE_TABLE_NAME.equals(f.getName()))
|
||||
.findFirst()
|
||||
.ifPresent(f -> f.setDefaultValue(REPORT_STORAGE_TABLE_NAME));
|
||||
|
||||
instance.addWidget(defineReportSetupWidget());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private QTableMetaData defineReportStorageTable(String backendName, Consumer<QTableMetaData> backendDetailEnricher)
|
||||
{
|
||||
QTableMetaData table = new QTableMetaData()
|
||||
.withName(REPORT_STORAGE_TABLE_NAME)
|
||||
.withBackendName(backendName)
|
||||
.withPrimaryKeyField("reference")
|
||||
.withField(new QFieldMetaData("reference", QFieldType.STRING))
|
||||
.withField(new QFieldMetaData("contents", QFieldType.BLOB));
|
||||
|
||||
if(backendDetailEnricher != null)
|
||||
{
|
||||
backendDetailEnricher.accept(table);
|
||||
}
|
||||
|
||||
return (table);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private QWidgetMetaDataInterface defineReportSetupWidget()
|
||||
{
|
||||
return new QWidgetMetaData()
|
||||
.withName("reportSetupWidget")
|
||||
.withLabel("Report Setup")
|
||||
.withIsCard(true)
|
||||
.withType(WidgetType.REPORT_SETUP.getType())
|
||||
.withCodeReference(new QCodeReference(DefaultWidgetRenderer.class));
|
||||
}
|
||||
|
||||
|
||||
@ -73,6 +130,7 @@ public class SavedReportsMetaDataProvider
|
||||
.withFieldsFromEntity(SavedReport.class)
|
||||
.withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id", "label")))
|
||||
.withSection(new QFieldSection("settings", new QIcon().withName("settings"), Tier.T2, List.of("tableName")))
|
||||
.withSection(new QFieldSection("reportSetup", new QIcon().withName("table_chart"), Tier.T2).withWidgetName("reportSetupWidget"))
|
||||
.withSection(new QFieldSection("data", new QIcon().withName("text_snippet"), Tier.T2, List.of("queryFilterJson", "columnsJson", "pivotTableJson")))
|
||||
.withSection(new QFieldSection("hidden", new QIcon().withName("text_snippet"), Tier.T2, List.of("inputFieldsJson", "userId")).withIsHidden(true))
|
||||
.withSection(new QFieldSection("dates", new QIcon().withName("calendar_month"), Tier.T3, List.of("createDate", "modifyDate")));
|
||||
|
@ -22,15 +22,16 @@
|
||||
package com.kingsrook.qqq.backend.core.processes.implementations.savedreports;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.GenerateReportAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.StorageAction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||
@ -38,6 +39,7 @@ import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutp
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportDestination;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.storage.StorageInput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
@ -60,32 +62,33 @@ public class RenderSavedReportExecuteStep implements BackendStep
|
||||
{
|
||||
try
|
||||
{
|
||||
ReportFormat reportFormat = ReportFormat.fromString(runBackendStepInput.getValueString("reportFormat"));
|
||||
String storageTableName = runBackendStepInput.getValueString(RenderSavedReportMetaDataProducer.FIELD_NAME_STORAGE_TABLE_NAME);
|
||||
ReportFormat reportFormat = ReportFormat.fromString(runBackendStepInput.getValueString(RenderSavedReportMetaDataProducer.FIELD_NAME_REPORT_FORMAT));
|
||||
|
||||
SavedReport savedReport = new SavedReport(runBackendStepInput.getRecords().get(0));
|
||||
File tmpFile = File.createTempFile("SavedReport" + savedReport.getId(), "." + reportFormat.getExtension(), new File("/tmp/"));
|
||||
SavedReport savedReport = new SavedReport(runBackendStepInput.getRecords().get(0));
|
||||
String downloadFileBaseName = getDownloadFileBaseName(runBackendStepInput, savedReport);
|
||||
String storageReference = UUID.randomUUID() + "/" + downloadFileBaseName + "." + reportFormat.getExtension();
|
||||
|
||||
OutputStream outputStream = new StorageAction().createOutputStream(new StorageInput(storageTableName).withReference(storageReference));
|
||||
|
||||
runBackendStepInput.getAsyncJobCallback().updateStatus("Generating Report");
|
||||
|
||||
QReportMetaData reportMetaData = new SavedReportToReportMetaDataAdapter().adapt(savedReport, reportFormat);
|
||||
|
||||
try(FileOutputStream reportOutputStream = new FileOutputStream(tmpFile))
|
||||
{
|
||||
ReportInput reportInput = new ReportInput();
|
||||
reportInput.setReportMetaData(reportMetaData);
|
||||
reportInput.setReportDestination(new ReportDestination()
|
||||
.withReportFormat(reportFormat)
|
||||
.withReportOutputStream(reportOutputStream));
|
||||
ReportInput reportInput = new ReportInput();
|
||||
reportInput.setReportMetaData(reportMetaData);
|
||||
reportInput.setReportDestination(new ReportDestination()
|
||||
.withReportFormat(reportFormat)
|
||||
.withReportOutputStream(outputStream));
|
||||
|
||||
Map<String, Serializable> values = runBackendStepInput.getValues();
|
||||
reportInput.setInputValues(values);
|
||||
Map<String, Serializable> values = runBackendStepInput.getValues();
|
||||
reportInput.setInputValues(values);
|
||||
|
||||
new GenerateReportAction().execute(reportInput);
|
||||
}
|
||||
new GenerateReportAction().execute(reportInput);
|
||||
|
||||
String downloadFileBaseName = getDownloadFileBaseName(runBackendStepInput, savedReport);
|
||||
runBackendStepOutput.addValue("downloadFileName", downloadFileBaseName + "." + reportFormat.getExtension());
|
||||
runBackendStepOutput.addValue("serverFilePath", tmpFile.getCanonicalPath());
|
||||
runBackendStepOutput.addValue("storageTableName", storageTableName);
|
||||
runBackendStepOutput.addValue("storageReference", storageReference);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
@ -47,6 +47,9 @@ public class RenderSavedReportMetaDataProducer implements MetaDataProducerInterf
|
||||
{
|
||||
public static final String NAME = "renderSavedReport";
|
||||
|
||||
public static final String FIELD_NAME_STORAGE_TABLE_NAME = "storageTableName";
|
||||
public static final String FIELD_NAME_REPORT_FORMAT = "reportFormat";
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -61,13 +64,14 @@ public class RenderSavedReportMetaDataProducer implements MetaDataProducerInterf
|
||||
.withIcon(new QIcon().withName("print"))
|
||||
.addStep(new QBackendStepMetaData()
|
||||
.withName("pre")
|
||||
.withInputData(new QFunctionInputMetaData().withRecordListMetaData(new QRecordListMetaData()
|
||||
.withTableName(SavedReport.TABLE_NAME)))
|
||||
.withInputData(new QFunctionInputMetaData()
|
||||
.withField(new QFieldMetaData(FIELD_NAME_STORAGE_TABLE_NAME, QFieldType.STRING))
|
||||
.withRecordListMetaData(new QRecordListMetaData().withTableName(SavedReport.TABLE_NAME)))
|
||||
.withCode(new QCodeReference(RenderSavedReportPreStep.class)))
|
||||
.addStep(new QFrontendStepMetaData()
|
||||
.withName("input")
|
||||
.withComponent(new QFrontendComponentMetaData().withType(QComponentType.EDIT_FORM))
|
||||
.withFormField(new QFieldMetaData("reportFormat", QFieldType.STRING)
|
||||
.withFormField(new QFieldMetaData(FIELD_NAME_REPORT_FORMAT, QFieldType.STRING)
|
||||
.withPossibleValueSourceName(ReportFormatPossibleValueEnum.NAME)
|
||||
.withIsRequired(true)))
|
||||
.addStep(new QBackendStepMetaData()
|
||||
|
@ -22,10 +22,17 @@
|
||||
package com.kingsrook.qqq.backend.core.processes.implementations.savedreports;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -40,8 +47,30 @@ public class RenderSavedReportPreStep implements BackendStep
|
||||
@Override
|
||||
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
|
||||
{
|
||||
// todo - verify ran on 1
|
||||
// todo - load the SavedReport
|
||||
String storageTableName = runBackendStepInput.getValueString(RenderSavedReportMetaDataProducer.FIELD_NAME_STORAGE_TABLE_NAME);
|
||||
if(!StringUtils.hasContent(storageTableName))
|
||||
{
|
||||
throw (new QUserFacingException("Process configuration error: Missing value for storageTableName."));
|
||||
}
|
||||
|
||||
if(QContext.getQInstance().getTable(storageTableName) == null)
|
||||
{
|
||||
throw (new QUserFacingException("Process configuration error: Unrecognized value for storageTableName - no table named [" + storageTableName + "] was found in the instance."));
|
||||
}
|
||||
|
||||
List<QRecord> records = runBackendStepInput.getRecords();
|
||||
if(!CollectionUtils.nullSafeHasContents(records))
|
||||
{
|
||||
throw (new QUserFacingException("No report was selected or found to be rendered."));
|
||||
}
|
||||
|
||||
if(records.size() > 1)
|
||||
{
|
||||
throw (new QUserFacingException("You may only render 1 report at a time."));
|
||||
}
|
||||
|
||||
SavedReport savedReport = new SavedReport(records.get(0));
|
||||
|
||||
// todo - check for inputs - set up the input screen...
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user