mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-17 20:50:44 +00:00
CE-881 - Bridge code for RenderSavedReportProcess in qqq-middleware-api
This commit is contained in:
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.api.implementations.savedreports;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.PreRunApiProcessCustomizer;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.QProcessCallbackFactory;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** API-Customizer for the RenderSavedReport process
|
||||
*******************************************************************************/
|
||||
public class RenderSavedReportProcessApiCustomizer implements PreRunApiProcessCustomizer
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void preApiRun(RunProcessInput runProcessInput) throws QException
|
||||
{
|
||||
Integer reportId = runProcessInput.getValueInteger("reportId");
|
||||
if(reportId != null)
|
||||
{
|
||||
QRecord record = new GetAction().executeForRecord(new GetInput(SavedReport.TABLE_NAME).withPrimaryKey(reportId));
|
||||
if(record == null)
|
||||
{
|
||||
throw (new QNotFoundException("Report Id " + reportId + " was not found."));
|
||||
}
|
||||
|
||||
runProcessInput.setCallback(QProcessCallbackFactory.forPrimaryKey("id", reportId));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.api.implementations.savedreports;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessCustomizers;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessInput;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessInputFieldsContainer;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.openapi.ExampleWithListValue;
|
||||
import com.kingsrook.qqq.api.model.openapi.ExampleWithSingleValue;
|
||||
import com.kingsrook.qqq.api.model.openapi.HttpMethod;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormatPossibleValueEnum;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
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.processes.QProcessMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Class that helps prepare the RenderSavedReport process for use in an API
|
||||
*******************************************************************************/
|
||||
public class RenderSavedReportProcessApiMetaDataEnricher
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static ApiProcessMetaData setupProcessForApi(QProcessMetaData process, String apiName, String initialApiVersion)
|
||||
{
|
||||
ApiProcessMetaDataContainer apiProcessMetaDataContainer = ApiProcessMetaDataContainer.ofOrWithNew(process);
|
||||
|
||||
ApiProcessInput input = new ApiProcessInput()
|
||||
.withPathParams(new ApiProcessInputFieldsContainer()
|
||||
.withField(new QFieldMetaData("reportId", QFieldType.INTEGER)
|
||||
.withIsRequired(true)
|
||||
.withSupplementalMetaData(newDefaultApiFieldMetaData("Saved Report Id", 1701))))
|
||||
.withQueryStringParams(new ApiProcessInputFieldsContainer()
|
||||
.withField(new QFieldMetaData("reportFormat", QFieldType.STRING)
|
||||
.withIsRequired(true)
|
||||
.withPossibleValueSourceName(ReportFormatPossibleValueEnum.NAME)
|
||||
.withSupplementalMetaData(newDefaultApiFieldMetaData("Requested file format", "XLSX"))));
|
||||
// todo (when implemented) - probably a JSON doc w/ input values.
|
||||
|
||||
RenderSavedReportProcessApiProcessOutput output = new RenderSavedReportProcessApiProcessOutput();
|
||||
|
||||
ApiProcessMetaData apiProcessMetaData = new ApiProcessMetaData()
|
||||
.withInitialVersion(initialApiVersion)
|
||||
.withCustomizer(ApiProcessCustomizers.PRE_RUN.getRole(), new QCodeReference(RenderSavedReportProcessApiCustomizer.class))
|
||||
.withAsyncMode(ApiProcessMetaData.AsyncMode.OPTIONAL)
|
||||
.withMethod(HttpMethod.GET)
|
||||
.withInput(input)
|
||||
.withOutput(output);
|
||||
|
||||
apiProcessMetaDataContainer.withApiProcessMetaData(apiName, apiProcessMetaData);
|
||||
|
||||
return (apiProcessMetaData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** todo - move to higher-level utility
|
||||
*******************************************************************************/
|
||||
public static ApiFieldMetaDataContainer newDefaultApiFieldMetaData(String description, Serializable example)
|
||||
{
|
||||
ApiFieldMetaData defaultApiFieldMetaData = new ApiFieldMetaData().withDescription(description);
|
||||
ApiFieldMetaDataContainer apiFieldMetaDataContainer = new ApiFieldMetaDataContainer().withDefaultApiFieldMetaData(defaultApiFieldMetaData);
|
||||
if(example instanceof List)
|
||||
{
|
||||
defaultApiFieldMetaData.withExample(new ExampleWithListValue().withValue((List<String>) example));
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultApiFieldMetaData.withExample(new ExampleWithSingleValue().withValue(example));
|
||||
}
|
||||
|
||||
return (apiFieldMetaDataContainer);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.api.implementations.savedreports;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.api.model.actions.HttpApiResponse;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessOutputInterface;
|
||||
import com.kingsrook.qqq.api.model.openapi.Content;
|
||||
import com.kingsrook.qqq.api.model.openapi.Response;
|
||||
import com.kingsrook.qqq.api.model.openapi.Schema;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** api process output specifier for the RenderSavedReport process
|
||||
*******************************************************************************/
|
||||
public class RenderSavedReportProcessApiProcessOutput implements ApiProcessOutputInterface
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public Serializable getOutputForProcess(RunProcessInput runProcessInput, RunProcessOutput runProcessOutput) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
ReportFormat reportFormat = ReportFormat.fromString(runProcessOutput.getValueString("reportFormat"));
|
||||
|
||||
String filePath = runProcessOutput.getValueString("serverFilePath");
|
||||
File file = new File(filePath);
|
||||
if(reportFormat.getIsBinary())
|
||||
{
|
||||
return FileUtils.readFileToByteArray(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
return FileUtils.readFileToString(file, Charset.defaultCharset());
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new QException("Error streaming report contents", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void customizeHttpApiResponse(HttpApiResponse httpApiResponse, RunProcessInput runProcessInput, RunProcessOutput runProcessOutput) throws QException
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// we don't need anyone else to format our response - assume that we've done so ourselves. //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
httpApiResponse.setNeedsFormattedAsJson(false);
|
||||
|
||||
ReportFormat reportFormat = ReportFormat.fromString(runProcessOutput.getValueString("reportFormat"));
|
||||
httpApiResponse.setContentType(reportFormat.getMimeType());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public HttpStatus.Code getSuccessStatusCode(RunProcessInput runProcessInput, RunProcessOutput runProcessOutput)
|
||||
{
|
||||
return (HttpStatus.Code.OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public Map<Integer, Response> getSpecResponses(String apiName)
|
||||
{
|
||||
return Map.of(HttpStatus.Code.OK.getCode(), new Response()
|
||||
.withDescription("Report contents in the requested format.")
|
||||
.withContent(Map.of(
|
||||
ReportFormat.JSON.getMimeType(), new Content()
|
||||
.withSchema(new Schema()
|
||||
.withDescription("JSON Report contents")
|
||||
.withExample("""
|
||||
[
|
||||
{"id": 1, "name": "James"},
|
||||
{"id": 2, "name": "Jean-Luc"}
|
||||
]
|
||||
""")
|
||||
.withType("string")
|
||||
.withFormat("text")),
|
||||
ReportFormat.CSV.getMimeType(), new Content()
|
||||
.withSchema(new Schema()
|
||||
.withDescription("CSV Report contents")
|
||||
.withExample("""
|
||||
"id","name"
|
||||
1,"James"
|
||||
2,"Jean-Luc"
|
||||
""")
|
||||
.withType("string")
|
||||
.withFormat("text")),
|
||||
ReportFormat.XLSX.getMimeType(), new Content()
|
||||
.withSchema(new Schema()
|
||||
.withDescription("Excel Report contents")
|
||||
.withType("string")
|
||||
.withFormat("binary"))
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -24,6 +24,7 @@ package com.kingsrook.qqq.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import com.kingsrook.qqq.api.implementations.savedreports.RenderSavedReportProcessApiMetaDataEnricher;
|
||||
import com.kingsrook.qqq.api.model.APIVersion;
|
||||
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaDataContainer;
|
||||
@ -45,6 +46,7 @@ import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||
@ -71,7 +73,10 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMeta
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.Association;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.TablesPossibleValueSourceMetaDataProvider;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey;
|
||||
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
|
||||
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReportsMetaDataProvider;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.BadInputStatusMessage;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.SystemErrorStatusMessage;
|
||||
@ -79,6 +84,7 @@ import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.Mem
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.ExtractViaQueryStep;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.LoadViaUpdateStep;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.StreamedETLWithFrontendProcess;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.savedreports.RenderSavedReportMetaDataProducer;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
|
||||
|
||||
@ -112,7 +118,7 @@ public class TestUtils
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static QInstance defineInstance()
|
||||
public static QInstance defineInstance() throws QException
|
||||
{
|
||||
QInstance qInstance = new QInstance();
|
||||
|
||||
@ -133,6 +139,8 @@ public class TestUtils
|
||||
|
||||
qInstance.setAuthentication(new Auth0AuthenticationMetaData().withType(QAuthenticationType.FULLY_ANONYMOUS).withName("anonymous"));
|
||||
|
||||
addSavedReports(qInstance);
|
||||
|
||||
qInstance.withSupplementalMetaData(new ApiInstanceMetaDataContainer()
|
||||
.withApiInstanceMetaData(new ApiInstanceMetaData()
|
||||
.withName(API_NAME)
|
||||
@ -161,6 +169,18 @@ public class TestUtils
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void addSavedReports(QInstance qInstance) throws QException
|
||||
{
|
||||
qInstance.add(TablesPossibleValueSourceMetaDataProvider.defineTablesPossibleValueSource(qInstance));
|
||||
new SavedReportsMetaDataProvider().defineAll(qInstance, MEMORY_BACKEND_NAME, null);
|
||||
RenderSavedReportProcessApiMetaDataEnricher.setupProcessForApi(qInstance.getProcess(RenderSavedReportMetaDataProducer.NAME), API_NAME, V2022_Q4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -531,6 +551,19 @@ public class TestUtils
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static Integer insertSavedReport(SavedReport savedReport) throws QException
|
||||
{
|
||||
InsertInput insertInput = new InsertInput();
|
||||
insertInput.setTableName(SavedReport.TABLE_NAME);
|
||||
insertInput.setRecords(List.of(savedReport.toQRecord()));
|
||||
InsertOutput insertOutput = new InsertAction().execute(insertInput);
|
||||
return insertOutput.getRecords().get(0).getValueInteger("id");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
|
Reference in New Issue
Block a user