mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
CE-1887 Initial (not quite finished) version 1 middleware api spec
This commit is contained in:
@ -63,12 +63,10 @@ import com.kingsrook.qqq.backend.core.actions.values.SearchPossibleValueSourceAc
|
||||
import com.kingsrook.qqq.backend.core.adapters.QInstanceAdapter;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QBadRequestException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QPermissionDeniedException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||
import com.kingsrook.qqq.backend.core.instances.QInstanceValidator;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
@ -1709,7 +1707,7 @@ public class QJavalinImplementation
|
||||
}
|
||||
catch(QUserFacingException e)
|
||||
{
|
||||
handleException(HttpStatus.Code.BAD_REQUEST, context, e);
|
||||
QJavalinUtils.handleException(HttpStatus.Code.BAD_REQUEST, context, e);
|
||||
return null;
|
||||
}
|
||||
return reportFormat;
|
||||
@ -1849,67 +1847,7 @@ public class QJavalinImplementation
|
||||
*******************************************************************************/
|
||||
public static void handleException(Context context, Exception e)
|
||||
{
|
||||
handleException(null, context, e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static void handleException(HttpStatus.Code statusCode, Context context, Exception e)
|
||||
{
|
||||
QUserFacingException userFacingException = ExceptionUtils.findClassInRootChain(e, QUserFacingException.class);
|
||||
if(userFacingException != null)
|
||||
{
|
||||
if(userFacingException instanceof QNotFoundException)
|
||||
{
|
||||
statusCode = Objects.requireNonNullElse(statusCode, HttpStatus.Code.NOT_FOUND); // 404
|
||||
respondWithError(context, statusCode, userFacingException.getMessage());
|
||||
}
|
||||
else if(userFacingException instanceof QBadRequestException)
|
||||
{
|
||||
statusCode = Objects.requireNonNullElse(statusCode, HttpStatus.Code.BAD_REQUEST); // 400
|
||||
respondWithError(context, statusCode, userFacingException.getMessage());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.info("User-facing exception", e);
|
||||
statusCode = Objects.requireNonNullElse(statusCode, HttpStatus.Code.INTERNAL_SERVER_ERROR); // 500
|
||||
respondWithError(context, statusCode, userFacingException.getMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(e instanceof QAuthenticationException)
|
||||
{
|
||||
respondWithError(context, HttpStatus.Code.UNAUTHORIZED, e.getMessage()); // 401
|
||||
return;
|
||||
}
|
||||
|
||||
if(e instanceof QPermissionDeniedException)
|
||||
{
|
||||
respondWithError(context, HttpStatus.Code.FORBIDDEN, e.getMessage()); // 403
|
||||
return;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// default exception handling //
|
||||
////////////////////////////////
|
||||
LOG.warn("Exception in javalin request", e);
|
||||
respondWithError(context, HttpStatus.Code.INTERNAL_SERVER_ERROR, e.getClass().getSimpleName() + " (" + e.getMessage() + ")"); // 500
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static void respondWithError(Context context, HttpStatus.Code statusCode, String errorMessage)
|
||||
{
|
||||
context.status(statusCode.getCode());
|
||||
context.result(JsonUtils.toJson(Map.of("error", errorMessage)));
|
||||
QJavalinUtils.handleException(null, context, e);
|
||||
}
|
||||
|
||||
|
||||
|
@ -236,13 +236,13 @@ public class QJavalinProcessHandler
|
||||
|
||||
if(inputField.getIsRequired() && !setValue)
|
||||
{
|
||||
QJavalinImplementation.respondWithError(context, HttpStatus.Code.BAD_REQUEST, "Missing query param value for required input field: [" + inputField.getName() + "]");
|
||||
QJavalinUtils.respondWithError(context, HttpStatus.Code.BAD_REQUEST, "Missing query param value for required input field: [" + inputField.getName() + "]");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
QJavalinImplementation.respondWithError(context, HttpStatus.Code.BAD_REQUEST, "Error processing query param [" + inputField.getName() + "]: " + e.getClass().getSimpleName() + " (" + e.getMessage() + ")");
|
||||
QJavalinUtils.respondWithError(context, HttpStatus.Code.BAD_REQUEST, "Error processing query param [" + inputField.getName() + "]: " + e.getClass().getSimpleName() + " (" + e.getMessage() + ")");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -22,11 +22,21 @@
|
||||
package com.kingsrook.qqq.backend.javalin;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QBadRequestException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QPermissionDeniedException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
import io.javalin.http.Context;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -34,6 +44,10 @@ import io.javalin.http.Context;
|
||||
*******************************************************************************/
|
||||
public class QJavalinUtils
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(QJavalinUtils.class);
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Returns Integer if context has a valid int query parameter by the given name,
|
||||
@ -178,4 +192,64 @@ public class QJavalinUtils
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static void handleException(HttpStatus.Code statusCode, Context context, Exception e)
|
||||
{
|
||||
QUserFacingException userFacingException = ExceptionUtils.findClassInRootChain(e, QUserFacingException.class);
|
||||
if(userFacingException != null)
|
||||
{
|
||||
if(userFacingException instanceof QNotFoundException)
|
||||
{
|
||||
statusCode = Objects.requireNonNullElse(statusCode, HttpStatus.Code.NOT_FOUND); // 404
|
||||
respondWithError(context, statusCode, userFacingException.getMessage());
|
||||
}
|
||||
else if(userFacingException instanceof QBadRequestException)
|
||||
{
|
||||
statusCode = Objects.requireNonNullElse(statusCode, HttpStatus.Code.BAD_REQUEST); // 400
|
||||
respondWithError(context, statusCode, userFacingException.getMessage());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.info("User-facing exception", e);
|
||||
statusCode = Objects.requireNonNullElse(statusCode, HttpStatus.Code.INTERNAL_SERVER_ERROR); // 500
|
||||
respondWithError(context, statusCode, userFacingException.getMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(e instanceof QAuthenticationException)
|
||||
{
|
||||
respondWithError(context, HttpStatus.Code.UNAUTHORIZED, e.getMessage()); // 401
|
||||
return;
|
||||
}
|
||||
|
||||
if(e instanceof QPermissionDeniedException)
|
||||
{
|
||||
respondWithError(context, HttpStatus.Code.FORBIDDEN, e.getMessage()); // 403
|
||||
return;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// default exception handling //
|
||||
////////////////////////////////
|
||||
LOG.warn("Exception in javalin request", e);
|
||||
respondWithError(context, HttpStatus.Code.INTERNAL_SERVER_ERROR, e.getClass().getSimpleName() + " (" + e.getMessage() + ")"); // 500
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static void respondWithError(Context context, HttpStatus.Code statusCode, String errorMessage)
|
||||
{
|
||||
context.status(statusCode.getCode());
|
||||
context.result(JsonUtils.toJson(Map.of("error", errorMessage)));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.AbstractMiddlewareInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.AbstractMiddlewareOutputInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public abstract class AbstractMiddlewareExecutor<INPUT extends AbstractMiddlewareInput, OUTPUT extends AbstractMiddlewareOutputInterface>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public abstract void execute(INPUT input, OUTPUT output) throws QException;
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.AuthenticationMetaDataInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.AuthenticationMetaDataOutputInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class AuthenticationMetaDataExecutor extends AbstractMiddlewareExecutor<AuthenticationMetaDataInput, AuthenticationMetaDataOutputInterface>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void execute(AuthenticationMetaDataInput input, AuthenticationMetaDataOutputInterface output) throws QException
|
||||
{
|
||||
output.setAuthenticationMetaData(QContext.getQInstance().getAuthentication());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleDispatcher;
|
||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleInterface;
|
||||
import com.kingsrook.qqq.backend.core.modules.authentication.implementations.Auth0AuthenticationModule;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import io.javalin.http.Context;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ExecutorSessionUtils
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(ExecutorSessionUtils.class);
|
||||
|
||||
public static final int SESSION_COOKIE_AGE = 60 * 60 * 24;
|
||||
public static final String SESSION_ID_COOKIE_NAME = "sessionId";
|
||||
public static final String API_KEY_NAME = "apiKey";
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static QSession setupSession(Context context, QInstance qInstance) throws QModuleDispatchException, QAuthenticationException
|
||||
{
|
||||
QAuthenticationModuleDispatcher qAuthenticationModuleDispatcher = new QAuthenticationModuleDispatcher();
|
||||
QAuthenticationModuleInterface authenticationModule = qAuthenticationModuleDispatcher.getQModule(qInstance.getAuthentication());
|
||||
|
||||
try
|
||||
{
|
||||
Map<String, String> authenticationContext = new HashMap<>();
|
||||
|
||||
String sessionIdCookieValue = context.cookie(SESSION_ID_COOKIE_NAME);
|
||||
String sessionUuidCookieValue = context.cookie(Auth0AuthenticationModule.SESSION_UUID_KEY);
|
||||
String authorizationHeaderValue = context.header("Authorization");
|
||||
String apiKeyHeaderValue = context.header("x-api-key");
|
||||
|
||||
if(StringUtils.hasContent(sessionIdCookieValue))
|
||||
{
|
||||
///////////////////////////////////////////////////////
|
||||
// sessionId - maybe used by table-based auth module //
|
||||
///////////////////////////////////////////////////////
|
||||
authenticationContext.put(SESSION_ID_COOKIE_NAME, sessionIdCookieValue);
|
||||
}
|
||||
else if(StringUtils.hasContent(sessionUuidCookieValue))
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// session UUID - known to be used by auth0 module (in aug. 2023 update) //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
authenticationContext.put(Auth0AuthenticationModule.SESSION_UUID_KEY, sessionUuidCookieValue);
|
||||
}
|
||||
else if(apiKeyHeaderValue != null)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// next, look for an api key header: //
|
||||
// this will be used to look up auth0 values via an auth table //
|
||||
/////////////////////////////////////////////////////////////////
|
||||
authenticationContext.put(API_KEY_NAME, apiKeyHeaderValue);
|
||||
}
|
||||
else if(authorizationHeaderValue != null)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// second, look for the authorization header: //
|
||||
// either with a "Basic " prefix (for a username:password pair) //
|
||||
// or with a "Bearer " prefix (for a token that can be handled the same as a sessionId cookie) //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
processAuthorizationValue(authenticationContext, authorizationHeaderValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
String authorizationFormValue = context.formParam("Authorization");
|
||||
if(StringUtils.hasContent(authorizationFormValue))
|
||||
{
|
||||
processAuthorizationValue(authenticationContext, authorizationFormValue);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.info("Exception looking for Authorization formParam", e);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// put the qInstance into context - but no session yet (since, the whole point of this call is to setup the session!) //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
QContext.init(qInstance, null);
|
||||
QSession session = authenticationModule.createSession(qInstance, authenticationContext);
|
||||
QContext.init(qInstance, session, null, null);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// todo - this must be moved ... not exactly sure where, but into some spec. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// String tableVariant = QJavalinUtils.getFormParamOrQueryParam(context, "tableVariant");
|
||||
// if(StringUtils.hasContent(tableVariant))
|
||||
// {
|
||||
// JSONObject variant = new JSONObject(tableVariant);
|
||||
// QContext.getQSession().setBackendVariants(MapBuilder.of(variant.getString("type"), variant.getInt("id")));
|
||||
// }
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// if we got a session id cookie in, then send it back with updated cookie age //
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
if(authenticationModule.usesSessionIdCookie())
|
||||
{
|
||||
context.cookie(SESSION_ID_COOKIE_NAME, session.getIdReference(), SESSION_COOKIE_AGE);
|
||||
}
|
||||
|
||||
setUserTimezoneOffsetMinutesInSession(context, session);
|
||||
setUserTimezoneInSession(context, session);
|
||||
|
||||
return (session);
|
||||
}
|
||||
catch(QAuthenticationException qae)
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// if exception caught, clear out the cookie so the frontend will reauthorize //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
if(authenticationModule.usesSessionIdCookie())
|
||||
{
|
||||
context.removeCookie(SESSION_ID_COOKIE_NAME);
|
||||
}
|
||||
|
||||
throw (qae);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void processAuthorizationValue(Map<String, String> authenticationContext, String authorizationHeaderValue)
|
||||
{
|
||||
String basicPrefix = "Basic ";
|
||||
String bearerPrefix = "Bearer ";
|
||||
if(authorizationHeaderValue.startsWith(basicPrefix))
|
||||
{
|
||||
authorizationHeaderValue = authorizationHeaderValue.replaceFirst(basicPrefix, "");
|
||||
authenticationContext.put(Auth0AuthenticationModule.BASIC_AUTH_KEY, authorizationHeaderValue);
|
||||
}
|
||||
else if(authorizationHeaderValue.startsWith(bearerPrefix))
|
||||
{
|
||||
authorizationHeaderValue = authorizationHeaderValue.replaceFirst(bearerPrefix, "");
|
||||
authenticationContext.put(Auth0AuthenticationModule.ACCESS_TOKEN_KEY, authorizationHeaderValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("Authorization value did not have Basic or Bearer prefix. [" + authorizationHeaderValue + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void setUserTimezoneOffsetMinutesInSession(Context context, QSession session)
|
||||
{
|
||||
String userTimezoneOffsetMinutes = context.header("X-QQQ-UserTimezoneOffsetMinutes");
|
||||
if(StringUtils.hasContent(userTimezoneOffsetMinutes))
|
||||
{
|
||||
try
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// even though we're putting it in the session as a string, go through parse int, to make sure it's a valid int. //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
session.setValue(QSession.VALUE_KEY_USER_TIMEZONE_OFFSET_MINUTES, String.valueOf(Integer.parseInt(userTimezoneOffsetMinutes)));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.debug("Received non-integer value for X-QQQ-UserTimezoneOffsetMinutes header: " + userTimezoneOffsetMinutes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void setUserTimezoneInSession(Context context, QSession session)
|
||||
{
|
||||
String userTimezone = context.header("X-QQQ-UserTimezone");
|
||||
if(StringUtils.hasContent(userTimezone))
|
||||
{
|
||||
session.setValue(QSession.VALUE_KEY_USER_TIMEZONE, userTimezone);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleDispatcher;
|
||||
import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModuleInterface;
|
||||
import com.kingsrook.qqq.backend.core.modules.authentication.implementations.Auth0AuthenticationModule;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ManageSessionInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ManageSessionOutputInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ManageSessionExecutor extends AbstractMiddlewareExecutor<ManageSessionInput, ManageSessionOutputInterface>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void execute(ManageSessionInput input, ManageSessionOutputInterface output) throws QException
|
||||
{
|
||||
QAuthenticationModuleDispatcher qAuthenticationModuleDispatcher = new QAuthenticationModuleDispatcher();
|
||||
QAuthenticationModuleInterface authenticationModule = qAuthenticationModuleDispatcher.getQModule(QContext.getQInstance().getAuthentication());
|
||||
|
||||
Map<String, String> authContext = new HashMap<>();
|
||||
authContext.put(Auth0AuthenticationModule.ACCESS_TOKEN_KEY, input.getAccessToken());
|
||||
authContext.put(Auth0AuthenticationModule.DO_STORE_USER_SESSION_KEY, "true");
|
||||
|
||||
/////////////////////////////////
|
||||
// (try to) create the session //
|
||||
/////////////////////////////////
|
||||
QSession session = authenticationModule.createSession(QContext.getQInstance(), authContext);
|
||||
|
||||
//////////////////
|
||||
// build output //
|
||||
//////////////////
|
||||
output.setUuid(session.getUuid());
|
||||
|
||||
if(session.getValuesForFrontend() != null)
|
||||
{
|
||||
LinkedHashMap<String, Serializable> valuesForFrontend = new LinkedHashMap<>(session.getValuesForFrontend());
|
||||
output.setValues(valuesForFrontend);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.actions.metadata.MetaDataAction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataOutput;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.MetaDataInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.MetaDataOutputInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class MetaDataExecutor extends AbstractMiddlewareExecutor<MetaDataInput, MetaDataOutputInterface>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void execute(MetaDataInput input, MetaDataOutputInterface output) throws QException
|
||||
{
|
||||
MetaDataAction metaDataAction = new MetaDataAction();
|
||||
MetaDataOutput metaDataOutput = metaDataAction.execute(new com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataInput());
|
||||
output.setMetaDataOutput(metaDataOutput);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobManager;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.JobGoingAsyncException;
|
||||
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.QProcessCallback;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QPermissionDeniedException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
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.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
import com.kingsrook.qqq.backend.javalin.QJavalinAccessLogger;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessInitOrStepInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessInitOrStepOrStatusOutputInterface;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.utils.ProcessExecutorUtils;
|
||||
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessInitOrStepExecutor extends AbstractMiddlewareExecutor<ProcessInitOrStepInput, ProcessInitOrStepOrStatusOutputInterface>
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(ProcessInitOrStepExecutor.class);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** Note: implementation of the output interface here, it wants to know what
|
||||
** type it's going to be first, so, be polite and always call .setType before
|
||||
** any other setters.
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void execute(ProcessInitOrStepInput input, ProcessInitOrStepOrStatusOutputInterface output) throws QException
|
||||
{
|
||||
Exception returningException = null;
|
||||
|
||||
String processName = input.getProcessName();
|
||||
String startAfterStep = input.getStartAfterStep();
|
||||
String processUUID = input.getProcessUUID();
|
||||
|
||||
if(processUUID == null)
|
||||
{
|
||||
processUUID = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
LOG.info(startAfterStep == null ? "Initiating process [" + processName + "] [" + processUUID + "]"
|
||||
: "Resuming process [" + processName + "] [" + processUUID + "] after step [" + startAfterStep + "]");
|
||||
|
||||
try
|
||||
{
|
||||
RunProcessInput runProcessInput = new RunProcessInput();
|
||||
QContext.pushAction(runProcessInput);
|
||||
|
||||
runProcessInput.setProcessName(processName);
|
||||
runProcessInput.setFrontendStepBehavior(input.getFrontendStepBehavior());
|
||||
runProcessInput.setProcessUUID(processUUID);
|
||||
runProcessInput.setStartAfterStep(startAfterStep);
|
||||
runProcessInput.setValues(Objects.requireNonNullElseGet(input.getValues(), HashMap::new));
|
||||
|
||||
if(input.getRecordsFilter() != null)
|
||||
{
|
||||
runProcessInput.setCallback(new QProcessCallback()
|
||||
{
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public QQueryFilter getQueryFilter()
|
||||
{
|
||||
return (input.getRecordsFilter());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Map<String, Serializable> getFieldValues(List<QFieldMetaData> fields)
|
||||
{
|
||||
return (Collections.emptyMap());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
String reportName = ValueUtils.getValueAsString(runProcessInput.getValue("reportName"));
|
||||
QJavalinAccessLogger.logStart(startAfterStep == null ? "processInit" : "processStep", logPair("processName", processName), logPair("processUUID", processUUID),
|
||||
StringUtils.hasContent(startAfterStep) ? logPair("startAfterStep", startAfterStep) : null,
|
||||
StringUtils.hasContent(reportName) ? logPair("reportName", reportName) : null);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// important to do this check AFTER the runProcessInput is populated with values from context - //
|
||||
// e.g., in case things like a reportName are set in here //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
PermissionsHelper.checkProcessPermissionThrowing(runProcessInput, processName);
|
||||
|
||||
////////////////////////////////////////
|
||||
// run the process as an async action //
|
||||
////////////////////////////////////////
|
||||
RunProcessOutput runProcessOutput = new AsyncJobManager().startJob(processName, input.getStepTimeoutMillis(), TimeUnit.MILLISECONDS, (callback) ->
|
||||
{
|
||||
runProcessInput.setAsyncJobCallback(callback);
|
||||
return (new RunProcessAction().execute(runProcessInput));
|
||||
});
|
||||
|
||||
LOG.debug("Process result error? " + runProcessOutput.getException());
|
||||
for(QFieldMetaData outputField : QContext.getQInstance().getProcess(runProcessInput.getProcessName()).getOutputFields())
|
||||
{
|
||||
LOG.debug("Process result output value: " + outputField.getName() + ": " + runProcessOutput.getValues().get(outputField.getName()));
|
||||
}
|
||||
|
||||
ProcessExecutorUtils.serializeRunProcessResultForCaller(output, processName, runProcessOutput);
|
||||
QJavalinAccessLogger.logProcessSummary(processName, processUUID, runProcessOutput);
|
||||
}
|
||||
catch(JobGoingAsyncException jgae)
|
||||
{
|
||||
output.setType(ProcessInitOrStepOrStatusOutputInterface.Type.JOB_STARTED);
|
||||
output.setJobUUID(jgae.getJobUUID());
|
||||
}
|
||||
catch(QPermissionDeniedException | QAuthenticationException e)
|
||||
{
|
||||
throw (e);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// our other actions in here would do: handleException(context, e); //
|
||||
// which would return a 500 to the client. //
|
||||
// but - other process-step actions, they always return a 200, just with an //
|
||||
// optional error message - so - keep all of the processes consistent. //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
returningException = e;
|
||||
ProcessExecutorUtils.serializeRunProcessExceptionForCaller(output, e);
|
||||
}
|
||||
|
||||
output.setProcessUUID(processUUID);
|
||||
|
||||
if(returningException != null)
|
||||
{
|
||||
QJavalinAccessLogger.logEndFail(returningException);
|
||||
}
|
||||
else
|
||||
{
|
||||
QJavalinAccessLogger.logEndSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.actions.metadata.ProcessMetaDataAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.ProcessMetaDataOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessMetaDataInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessMetaDataOutputInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessMetaDataExecutor extends AbstractMiddlewareExecutor<ProcessMetaDataInput, ProcessMetaDataOutputInterface>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void execute(ProcessMetaDataInput input, ProcessMetaDataOutputInterface output) throws QException
|
||||
{
|
||||
com.kingsrook.qqq.backend.core.model.actions.metadata.ProcessMetaDataInput processMetaDataInput = new com.kingsrook.qqq.backend.core.model.actions.metadata.ProcessMetaDataInput();
|
||||
|
||||
String processName = input.getProcessName();
|
||||
QProcessMetaData process = QContext.getQInstance().getProcess(processName);
|
||||
if(process == null)
|
||||
{
|
||||
throw (new QNotFoundException("Process [" + processName + "] was not found."));
|
||||
}
|
||||
PermissionsHelper.checkProcessPermissionThrowing(processMetaDataInput, processName);
|
||||
|
||||
processMetaDataInput.setProcessName(processName);
|
||||
ProcessMetaDataAction processMetaDataAction = new ProcessMetaDataAction();
|
||||
ProcessMetaDataOutput processMetaDataOutput = processMetaDataAction.execute(processMetaDataInput);
|
||||
|
||||
output.setProcessMetaData(processMetaDataOutput.getProcess());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors;
|
||||
|
||||
|
||||
import java.util.Optional;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobManager;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobState;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobStatus;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction;
|
||||
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.ProcessState;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput;
|
||||
import com.kingsrook.qqq.backend.javalin.QJavalinAccessLogger;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessInitOrStepOrStatusOutputInterface;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessStatusInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.utils.ProcessExecutorUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessStatusExecutor extends AbstractMiddlewareExecutor<ProcessStatusInput, ProcessInitOrStepOrStatusOutputInterface>
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(ProcessStatusExecutor.class);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** Note: implementation of the output interface here, it wants to know what
|
||||
** type it's going to be first, so, be polite and always call .setType before
|
||||
** any other setters.
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void execute(ProcessStatusInput input, ProcessInitOrStepOrStatusOutputInterface output) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
String processName = input.getProcessName();
|
||||
String processUUID = input.getProcessUUID();
|
||||
String jobUUID = input.getJobUUID();
|
||||
|
||||
LOG.debug("Request for status of process " + processUUID + ", job " + jobUUID);
|
||||
Optional<AsyncJobStatus> optionalJobStatus = new AsyncJobManager().getJobStatus(jobUUID);
|
||||
if(optionalJobStatus.isEmpty())
|
||||
{
|
||||
ProcessExecutorUtils.serializeRunProcessExceptionForCaller(output, new RuntimeException("Could not find status of process step job"));
|
||||
}
|
||||
else
|
||||
{
|
||||
AsyncJobStatus jobStatus = optionalJobStatus.get();
|
||||
|
||||
// resultForCaller.put("jobStatus", jobStatus);
|
||||
LOG.debug("Job status is " + jobStatus.getState() + " for " + jobUUID);
|
||||
|
||||
if(jobStatus.getState().equals(AsyncJobState.COMPLETE))
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// if the job is complete, get the process result from state provider, and return it //
|
||||
// this output should look like it did if the job finished synchronously!! //
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
Optional<ProcessState> processState = RunProcessAction.getState(processUUID);
|
||||
if(processState.isPresent())
|
||||
{
|
||||
RunProcessOutput runProcessOutput = new RunProcessOutput(processState.get());
|
||||
ProcessExecutorUtils.serializeRunProcessResultForCaller(output, processName, runProcessOutput);
|
||||
QJavalinAccessLogger.logProcessSummary(processName, processUUID, runProcessOutput);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessExecutorUtils.serializeRunProcessExceptionForCaller(output, new RuntimeException("Could not find results for process " + processUUID));
|
||||
}
|
||||
}
|
||||
else if(jobStatus.getState().equals(AsyncJobState.ERROR))
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if the job had an error (e.g., a process step threw), "nicely" serialize its exception for the caller //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
if(jobStatus.getCaughtException() != null)
|
||||
{
|
||||
ProcessExecutorUtils.serializeRunProcessExceptionForCaller(output, jobStatus.getCaughtException());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
output.setType(ProcessInitOrStepOrStatusOutputInterface.Type.RUNNING);
|
||||
output.setMessage(jobStatus.getMessage());
|
||||
output.setCurrent(jobStatus.getCurrent());
|
||||
output.setTotal(jobStatus.getTotal());
|
||||
}
|
||||
}
|
||||
|
||||
output.setProcessUUID(processUUID);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
ProcessExecutorUtils.serializeRunProcessExceptionForCaller(output, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class AbstractMiddlewareInput
|
||||
{
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface AbstractMiddlewareOutputInterface
|
||||
{
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class AuthenticationMetaDataInput extends AbstractMiddlewareInput
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.authentication.QAuthenticationMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface AuthenticationMetaDataOutputInterface extends AbstractMiddlewareOutputInterface
|
||||
{
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
void setAuthenticationMetaData(QAuthenticationMetaData qAuthenticationMetaData);
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** generic middleware input that has no fields.
|
||||
*******************************************************************************/
|
||||
public class EmptyMiddlewareInput extends AbstractMiddlewareInput
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface EmptyMiddlewareOutputInterface extends AbstractMiddlewareOutputInterface
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ManageSessionInput extends AbstractMiddlewareInput
|
||||
{
|
||||
private String accessToken;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for accessToken
|
||||
*******************************************************************************/
|
||||
public String getAccessToken()
|
||||
{
|
||||
return (this.accessToken);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for accessToken
|
||||
*******************************************************************************/
|
||||
public void setAccessToken(String accessToken)
|
||||
{
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for accessToken
|
||||
*******************************************************************************/
|
||||
public ManageSessionInput withAccessToken(String accessToken)
|
||||
{
|
||||
this.accessToken = accessToken;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface ManageSessionOutputInterface extends AbstractMiddlewareOutputInterface
|
||||
{
|
||||
/***************************************************************************
|
||||
** Setter for Uuid
|
||||
***************************************************************************/
|
||||
void setUuid(String uuid);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
*******************************************************************************/
|
||||
void setValues(Map<String, Serializable> values);
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class MetaDataInput extends AbstractMiddlewareInput
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataOutput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface MetaDataOutputInterface extends AbstractMiddlewareOutputInterface
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for metaDataOutput
|
||||
*******************************************************************************/
|
||||
void setMetaDataOutput(MetaDataOutput metaDataOutput);
|
||||
|
||||
}
|
@ -0,0 +1,295 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessInitOrStepInput extends AbstractMiddlewareInput
|
||||
{
|
||||
private String processName;
|
||||
private Integer stepTimeoutMillis = 3000;
|
||||
private QQueryFilter recordsFilter;
|
||||
|
||||
private Map<String, Serializable> values = new LinkedHashMap<>();
|
||||
|
||||
/////////////////////////////////////
|
||||
// used only for 'step' (not init) //
|
||||
/////////////////////////////////////
|
||||
private String processUUID;
|
||||
private String startAfterStep;
|
||||
|
||||
private RunProcessInput.FrontendStepBehavior frontendStepBehavior = RunProcessInput.FrontendStepBehavior.BREAK;
|
||||
|
||||
// todo - file??
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public enum RecordsParam
|
||||
{
|
||||
FILTER_JSON("filterJSON"),
|
||||
RECORD_IDS("recordIds");
|
||||
|
||||
|
||||
private final String value;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
RecordsParam(String value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processName
|
||||
*******************************************************************************/
|
||||
public String getProcessName()
|
||||
{
|
||||
return (this.processName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processName
|
||||
*******************************************************************************/
|
||||
public void setProcessName(String processName)
|
||||
{
|
||||
this.processName = processName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for processName
|
||||
*******************************************************************************/
|
||||
public ProcessInitOrStepInput withProcessName(String processName)
|
||||
{
|
||||
this.processName = processName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for stepTimeoutMillis
|
||||
*******************************************************************************/
|
||||
public Integer getStepTimeoutMillis()
|
||||
{
|
||||
return (this.stepTimeoutMillis);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for stepTimeoutMillis
|
||||
*******************************************************************************/
|
||||
public void setStepTimeoutMillis(Integer stepTimeoutMillis)
|
||||
{
|
||||
this.stepTimeoutMillis = stepTimeoutMillis;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for stepTimeoutMillis
|
||||
*******************************************************************************/
|
||||
public ProcessInitOrStepInput withStepTimeoutMillis(Integer stepTimeoutMillis)
|
||||
{
|
||||
this.stepTimeoutMillis = stepTimeoutMillis;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for recordsFilter
|
||||
*******************************************************************************/
|
||||
public QQueryFilter getRecordsFilter()
|
||||
{
|
||||
return (this.recordsFilter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for recordsFilter
|
||||
*******************************************************************************/
|
||||
public void setRecordsFilter(QQueryFilter recordsFilter)
|
||||
{
|
||||
this.recordsFilter = recordsFilter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for recordsFilter
|
||||
*******************************************************************************/
|
||||
public ProcessInitOrStepInput withRecordsFilter(QQueryFilter recordsFilter)
|
||||
{
|
||||
this.recordsFilter = recordsFilter;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getValues()
|
||||
{
|
||||
return (this.values);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
*******************************************************************************/
|
||||
public void setValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for values
|
||||
*******************************************************************************/
|
||||
public ProcessInitOrStepInput withValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.values = values;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for frontendStepBehavior
|
||||
*******************************************************************************/
|
||||
public RunProcessInput.FrontendStepBehavior getFrontendStepBehavior()
|
||||
{
|
||||
return (this.frontendStepBehavior);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for frontendStepBehavior
|
||||
*******************************************************************************/
|
||||
public void setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior frontendStepBehavior)
|
||||
{
|
||||
this.frontendStepBehavior = frontendStepBehavior;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for frontendStepBehavior
|
||||
*******************************************************************************/
|
||||
public ProcessInitOrStepInput withFrontendStepBehavior(RunProcessInput.FrontendStepBehavior frontendStepBehavior)
|
||||
{
|
||||
this.frontendStepBehavior = frontendStepBehavior;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processUUID
|
||||
*******************************************************************************/
|
||||
public String getProcessUUID()
|
||||
{
|
||||
return (this.processUUID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processUUID
|
||||
*******************************************************************************/
|
||||
public void setProcessUUID(String processUUID)
|
||||
{
|
||||
this.processUUID = processUUID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for processUUID
|
||||
*******************************************************************************/
|
||||
public ProcessInitOrStepInput withProcessUUID(String processUUID)
|
||||
{
|
||||
this.processUUID = processUUID;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for startAfterStep
|
||||
*******************************************************************************/
|
||||
public String getStartAfterStep()
|
||||
{
|
||||
return (this.startAfterStep);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for startAfterStep
|
||||
*******************************************************************************/
|
||||
public void setStartAfterStep(String startAfterStep)
|
||||
{
|
||||
this.startAfterStep = startAfterStep;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for startAfterStep
|
||||
*******************************************************************************/
|
||||
public ProcessInitOrStepInput withStartAfterStep(String startAfterStep)
|
||||
{
|
||||
this.startAfterStep = startAfterStep;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessMetaDataAdjustment;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface ProcessInitOrStepOrStatusOutputInterface extends AbstractMiddlewareOutputInterface
|
||||
{
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
enum Type
|
||||
{
|
||||
COMPLETE, JOB_STARTED, RUNNING, ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for type
|
||||
*******************************************************************************/
|
||||
void setType(Type type);
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processUUID
|
||||
*******************************************************************************/
|
||||
void setProcessUUID(String processUUID);
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for nextStep
|
||||
*******************************************************************************/
|
||||
void setNextStep(String nextStep);
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
*******************************************************************************/
|
||||
void setValues(Map<String, Serializable> values);
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for jobUUID
|
||||
*******************************************************************************/
|
||||
void setJobUUID(String jobUUID);
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for message
|
||||
*******************************************************************************/
|
||||
void setMessage(String message);
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for current
|
||||
*******************************************************************************/
|
||||
void setCurrent(Integer current);
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for total
|
||||
*******************************************************************************/
|
||||
void setTotal(Integer total);
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for error
|
||||
*******************************************************************************/
|
||||
void setError(String error);
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for userFacingError
|
||||
*******************************************************************************/
|
||||
void setUserFacingError(String userFacingError);
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processMetaDataAdjustment
|
||||
*******************************************************************************/
|
||||
void setProcessMetaDataAdjustment(ProcessMetaDataAdjustment processMetaDataAdjustment);
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessMetaDataInput extends AbstractMiddlewareInput
|
||||
{
|
||||
private String processName;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getProcessName()
|
||||
{
|
||||
return processName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setProcessName(String processName)
|
||||
{
|
||||
this.processName = processName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for processName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessMetaDataInput withProcessName(String processName)
|
||||
{
|
||||
this.processName = processName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface ProcessMetaDataOutputInterface extends AbstractMiddlewareOutputInterface
|
||||
{
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
void setProcessMetaData(QFrontendProcessMetaData processMetaData);
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessStatusInput extends AbstractMiddlewareInput
|
||||
{
|
||||
private String processName;
|
||||
private String processUUID;
|
||||
private String jobUUID;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processName
|
||||
*******************************************************************************/
|
||||
public String getProcessName()
|
||||
{
|
||||
return (this.processName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processName
|
||||
*******************************************************************************/
|
||||
public void setProcessName(String processName)
|
||||
{
|
||||
this.processName = processName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for processName
|
||||
*******************************************************************************/
|
||||
public ProcessStatusInput withProcessName(String processName)
|
||||
{
|
||||
this.processName = processName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processUUID
|
||||
*******************************************************************************/
|
||||
public String getProcessUUID()
|
||||
{
|
||||
return (this.processUUID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for processUUID
|
||||
*******************************************************************************/
|
||||
public void setProcessUUID(String processUUID)
|
||||
{
|
||||
this.processUUID = processUUID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for processUUID
|
||||
*******************************************************************************/
|
||||
public ProcessStatusInput withProcessUUID(String processUUID)
|
||||
{
|
||||
this.processUUID = processUUID;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for jobUUID
|
||||
*******************************************************************************/
|
||||
public String getJobUUID()
|
||||
{
|
||||
return (this.jobUUID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for jobUUID
|
||||
*******************************************************************************/
|
||||
public void setJobUUID(String jobUUID)
|
||||
{
|
||||
this.jobUUID = jobUUID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for jobUUID
|
||||
*******************************************************************************/
|
||||
public ProcessStatusInput withJobUUID(String jobUUID)
|
||||
{
|
||||
this.jobUUID = jobUUID;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface ProcessStatusOutputInterface extends AbstractMiddlewareOutputInterface
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.io;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QueryMiddlewareInput extends AbstractMiddlewareInput
|
||||
{
|
||||
private String table;
|
||||
private QQueryFilter filter;
|
||||
private List<QueryJoin> queryJoins;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for table
|
||||
*******************************************************************************/
|
||||
public String getTable()
|
||||
{
|
||||
return (this.table);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for table
|
||||
*******************************************************************************/
|
||||
public void setTable(String table)
|
||||
{
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for table
|
||||
*******************************************************************************/
|
||||
public QueryMiddlewareInput withTable(String table)
|
||||
{
|
||||
this.table = table;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for filter
|
||||
*******************************************************************************/
|
||||
public QQueryFilter getFilter()
|
||||
{
|
||||
return (this.filter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for filter
|
||||
*******************************************************************************/
|
||||
public void setFilter(QQueryFilter filter)
|
||||
{
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for filter
|
||||
*******************************************************************************/
|
||||
public QueryMiddlewareInput withFilter(QQueryFilter filter)
|
||||
{
|
||||
this.filter = filter;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for queryJoins
|
||||
*******************************************************************************/
|
||||
public List<QueryJoin> getQueryJoins()
|
||||
{
|
||||
return (this.queryJoins);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for queryJoins
|
||||
*******************************************************************************/
|
||||
public void setQueryJoins(List<QueryJoin> queryJoins)
|
||||
{
|
||||
this.queryJoins = queryJoins;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for queryJoins
|
||||
*******************************************************************************/
|
||||
public QueryMiddlewareInput withQueryJoins(List<QueryJoin> queryJoins)
|
||||
{
|
||||
this.queryJoins = queryJoins;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
** These classes are input/output wrappers for middleware executors.
|
||||
**
|
||||
** Some "empty" implementations are provided, for executors that (more likely)
|
||||
** take no inputs, or (less likely?) return no outputs.
|
||||
**
|
||||
*******************************************************************************/
|
||||
package com.kingsrook.qqq.middleware.javalin.executors.io;
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
** This package contains (hopefully generally) api-version-agnostic classes
|
||||
** that implement the actual QQQ Middleware. That is to say, subclasses of
|
||||
** `AbstractMiddlewareExecutor`, which use classes from the `.io` subpackage
|
||||
** for I/O, to run code in a QQQ server.
|
||||
**
|
||||
** As new versions of the middleware evolve, the idea is that the spec classes
|
||||
** for new versions will be responsible for appropriately marshalling data
|
||||
** in and out of the executors, via the I/O classes, with "feature flags", etc
|
||||
** added to those input classes as needed (say if v N+1 adds a new feature,
|
||||
** then a request for v N may omit the feature-flag that turns that feature on).
|
||||
**
|
||||
** As functionality continues to evolve, the time may come when it's appropriate
|
||||
** to fork an Executor. Hypothetically, if version 5 of the QueryExecutor
|
||||
** bears very little resemblance to versions 1 through 4 (due to additional
|
||||
** pizzazz?) spawn a new QueryWithPizzazzExecutor. Of course, naming here
|
||||
** will be the hardest part (e.g., avoid NewNewQueryExecutorFinal2B...)
|
||||
*******************************************************************************/
|
||||
package com.kingsrook.qqq.middleware.javalin.executors;
|
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.middleware.javalin.executors.utils;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput;
|
||||
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessInitOrStepOrStatusOutputInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessExecutorUtils
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(ProcessExecutorUtils.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Whether a step finished synchronously or asynchronously, return its data
|
||||
** to the caller the same way.
|
||||
*******************************************************************************/
|
||||
public static void serializeRunProcessResultForCaller(ProcessInitOrStepOrStatusOutputInterface processInitOrStepOutput, String processName, RunProcessOutput runProcessOutput)
|
||||
{
|
||||
processInitOrStepOutput.setType(ProcessInitOrStepOrStatusOutputInterface.Type.COMPLETE);
|
||||
|
||||
if(runProcessOutput.getException().isPresent())
|
||||
{
|
||||
////////////////////////////////////////////////////////////////
|
||||
// per code coverage, this path may never actually get hit... //
|
||||
////////////////////////////////////////////////////////////////
|
||||
serializeRunProcessExceptionForCaller(processInitOrStepOutput, runProcessOutput.getException().get());
|
||||
}
|
||||
|
||||
processInitOrStepOutput.setValues(runProcessOutput.getValues());
|
||||
// processInitOrStepOutput.setValues(getValuesForCaller(processName, runProcessOutput));
|
||||
|
||||
runProcessOutput.getProcessState().getNextStepName().ifPresent(nextStep -> processInitOrStepOutput.setNextStep(nextStep));
|
||||
|
||||
if(runProcessOutput.getProcessMetaDataAdjustment() != null)
|
||||
{
|
||||
processInitOrStepOutput.setProcessMetaDataAdjustment(runProcessOutput.getProcessMetaDataAdjustment());
|
||||
}
|
||||
}
|
||||
|
||||
// /***************************************************************************
|
||||
// ** maybe good idea here, but... to only return fields that the frontend steps
|
||||
// ** say they care about. yeah.
|
||||
// ***************************************************************************/
|
||||
// private static Map<String, Serializable> getValuesForCaller(String processName, RunProcessOutput runProcessOutput)
|
||||
// {
|
||||
// QProcessMetaData process = QContext.getQInstance().getProcess(processName);
|
||||
// Map<String, QFieldMetaData> frontendFields = new LinkedHashMap<>();
|
||||
// for(QStepMetaData step : process.getAllSteps().values())
|
||||
// {
|
||||
// if(step instanceof QFrontendStepMetaData frontendStepMetaData)
|
||||
// {
|
||||
// frontendFields.addAll(frontendStepMetaData.getAllFields());
|
||||
// }
|
||||
// else if(step instanceof QStateMachineStep stateMachineStep)
|
||||
// {
|
||||
// for(QStepMetaData subStep : stateMachineStep.getSubSteps())
|
||||
// {
|
||||
// // recur, etc
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // then, only return ones in the map, eh
|
||||
// }
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static void serializeRunProcessExceptionForCaller(ProcessInitOrStepOrStatusOutputInterface processInitOrStepOutput, Exception exception)
|
||||
{
|
||||
processInitOrStepOutput.setType(ProcessInitOrStepOrStatusOutputInterface.Type.ERROR);
|
||||
|
||||
QUserFacingException userFacingException = ExceptionUtils.findClassInRootChain(exception, QUserFacingException.class);
|
||||
|
||||
if(userFacingException != null)
|
||||
{
|
||||
LOG.info("User-facing exception in process", userFacingException);
|
||||
processInitOrStepOutput.setError(userFacingException.getMessage());
|
||||
processInitOrStepOutput.setUserFacingError(userFacingException.getMessage());
|
||||
}
|
||||
else
|
||||
{
|
||||
Throwable rootException = ExceptionUtils.getRootException(exception);
|
||||
LOG.warn("Uncaught Exception in process", exception);
|
||||
processInitOrStepOutput.setError("Error message: " + rootException.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QRuntimeException;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
@ -64,13 +65,57 @@ public class SchemaBuilder
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static class SchemaFromBuilder extends Schema
|
||||
{
|
||||
private Class<?> originalClass;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for originalClass
|
||||
**
|
||||
*******************************************************************************/
|
||||
@JsonIgnore
|
||||
public Class<?> getOriginalClass()
|
||||
{
|
||||
return originalClass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for originalClass
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setOriginalClass(Class<?> originalClass)
|
||||
{
|
||||
this.originalClass = originalClass;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for originalClass
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SchemaFromBuilder withOriginalClass(Class<?> originalClass)
|
||||
{
|
||||
this.originalClass = originalClass;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private Schema classToSchema(Class<?> c, AnnotatedElement element)
|
||||
{
|
||||
Schema schema = new Schema();
|
||||
SchemaFromBuilder schema = new SchemaFromBuilder();
|
||||
schema.setOriginalClass(c);
|
||||
|
||||
if(c.isEnum())
|
||||
{
|
||||
@ -121,10 +166,10 @@ public class SchemaBuilder
|
||||
if(openAPIMapKnownEntriesAnnotation != null)
|
||||
{
|
||||
schema.withRef("#/components/schemas/" + openAPIMapKnownEntriesAnnotation.value().getSimpleName());
|
||||
// if(openAPIMapKnownEntriesAnnotation.additionalProperties())
|
||||
// {
|
||||
// schema.withAdditionalProperties(true);
|
||||
// }
|
||||
// if(openAPIMapKnownEntriesAnnotation.additionalProperties())
|
||||
// {
|
||||
// schema.withAdditionalProperties(true);
|
||||
// }
|
||||
}
|
||||
|
||||
OpenAPIMapValueType openAPIMapValueTypeAnnotation = element.getAnnotation(OpenAPIMapValueType.class);
|
||||
@ -142,13 +187,23 @@ public class SchemaBuilder
|
||||
}
|
||||
else
|
||||
{
|
||||
OpenAPIOneOf openAPIOneOfAnnotation = element.getAnnotation(OpenAPIOneOf.class);
|
||||
OpenAPIOneOf openAPIOneOfAnnotation = element.getAnnotation(OpenAPIOneOf.class);
|
||||
OpenAPIMapKnownEntries openAPIMapKnownEntriesAnnotation = element.getAnnotation(OpenAPIMapKnownEntries.class);
|
||||
|
||||
if(openAPIOneOfAnnotation != null)
|
||||
{
|
||||
String description = "[" + element + "]";
|
||||
List<Schema> oneOfList = processOneOfAnnotation(openAPIOneOfAnnotation, c, description);
|
||||
schema.withOneOf(oneOfList);
|
||||
}
|
||||
// todo no, lot like this else if(openAPIMapKnownEntriesAnnotation != null)
|
||||
// todo no, lot like this {
|
||||
// todo no, lot like this schema.withRef("#/components/schemas/" + openAPIMapKnownEntriesAnnotation.value().getSimpleName());
|
||||
// todo no, lot like this // if(openAPIMapKnownEntriesAnnotation.additionalProperties())
|
||||
// todo no, lot like this // {
|
||||
// todo no, lot like this // schema.withAdditionalProperties(true);
|
||||
// todo no, lot like this // }
|
||||
// todo no, lot like this }
|
||||
else
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -296,5 +351,4 @@ public class SchemaBuilder
|
||||
return oneOfList;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ import java.lang.annotation.Target;
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface OpenAPIHasAdditionalProperties
|
||||
{
|
||||
|
@ -0,0 +1,545 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QRuntimeException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
import com.kingsrook.qqq.backend.javalin.QJavalinUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.AbstractMiddlewareExecutor;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.ExecutorSessionUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.AbstractMiddlewareInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.AbstractMiddlewareOutputInterface;
|
||||
import com.kingsrook.qqq.openapi.model.Content;
|
||||
import com.kingsrook.qqq.openapi.model.Method;
|
||||
import com.kingsrook.qqq.openapi.model.Parameter;
|
||||
import com.kingsrook.qqq.openapi.model.RequestBody;
|
||||
import com.kingsrook.qqq.openapi.model.Response;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import io.javalin.apibuilder.ApiBuilder;
|
||||
import io.javalin.http.ContentType;
|
||||
import io.javalin.http.Context;
|
||||
import io.javalin.http.Handler;
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Base class for individual endpoint specs.
|
||||
** e.g., one path, that has one "spec" (a "Method" in openapi structure),
|
||||
** with one implementation (executor + input & output)
|
||||
*******************************************************************************/
|
||||
public abstract class AbstractEndpointSpec<
|
||||
INPUT extends AbstractMiddlewareInput,
|
||||
OUTPUT extends AbstractMiddlewareOutputInterface,
|
||||
EXECUTOR extends AbstractMiddlewareExecutor<INPUT, ? super OUTPUT>>
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(AbstractEndpointSpec.class);
|
||||
|
||||
protected QInstance qInstance;
|
||||
|
||||
private List<Parameter> memoizedRequestParameters = null;
|
||||
private RequestBody memoizedRequestBody = null;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** build the endpoint's input object from a javalin context
|
||||
***************************************************************************/
|
||||
public abstract INPUT buildInput(Context context) throws Exception;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** build the endpoint's http response (written to the javalin context) from
|
||||
** an execution output object
|
||||
***************************************************************************/
|
||||
public abstract void handleOutput(Context context, OUTPUT output) throws Exception;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** Construct a new instance of the executor class, based on type-argument
|
||||
***************************************************************************/
|
||||
@SuppressWarnings("unchecked")
|
||||
public EXECUTOR newExecutor()
|
||||
{
|
||||
Object object = newObjectFromTypeArgument(2);
|
||||
return (EXECUTOR) object;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** Construct a new instance of the output class, based on type-argument
|
||||
***************************************************************************/
|
||||
@SuppressWarnings("unchecked")
|
||||
public OUTPUT newOutput()
|
||||
{
|
||||
Object object = newObjectFromTypeArgument(1);
|
||||
return (OUTPUT) object;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** credit: https://www.baeldung.com/java-generic-type-find-class-runtime
|
||||
***************************************************************************/
|
||||
private Object newObjectFromTypeArgument(int argumentIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
Type superClass = getClass().getGenericSuperclass();
|
||||
Type actualTypeArgument = ((ParameterizedType) superClass).getActualTypeArguments()[argumentIndex];
|
||||
String className = actualTypeArgument.getTypeName().replaceAll("<.*", "");
|
||||
Class<?> aClass = Class.forName(className);
|
||||
return (aClass.getConstructor().newInstance());
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QRuntimeException("Failed to reflectively create new object from type argument", e));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** define a javalin route for the spec
|
||||
***************************************************************************/
|
||||
public void defineRoute(String versionBasePath)
|
||||
{
|
||||
CompleteOperation completeOperation = defineCompleteOperation();
|
||||
|
||||
String fullPath = "/qqq/" + versionBasePath + completeOperation.getPath();
|
||||
fullPath = fullPath.replaceAll("/+", "/");
|
||||
|
||||
final Handler handler = context -> serveRequest(context);
|
||||
|
||||
switch(completeOperation.getHttpMethod())
|
||||
{
|
||||
case GET -> ApiBuilder.get(fullPath, handler);
|
||||
case POST -> ApiBuilder.post(fullPath, handler);
|
||||
case PUT -> ApiBuilder.put(fullPath, handler);
|
||||
case PATCH -> ApiBuilder.patch(fullPath, handler);
|
||||
case DELETE -> ApiBuilder.delete(fullPath, handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public OUTPUT serveRequest(Context context) throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
if(isSecured())
|
||||
{
|
||||
ExecutorSessionUtils.setupSession(context, qInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
QContext.setQInstance(qInstance);
|
||||
}
|
||||
|
||||
INPUT input = buildInput(context);
|
||||
EXECUTOR executor = newExecutor();
|
||||
OUTPUT output = newOutput();
|
||||
executor.execute(input, output);
|
||||
handleOutput(context, output);
|
||||
return (output);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
handleException(context, e);
|
||||
return (null);
|
||||
}
|
||||
finally
|
||||
{
|
||||
QContext.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
protected void handleException(Context context, Exception e)
|
||||
{
|
||||
QJavalinUtils.handleException(null, context, e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public Method defineMethod()
|
||||
{
|
||||
BasicOperation basicOperation = defineBasicOperation();
|
||||
|
||||
Method method = new Method()
|
||||
.withTag(basicOperation.getTag().getText())
|
||||
.withSummary(basicOperation.getShortSummary())
|
||||
.withDescription(basicOperation.getLongDescription())
|
||||
.withParameters(defineRequestParameters())
|
||||
.withRequestBody(defineRequestBody())
|
||||
.withResponses(defineResponses());
|
||||
|
||||
customizeMethod(method);
|
||||
|
||||
return (method);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
protected void customizeMethod(Method method)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public BasicOperation defineBasicOperation()
|
||||
{
|
||||
throw new NotImplementedException(getClass().getSimpleName() + " did not implement defineBasicOperation or defineMethod");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public CompleteOperation defineCompleteOperation()
|
||||
{
|
||||
CompleteOperation completeOperation = new CompleteOperation(defineBasicOperation());
|
||||
completeOperation.setMethod(defineMethod());
|
||||
return completeOperation;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public boolean isSecured()
|
||||
{
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public BasicResponse defineBasicSuccessResponse()
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public List<BasicResponse> defineAdditionalBasicResponses()
|
||||
{
|
||||
return (Collections.emptyList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public Map<Integer, Response> defineResponses()
|
||||
{
|
||||
BasicResponse standardSuccessResponse = defineBasicSuccessResponse();
|
||||
List<BasicResponse> basicResponseList = defineAdditionalBasicResponses();
|
||||
|
||||
List<BasicResponse> allBasicResponses = new ArrayList<>();
|
||||
if(standardSuccessResponse != null)
|
||||
{
|
||||
allBasicResponses.add(standardSuccessResponse);
|
||||
}
|
||||
|
||||
if(basicResponseList != null)
|
||||
{
|
||||
allBasicResponses.addAll(basicResponseList);
|
||||
}
|
||||
|
||||
Map<Integer, Response> rs = new HashMap<>();
|
||||
for(BasicResponse basicResponse : allBasicResponses)
|
||||
{
|
||||
Response responseObject = rs.computeIfAbsent(basicResponse.status().getCode(), (k) -> new Response());
|
||||
responseObject.withDescription(basicResponse.description());
|
||||
Map<String, Content> content = responseObject.getContent();
|
||||
if(content == null)
|
||||
{
|
||||
content = new HashMap<>();
|
||||
responseObject.setContent(content);
|
||||
}
|
||||
|
||||
content.put(basicResponse.contentType(), new Content()
|
||||
.withSchema(new Schema().withRefToSchema(basicResponse.schemaRefName()))
|
||||
.withExamples(basicResponse.examples())
|
||||
);
|
||||
}
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public List<Parameter> defineRequestParameters()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public RequestBody defineRequestBody()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public Map<String, Schema> defineComponentSchemas()
|
||||
{
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
protected String getRequestParam(Context context, String name)
|
||||
{
|
||||
for(Parameter parameter : CollectionUtils.nonNullList(getMemoizedRequestParameters()))
|
||||
{
|
||||
if(parameter.getName().equals(name))
|
||||
{
|
||||
String value = switch(parameter.getIn())
|
||||
{
|
||||
case "path" -> context.pathParam(parameter.getName());
|
||||
case "query" -> context.queryParam(parameter.getName());
|
||||
default -> throw new IllegalStateException("Unexpected 'in' value for parameter [" + parameter.getName() + "]: " + parameter.getIn());
|
||||
};
|
||||
|
||||
// todo - validate value vs. required?
|
||||
// todo - validate value vs. schema?
|
||||
|
||||
return (value);
|
||||
}
|
||||
}
|
||||
|
||||
RequestBody requestBody = getMemoizedRequestBody();
|
||||
if(requestBody != null)
|
||||
{
|
||||
String requestContentType = context.contentType();
|
||||
if(requestContentType != null)
|
||||
{
|
||||
requestContentType = requestContentType.toLowerCase().replaceAll(" *;.*", "");
|
||||
}
|
||||
|
||||
Content contentSpec = requestBody.getContent().get(requestContentType);
|
||||
if(contentSpec != null && "object".equals(contentSpec.getSchema().getType()))
|
||||
{
|
||||
if(contentSpec.getSchema().getProperties() != null && contentSpec.getSchema().getProperties().containsKey(name))
|
||||
{
|
||||
String value = null;
|
||||
if(ContentType.MULTIPART_FORM_DATA.getMimeType().equals(requestContentType))
|
||||
{
|
||||
value = context.formParam(name);
|
||||
}
|
||||
else if(ContentType.APPLICATION_JSON.getMimeType().equals(requestContentType))
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// avoid re-parsing the JSON object if getting multiple attributes from it //
|
||||
// by stashing it in a (request) attribute. //
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Object jsonBodyAttribute = context.attribute("jsonBody");
|
||||
JSONObject jsonObject = null;
|
||||
|
||||
if(jsonBodyAttribute instanceof JSONObject jo)
|
||||
{
|
||||
jsonObject = jo;
|
||||
}
|
||||
|
||||
if(jsonObject == null)
|
||||
{
|
||||
jsonObject = new JSONObject(context.body());
|
||||
context.attribute("jsonBody", jsonObject);
|
||||
}
|
||||
|
||||
if(jsonObject.has(name))
|
||||
{
|
||||
value = jsonObject.getString(name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.warn("Unhandled content type: " + requestContentType);
|
||||
}
|
||||
|
||||
return (value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
protected Map<String, Serializable> getRequestParamMap(Context context, String name)
|
||||
{
|
||||
String requestParam = getRequestParam(context, name);
|
||||
if(requestParam == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
JSONObject jsonObject = new JSONObject(requestParam);
|
||||
Map<String, Serializable> map = new LinkedHashMap<>();
|
||||
for(String key : jsonObject.keySet())
|
||||
{
|
||||
Object value = jsonObject.get(key);
|
||||
if(value instanceof Serializable s)
|
||||
{
|
||||
map.put(key, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new QRuntimeException("Non-serializable value in param map under key [" + name + "][" + key + "]: " + value.getClass().getSimpleName()));
|
||||
}
|
||||
}
|
||||
return (map);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
protected Integer getRequestParamInteger(Context context, String name)
|
||||
{
|
||||
String requestParam = getRequestParam(context, name);
|
||||
return ValueUtils.getValueAsInteger(requestParam);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** For initial setup when server boots, set the qInstance - but also,
|
||||
** e.g., for development, to do a hot-swap.
|
||||
***************************************************************************/
|
||||
public void setQInstance(QInstance qInstance)
|
||||
{
|
||||
this.qInstance = qInstance;
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// if we did a hot swap, we should clear these memoizations too //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
memoizedRequestParameters = null;
|
||||
memoizedRequestBody = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** An original implementation here was prone to race-condition-based errors:
|
||||
*
|
||||
** if(memoizedRequestParameters == null)
|
||||
** {
|
||||
** memoizedRequestParameters = CollectionUtils.nonNullList(defineRequestParameters());
|
||||
** }
|
||||
** return (memoizedRequestParameters);
|
||||
**
|
||||
** where between the defineX call and the return, if another thread cleared the
|
||||
** memoizedX field, then a null would be returned, which isn't supposed to happen.
|
||||
** Thus, this implementation which looks a bit more convoluted, but should
|
||||
** be safe(r).
|
||||
***************************************************************************/
|
||||
private List<Parameter> getMemoizedRequestParameters()
|
||||
{
|
||||
List<Parameter> rs = memoizedRequestParameters;
|
||||
if(rs == null)
|
||||
{
|
||||
rs = CollectionUtils.nonNullList(defineRequestParameters());
|
||||
memoizedRequestParameters = rs;
|
||||
}
|
||||
|
||||
return (rs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private RequestBody getMemoizedRequestBody()
|
||||
{
|
||||
RequestBody rs = memoizedRequestBody;
|
||||
if(rs == null)
|
||||
{
|
||||
rs = defineRequestBody();
|
||||
memoizedRequestBody = rs;
|
||||
}
|
||||
|
||||
return (rs);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,360 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs;
|
||||
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.utils.ClassPathUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.SchemaBuilder;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.openapi.model.Components;
|
||||
import com.kingsrook.qqq.openapi.model.Contact;
|
||||
import com.kingsrook.qqq.openapi.model.Content;
|
||||
import com.kingsrook.qqq.openapi.model.Example;
|
||||
import com.kingsrook.qqq.openapi.model.Info;
|
||||
import com.kingsrook.qqq.openapi.model.Method;
|
||||
import com.kingsrook.qqq.openapi.model.OpenAPI;
|
||||
import com.kingsrook.qqq.openapi.model.Path;
|
||||
import com.kingsrook.qqq.openapi.model.Response;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import com.kingsrook.qqq.openapi.model.SecurityScheme;
|
||||
import com.kingsrook.qqq.openapi.model.SecuritySchemeType;
|
||||
import com.kingsrook.qqq.openapi.model.Type;
|
||||
import io.javalin.apibuilder.EndpointGroup;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Baseclass that combines multiple specs together into a single "version" of
|
||||
** the full qqq middleware.
|
||||
*******************************************************************************/
|
||||
public abstract class AbstractMiddlewareVersion
|
||||
{
|
||||
public static final QLogger LOG = QLogger.getLogger(AbstractMiddlewareVersion.class);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public abstract String getVersion();
|
||||
|
||||
/***************************************************************************
|
||||
** hey - don't re-construct the endpoint-spec objects inside this method...
|
||||
***************************************************************************/
|
||||
public abstract List<AbstractEndpointSpec<?, ?, ?>> getEndpointSpecs();
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public EndpointGroup getJavalinEndpointGroup(QInstance qInstance)
|
||||
{
|
||||
return (() ->
|
||||
{
|
||||
for(AbstractEndpointSpec<?, ?, ?> spec : CollectionUtils.nonNullList(getEndpointSpecs()))
|
||||
{
|
||||
spec.defineRoute("/" + getVersion() + "/");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** For initial setup when server boots, set the qInstance - but also,
|
||||
** e.g., for development, to do a hot-swap.
|
||||
***************************************************************************/
|
||||
public void setQInstance(QInstance qInstance)
|
||||
{
|
||||
getEndpointSpecs().forEach(spec -> spec.setQInstance(qInstance));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public OpenAPI generateOpenAPIModel(String basePath) throws QException
|
||||
{
|
||||
List<AbstractEndpointSpec<?, ?, ?>> list = getEndpointSpecs();
|
||||
|
||||
Map<String, Path> paths = new LinkedHashMap<>();
|
||||
Map<String, Example> componentExamples = new LinkedHashMap<>();
|
||||
|
||||
Set<Class<?>> componentClasses = new HashSet<>();
|
||||
Map<String, Schema> componentSchemas = new TreeMap<>();
|
||||
buildComponentSchemasFromComponentsPackage(componentSchemas, componentClasses);
|
||||
|
||||
String sessionUuidCookieSchemeName = "sessionUuidCookie";
|
||||
SecurityScheme sessionUuidCookieScheme = new SecurityScheme()
|
||||
.withType(SecuritySchemeType.API_KEY)
|
||||
.withName("sessionUUID")
|
||||
.withIn("cookie");
|
||||
|
||||
for(AbstractEndpointSpec<?, ?, ?> spec : list)
|
||||
{
|
||||
CompleteOperation completeOperation = spec.defineCompleteOperation();
|
||||
String fullPath = ("/" + basePath + "/" + getVersion() + "/" + completeOperation.getPath()).replaceAll("/+", "/");
|
||||
Path path = paths.computeIfAbsent(fullPath, (k) -> new Path());
|
||||
Method method = completeOperation.getMethod();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if this spec is supposed to be secured, but no security has been applied, then add our default security //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
if(spec.isSecured() && method.getSecurity() == null)
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// the N/A here refers to the lack of a 'scope' for this kind of permission //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
method.withSecurity(List.of(Map.of(sessionUuidCookieSchemeName, List.of("N/A"))));
|
||||
}
|
||||
|
||||
convertMethodSchemasToRefs(method, componentClasses);
|
||||
|
||||
switch(completeOperation.getHttpMethod())
|
||||
{
|
||||
case GET ->
|
||||
{
|
||||
warnIfPathMethodAlreadyUsed(path.getGet(), completeOperation, spec);
|
||||
path.withGet(method);
|
||||
}
|
||||
case POST ->
|
||||
{
|
||||
warnIfPathMethodAlreadyUsed(path.getPost(), completeOperation, spec);
|
||||
path.withPost(method);
|
||||
}
|
||||
case PUT ->
|
||||
{
|
||||
warnIfPathMethodAlreadyUsed(path.getPut(), completeOperation, spec);
|
||||
path.withPut(method);
|
||||
}
|
||||
case PATCH ->
|
||||
{
|
||||
warnIfPathMethodAlreadyUsed(path.getPatch(), completeOperation, spec);
|
||||
path.withPatch(method);
|
||||
}
|
||||
case DELETE ->
|
||||
{
|
||||
warnIfPathMethodAlreadyUsed(path.getDelete(), completeOperation, spec);
|
||||
path.withDelete(method);
|
||||
}
|
||||
}
|
||||
|
||||
for(Map.Entry<String, Schema> entry : CollectionUtils.nonNullMap(spec.defineComponentSchemas()).entrySet())
|
||||
{
|
||||
if(componentSchemas.containsKey(entry.getKey()))
|
||||
{
|
||||
LOG.warn("More than one endpoint spec defined a componentSchema named: " + entry.getKey() + ". The last one encountered (from " + spec.getClass().getSimpleName() + ") will be used.");
|
||||
}
|
||||
|
||||
componentSchemas.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
OpenAPI openAPI = new OpenAPI();
|
||||
openAPI.withInfo(new Info()
|
||||
.withVersion(getVersion())
|
||||
.withTitle("QQQ Middleware API")
|
||||
.withDescription(getDescription())
|
||||
.withContact(new Contact().withEmail("contact@kingsrook.com"))
|
||||
);
|
||||
|
||||
openAPI.withPaths(paths);
|
||||
|
||||
openAPI.withComponents(new Components()
|
||||
.withSchemas(componentSchemas)
|
||||
.withExamples(componentExamples)
|
||||
.withSecuritySchemes(Map.of(sessionUuidCookieSchemeName, sessionUuidCookieScheme))
|
||||
);
|
||||
|
||||
return openAPI;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private void buildComponentSchemasFromComponentsPackage(Map<String, Schema> componentSchemas, Set<Class<?>> componentClasses) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
////////////////////////////////////////////////////
|
||||
// find all classes in the components sub-package //
|
||||
////////////////////////////////////////////////////
|
||||
String packageName = getClass().getPackageName();
|
||||
List<Class<?>> classesInPackage = ClassPathUtils.getClassesInPackage(packageName);
|
||||
for(Class<?> c : classesInPackage)
|
||||
{
|
||||
if(c.getPackageName().matches(".*\\bcomponents\\b.*"))
|
||||
{
|
||||
componentClasses.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// now that we know that full set, make any references to others schemas in those objects be via Ref //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
for(Class<?> c : componentClasses)
|
||||
{
|
||||
Object o = null;
|
||||
try
|
||||
{
|
||||
o = c.getConstructor().newInstance();
|
||||
}
|
||||
catch(Exception nsme)
|
||||
{
|
||||
///////////////////////////////////////
|
||||
// fine, assume we can't do toSchema //
|
||||
///////////////////////////////////////
|
||||
}
|
||||
|
||||
Schema schema = null;
|
||||
if(o instanceof ToSchema toSchema)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// just in case a custom implementation of toSchema is provided (e.g., to go around a wrapped object or some-such) //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
schema = toSchema.toSchema();
|
||||
}
|
||||
else
|
||||
{
|
||||
schema = new SchemaBuilder().classToSchema(c);
|
||||
}
|
||||
|
||||
convertSchemaToRefs(schema, componentClasses);
|
||||
|
||||
componentSchemas.put(c.getSimpleName(), schema);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw (new QException("Error building component schemas from components package", e));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private void convertMethodSchemasToRefs(Method method, Set<Class<?>> componentClasses)
|
||||
{
|
||||
for(Response response : method.getResponses().values())
|
||||
{
|
||||
for(Content content : response.getContent().values())
|
||||
{
|
||||
Schema schema = content.getSchema();
|
||||
convertSchemaToRefs(schema, componentClasses);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private void convertSchemaToRefs(Schema schema, Set<Class<?>> componentClasses)
|
||||
{
|
||||
if(schema.getItems() instanceof SchemaBuilder.SchemaFromBuilder itemSchemaFromBuilder && componentClasses.contains(itemSchemaFromBuilder.getOriginalClass()))
|
||||
{
|
||||
schema.getItems().withRefToSchema(itemSchemaFromBuilder.getOriginalClass().getSimpleName());
|
||||
schema.getItems().setProperties(null);
|
||||
schema.getItems().setType((Type) null);
|
||||
}
|
||||
else if(schema.getItems() != null)
|
||||
{
|
||||
convertSchemaToRefs(schema.getItems(), componentClasses);
|
||||
}
|
||||
|
||||
if(schema.getProperties() != null)
|
||||
{
|
||||
for(Schema propertySchema : schema.getProperties().values())
|
||||
{
|
||||
if(propertySchema instanceof SchemaBuilder.SchemaFromBuilder propertySchemaFromBuilder && componentClasses.contains(propertySchemaFromBuilder.getOriginalClass()))
|
||||
{
|
||||
propertySchema.withRefToSchema(propertySchemaFromBuilder.getOriginalClass().getSimpleName());
|
||||
propertySchema.setProperties(null);
|
||||
propertySchema.setType((Type) null);
|
||||
}
|
||||
else
|
||||
{
|
||||
convertSchemaToRefs(propertySchema, componentClasses);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static String getDescription()
|
||||
{
|
||||
return """
|
||||
## Intro
|
||||
This is the definition of the standard API implemented by QQQ Middleware.
|
||||
|
||||
Developers of QQQ Frontends (e.g., javascript libraries, or native applications) use this API to access
|
||||
a QQQ Backend server.
|
||||
|
||||
As such, this API itself is not concerned with any of the application-level details of any particular
|
||||
application built using QQQ. Instead, this API is all about the generic endpoints used for any application
|
||||
built on QQQ. For example, many endpoints work with a `${table}` path parameter - whose possible values
|
||||
are defined by the application - but which are not known to this API.
|
||||
|
||||
## Flow
|
||||
The typical flow of a user (as implemented in a frontend that utilizes this API) looks like:
|
||||
1. Frontend calls `.../metaData/authentication`, to know what type of authentication provider is used by the backend, and display an appropriate UI to the user for authenticating.
|
||||
2. User authenticates in frontend, as required for the authentication provider.
|
||||
3. Frontend calls `.../manageSession`, providing authentication details (e.g., an accessToken or other credentials) to the backend.
|
||||
4. The response from the `manageSession` call (assuming success), sets the `sessionUUID` Cookie, which should be included in all subsequent requests for authentication.
|
||||
5. After the user is authenticated, the frontend calls `.../metaData`, to discover the apps, tables, processes, etc, that the application is made up of (and that the authenticated user has permission to access).
|
||||
6. As the user interacts with apps, tables, process, etc, the frontend utilizes the appropriate endpoints as required.
|
||||
""";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public void warnIfPathMethodAlreadyUsed(Method existing, CompleteOperation completeOperation, AbstractEndpointSpec<?, ?, ?> spec)
|
||||
{
|
||||
if(existing != null)
|
||||
{
|
||||
LOG.warn("More than one endpoint spec for version " + getVersion() + " defined a " + completeOperation.getHttpMethod() + " at path: " + completeOperation.getPath() + ". The last one encountered (from " + spec.getClass().getSimpleName() + ") will be used.");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.openapi.model.HttpMethod;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Basic definition of an operation (e.g., an endpoint exposed in the API).
|
||||
*******************************************************************************/
|
||||
public class BasicOperation
|
||||
{
|
||||
private String path;
|
||||
private HttpMethod httpMethod;
|
||||
private TagsInterface tag;
|
||||
private String shortSummary;
|
||||
private String longDescription;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for path
|
||||
*******************************************************************************/
|
||||
public String getPath()
|
||||
{
|
||||
return (this.path);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for path
|
||||
*******************************************************************************/
|
||||
public void setPath(String path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for path
|
||||
*******************************************************************************/
|
||||
public BasicOperation withPath(String path)
|
||||
{
|
||||
this.path = path;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for httpMethod
|
||||
*******************************************************************************/
|
||||
public HttpMethod getHttpMethod()
|
||||
{
|
||||
return (this.httpMethod);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for httpMethod
|
||||
*******************************************************************************/
|
||||
public void setHttpMethod(HttpMethod httpMethod)
|
||||
{
|
||||
this.httpMethod = httpMethod;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for httpMethod
|
||||
*******************************************************************************/
|
||||
public BasicOperation withHttpMethod(HttpMethod httpMethod)
|
||||
{
|
||||
this.httpMethod = httpMethod;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tag
|
||||
*******************************************************************************/
|
||||
public TagsInterface getTag()
|
||||
{
|
||||
return (this.tag);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tag
|
||||
*******************************************************************************/
|
||||
public void setTag(TagsInterface tag)
|
||||
{
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for tag
|
||||
*******************************************************************************/
|
||||
public BasicOperation withTag(TagsInterface tag)
|
||||
{
|
||||
this.tag = tag;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for shortSummary
|
||||
*******************************************************************************/
|
||||
public String getShortSummary()
|
||||
{
|
||||
return (this.shortSummary);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for shortSummary
|
||||
*******************************************************************************/
|
||||
public void setShortSummary(String shortSummary)
|
||||
{
|
||||
this.shortSummary = shortSummary;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for shortSummary
|
||||
*******************************************************************************/
|
||||
public BasicOperation withShortSummary(String shortSummary)
|
||||
{
|
||||
this.shortSummary = shortSummary;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for longDescription
|
||||
*******************************************************************************/
|
||||
public String getLongDescription()
|
||||
{
|
||||
return (this.longDescription);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for longDescription
|
||||
*******************************************************************************/
|
||||
public void setLongDescription(String longDescription)
|
||||
{
|
||||
this.longDescription = longDescription;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for longDescription
|
||||
*******************************************************************************/
|
||||
public BasicOperation withLongDescription(String longDescription)
|
||||
{
|
||||
this.longDescription = longDescription;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.openapi.model.Example;
|
||||
import io.javalin.http.ContentType;
|
||||
import io.javalin.http.HttpStatus;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** Basic version of a response from a spec/endpoint.
|
||||
***************************************************************************/
|
||||
public record BasicResponse(String contentType, HttpStatus status, String description, String schemaRefName, Map<String, Example> examples)
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public BasicResponse(String description, String schemaRefName)
|
||||
{
|
||||
this(ContentType.APPLICATION_JSON.getMimeType(), HttpStatus.OK, description, schemaRefName, null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public BasicResponse(String description, String schemaRefName, Map<String, Example> examples)
|
||||
{
|
||||
this(ContentType.APPLICATION_JSON.getMimeType(), HttpStatus.OK, description, schemaRefName, examples);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public BasicResponse(HttpStatus status, String description, String schemaRefName)
|
||||
{
|
||||
this(ContentType.APPLICATION_JSON.getMimeType(), status, description, schemaRefName, null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public BasicResponse(HttpStatus status, String description, String schemaRefName, Map<String, Example> examples)
|
||||
{
|
||||
this(ContentType.APPLICATION_JSON.getMimeType(), status, description, schemaRefName, examples);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.openapi.model.Method;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Extension of a BasicOperation that adds the full openAPI Method object.
|
||||
*******************************************************************************/
|
||||
public class CompleteOperation extends BasicOperation
|
||||
{
|
||||
private Method method;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public CompleteOperation(BasicOperation basicOperation)
|
||||
{
|
||||
setPath(basicOperation.getPath());
|
||||
setHttpMethod(basicOperation.getHttpMethod());
|
||||
setTag(basicOperation.getTag());
|
||||
setLongDescription(basicOperation.getLongDescription());
|
||||
setShortSummary(basicOperation.getShortSummary());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for method
|
||||
*******************************************************************************/
|
||||
public Method getMethod()
|
||||
{
|
||||
return (this.method);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for method
|
||||
*******************************************************************************/
|
||||
public void setMethod(Method method)
|
||||
{
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for method
|
||||
*******************************************************************************/
|
||||
public CompleteOperation withMethod(Method method)
|
||||
{
|
||||
this.method = method;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface TagsInterface
|
||||
{
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
String getText();
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.AuthenticationMetaDataExecutor;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.AuthenticationMetaDataInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicOperation;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicResponse;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.AuthenticationMetaDataResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.TagsV1;
|
||||
import com.kingsrook.qqq.openapi.model.Example;
|
||||
import com.kingsrook.qqq.openapi.model.HttpMethod;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import io.javalin.http.Context;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class AuthenticationMetaDataSpecV1 extends AbstractEndpointSpec<AuthenticationMetaDataInput, AuthenticationMetaDataResponseV1, AuthenticationMetaDataExecutor>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public BasicOperation defineBasicOperation()
|
||||
{
|
||||
return new BasicOperation()
|
||||
.withPath("/metaData/authentication")
|
||||
.withHttpMethod(HttpMethod.GET)
|
||||
.withTag(TagsV1.AUTHENTICATION)
|
||||
.withShortSummary("Get authentication metaData")
|
||||
.withLongDescription("""
|
||||
For a frontend to determine which authentication provider or mechanism to use, it should begin its lifecycle
|
||||
by requesting this metaData object, and inspecting the `type` property in the response.
|
||||
|
||||
Note that this endpoint is not secured, as its purpose is to be called as part of the workflow that results
|
||||
in a user being authenticated."""
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public boolean isSecured()
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public AuthenticationMetaDataInput buildInput(Context context) throws Exception
|
||||
{
|
||||
AuthenticationMetaDataInput input = new AuthenticationMetaDataInput();
|
||||
return (input);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Map<String, Schema> defineComponentSchemas()
|
||||
{
|
||||
return Map.of(AuthenticationMetaDataResponseV1.class.getSimpleName(), new AuthenticationMetaDataResponseV1().toSchema());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public BasicResponse defineBasicSuccessResponse()
|
||||
{
|
||||
Map<String, Example> examples = new LinkedHashMap<>();
|
||||
examples.put("For FULLY_ANONYMOUS type", new Example()
|
||||
.withValue(new AuthenticationMetaDataResponseV1()
|
||||
.withType(QAuthenticationType.FULLY_ANONYMOUS.name())
|
||||
.withName("anonymous")));
|
||||
|
||||
examples.put("For AUTH_0 type", new Example()
|
||||
.withValue(new AuthenticationMetaDataResponseV1()
|
||||
.withType(QAuthenticationType.AUTH_0.name())
|
||||
.withName("auth0")
|
||||
.withValues(new AuthenticationMetaDataResponseV1.Auth0Values()
|
||||
.withClientId("abcdefg1234567")
|
||||
.withBaseUrl("https://myapp.auth0.com/")
|
||||
.withAudience("myapp.mydomain.com"))));
|
||||
|
||||
return new BasicResponse("Successful Response", AuthenticationMetaDataResponseV1.class.getSimpleName(), examples);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void handleOutput(Context context, AuthenticationMetaDataResponseV1 output) throws Exception
|
||||
{
|
||||
context.result(JsonUtils.toJson(output));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.collections.MapBuilder;
|
||||
import com.kingsrook.qqq.backend.javalin.QJavalinImplementation;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.ManageSessionExecutor;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ManageSessionInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicOperation;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicResponse;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.BasicErrorResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.ManageSessionResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.ProcessSpecUtilsV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.TagsV1;
|
||||
import com.kingsrook.qqq.openapi.model.Content;
|
||||
import com.kingsrook.qqq.openapi.model.Example;
|
||||
import com.kingsrook.qqq.openapi.model.HttpMethod;
|
||||
import com.kingsrook.qqq.openapi.model.RequestBody;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import com.kingsrook.qqq.openapi.model.Type;
|
||||
import io.javalin.http.ContentType;
|
||||
import io.javalin.http.Context;
|
||||
import io.javalin.http.HttpStatus;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ManageSessionSpecV1 extends AbstractEndpointSpec<ManageSessionInput, ManageSessionResponseV1, ManageSessionExecutor>
|
||||
{
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public BasicOperation defineBasicOperation()
|
||||
{
|
||||
return new BasicOperation()
|
||||
.withPath("/manageSession")
|
||||
.withHttpMethod(HttpMethod.POST)
|
||||
.withTag(TagsV1.AUTHENTICATION)
|
||||
.withShortSummary("Create a session")
|
||||
.withLongDescription("""
|
||||
After a frontend authenticates the user as per the requirements of the authentication provider specified by the
|
||||
`type` field in the `metaData/authentication` response, data from that authentication provider should be posted
|
||||
to this endpoint, to create a session within the QQQ application.
|
||||
|
||||
The response object will include a session identifier (`uuid`) to authenticate the user in subsequent API calls.""");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public boolean isSecured()
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public ManageSessionResponseV1 serveRequest(Context context) throws Exception
|
||||
{
|
||||
ManageSessionResponseV1 result = super.serveRequest(context);
|
||||
if(result != null)
|
||||
{
|
||||
String sessionUuid = result.getUuid();
|
||||
context.cookie(QJavalinImplementation.SESSION_UUID_COOKIE_NAME, sessionUuid, QJavalinImplementation.SESSION_COOKIE_AGE);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public RequestBody defineRequestBody()
|
||||
{
|
||||
return new RequestBody()
|
||||
.withRequired(true)
|
||||
.withContent(MapBuilder.of(ContentType.JSON, new Content()
|
||||
.withSchema(new Schema()
|
||||
.withDescription("Data required to create the session. Specific needs may vary based on the AuthenticationModule type in the QQQ Backend.")
|
||||
.withType(Type.OBJECT)
|
||||
.withProperty("accessToken", new Schema()
|
||||
.withType(Type.STRING)
|
||||
.withDescription("An access token from a downstream authentication provider (e.g., Auth0), to use as the basis for authentication and authorization.")
|
||||
)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public ManageSessionInput buildInput(Context context) throws Exception
|
||||
{
|
||||
ManageSessionInput manageSessionInput = new ManageSessionInput();
|
||||
manageSessionInput.setAccessToken(getRequestParam(context, "accessToken"));
|
||||
return (manageSessionInput);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public BasicResponse defineBasicSuccessResponse()
|
||||
{
|
||||
Map<String, Example> examples = new LinkedHashMap<>();
|
||||
|
||||
examples.put("With no custom values", new Example().withValue(new ManageSessionResponseV1()
|
||||
.withUuid(ProcessSpecUtilsV1.EXAMPLE_PROCESS_UUID)
|
||||
));
|
||||
|
||||
examples.put("With custom values", new Example().withValue(new ManageSessionResponseV1()
|
||||
.withUuid(ProcessSpecUtilsV1.EXAMPLE_JOB_UUID)
|
||||
.withValues(MapBuilder.of(LinkedHashMap<String, Serializable>::new)
|
||||
.with("region", "US")
|
||||
.with("userCategoryId", 47)
|
||||
.build()
|
||||
)
|
||||
));
|
||||
|
||||
return new BasicResponse("Successful response - session has been created",
|
||||
ManageSessionResponseV1.class.getSimpleName(),
|
||||
examples);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Map<String, Schema> defineComponentSchemas()
|
||||
{
|
||||
return Map.of(
|
||||
ManageSessionResponseV1.class.getSimpleName(), new ManageSessionResponseV1().toSchema(),
|
||||
BasicErrorResponseV1.class.getSimpleName(), new BasicErrorResponseV1().toSchema()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public List<BasicResponse> defineAdditionalBasicResponses()
|
||||
{
|
||||
Map<String, Example> examples = new LinkedHashMap<>();
|
||||
examples.put("Invalid token", new Example().withValue(new BasicErrorResponseV1().withError("Unable to decode access token.")));
|
||||
|
||||
return List.of(
|
||||
new BasicResponse(HttpStatus.UNAUTHORIZED,
|
||||
"Authentication error - session was not created",
|
||||
BasicErrorResponseV1.class.getSimpleName(),
|
||||
examples
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void handleOutput(Context context, ManageSessionResponseV1 output) throws Exception
|
||||
{
|
||||
context.result(JsonUtils.toJson(output));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.metadata.MetaDataAction;
|
||||
import com.kingsrook.qqq.backend.core.context.CapturedContext;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.authentication.QAuthenticationMetaData;
|
||||
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.QAppMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.permissions.PermissionLevel;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.permissions.QPermissionRules;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.Capability;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSystemUserSession;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.MetaDataExecutor;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.MetaDataInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicOperation;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicResponse;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.MetaDataResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.TagsV1;
|
||||
import com.kingsrook.qqq.openapi.model.Example;
|
||||
import com.kingsrook.qqq.openapi.model.HttpMethod;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import io.javalin.http.Context;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class MetaDataSpecV1 extends AbstractEndpointSpec<MetaDataInput, MetaDataResponseV1, MetaDataExecutor>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public BasicOperation defineBasicOperation()
|
||||
{
|
||||
return new BasicOperation()
|
||||
.withPath("/metaData")
|
||||
.withHttpMethod(HttpMethod.GET)
|
||||
.withTag(TagsV1.GENERAL)
|
||||
.withShortSummary("Get instance metaData")
|
||||
.withLongDescription("""
|
||||
Load the overall metadata, as is relevant to a frontend, for the entire application, with permissions applied, as per the
|
||||
authenticated user.
|
||||
|
||||
This includes:
|
||||
- Apps (both as a map of name to AppMetaData (`apps`), but also as a tree (`appTree`), for presenting
|
||||
hierarchical navigation),
|
||||
- Tables (but without all details, e.g., fields),
|
||||
- Processes (also without full details, e.g., screens),
|
||||
- Reports
|
||||
- Widgets
|
||||
- Branding
|
||||
- Help Contents
|
||||
- Environment values
|
||||
"""
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public MetaDataInput buildInput(Context context) throws Exception
|
||||
{
|
||||
MetaDataInput input = new MetaDataInput();
|
||||
return (input);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Map<String, Schema> defineComponentSchemas()
|
||||
{
|
||||
return Map.of(MetaDataResponseV1.class.getSimpleName(), new MetaDataResponseV1().toSchema());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public BasicResponse defineBasicSuccessResponse()
|
||||
{
|
||||
Map<String, Example> examples = new HashMap<>();
|
||||
|
||||
QInstance exampleInstance = new QInstance();
|
||||
|
||||
exampleInstance.setAuthentication(new QAuthenticationMetaData().withName("anonymous").withType(QAuthenticationType.FULLY_ANONYMOUS));
|
||||
|
||||
QBackendMetaData exampleBackend = new QBackendMetaData()
|
||||
.withName("example")
|
||||
.withBackendType(MemoryBackendModule.class);
|
||||
exampleInstance.addBackend(exampleBackend);
|
||||
|
||||
QTableMetaData exampleTable = new QTableMetaData()
|
||||
.withName("person")
|
||||
.withLabel("Person")
|
||||
.withBackendName("example")
|
||||
.withPrimaryKeyField("id")
|
||||
.withIsHidden(false)
|
||||
.withIcon(new QIcon().withName("person_outline"))
|
||||
.withCapabilities(Capability.allReadCapabilities())
|
||||
.withCapabilities(Capability.allWriteCapabilities())
|
||||
.withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED))
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER));
|
||||
exampleInstance.addTable(exampleTable);
|
||||
|
||||
QProcessMetaData exampleProcess = new QProcessMetaData()
|
||||
.withName("samplePersonProcess")
|
||||
.withLabel("Sample Person Process")
|
||||
.withTableName("person")
|
||||
.withIsHidden(false)
|
||||
.withIcon(new QIcon().withName("person_add"))
|
||||
.withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED))
|
||||
.withStep(new QFrontendStepMetaData().withName("example"));
|
||||
exampleInstance.addProcess(exampleProcess);
|
||||
|
||||
QAppMetaData childApp = new QAppMetaData()
|
||||
.withName("childApp")
|
||||
.withLabel("Child App")
|
||||
.withIcon(new QIcon().withName("child_friendly"))
|
||||
.withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED))
|
||||
.withChild(exampleProcess);
|
||||
exampleInstance.addApp(childApp);
|
||||
|
||||
QAppMetaData exampleApp = new QAppMetaData()
|
||||
.withName("homeApp")
|
||||
.withLabel("Home App")
|
||||
.withIcon(new QIcon().withName("home"))
|
||||
.withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED))
|
||||
.withChild(childApp)
|
||||
.withChild(exampleTable);
|
||||
exampleInstance.addApp(exampleApp);
|
||||
|
||||
QContext.withTemporaryContext(new CapturedContext(exampleInstance, new QSystemUserSession()), () ->
|
||||
{
|
||||
try
|
||||
{
|
||||
MetaDataAction metaDataAction = new MetaDataAction();
|
||||
MetaDataOutput output = metaDataAction.execute(new com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataInput());
|
||||
examples.put("Example", new Example()
|
||||
.withValue(new MetaDataResponseV1()
|
||||
.withMetaDataOutput(output)
|
||||
)
|
||||
);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
examples.put("Example", new Example().withValue("Error building example: " + e.getMessage())
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return new BasicResponse("""
|
||||
Overall metadata for the application.""",
|
||||
MetaDataResponseV1.class.getSimpleName(),
|
||||
examples
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void handleOutput(Context context, MetaDataResponseV1 output) throws Exception
|
||||
{
|
||||
context.result(JsonUtils.toJson(output));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractMiddlewareVersion;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class MiddlewareVersionV1 extends AbstractMiddlewareVersion
|
||||
{
|
||||
private static List<AbstractEndpointSpec<?, ?, ?>> list = new ArrayList<>();
|
||||
|
||||
static
|
||||
{
|
||||
list.add(new AuthenticationMetaDataSpecV1());
|
||||
list.add(new ManageSessionSpecV1());
|
||||
|
||||
list.add(new MetaDataSpecV1());
|
||||
|
||||
list.add(new ProcessMetaDataSpecV1());
|
||||
list.add(new ProcessInitSpecV1());
|
||||
list.add(new ProcessStepSpecV1());
|
||||
list.add(new ProcessStatusSpecV1());
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public String getVersion()
|
||||
{
|
||||
return "v1";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public List<AbstractEndpointSpec<?, ?, ?>> getEndpointSpecs()
|
||||
{
|
||||
return (list);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,268 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.ProcessInitOrStepExecutor;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessInitOrStepInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicOperation;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicResponse;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.ProcessInitOrStepOrStatusResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.ProcessSpecUtilsV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.TagsV1;
|
||||
import com.kingsrook.qqq.openapi.model.Content;
|
||||
import com.kingsrook.qqq.openapi.model.Example;
|
||||
import com.kingsrook.qqq.openapi.model.HttpMethod;
|
||||
import com.kingsrook.qqq.openapi.model.In;
|
||||
import com.kingsrook.qqq.openapi.model.Parameter;
|
||||
import com.kingsrook.qqq.openapi.model.RequestBody;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import com.kingsrook.qqq.openapi.model.Type;
|
||||
import io.javalin.http.ContentType;
|
||||
import io.javalin.http.Context;
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessInitSpecV1 extends AbstractEndpointSpec<ProcessInitOrStepInput, ProcessInitOrStepOrStatusResponseV1, ProcessInitOrStepExecutor>
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(ProcessInitSpecV1.class);
|
||||
|
||||
public static int DEFAULT_ASYNC_STEP_TIMEOUT_MILLIS = 3_000;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public BasicOperation defineBasicOperation()
|
||||
{
|
||||
return new BasicOperation()
|
||||
.withPath("/processes/{processName}/init")
|
||||
.withHttpMethod(HttpMethod.POST)
|
||||
.withTag(TagsV1.PROCESSES)
|
||||
.withShortSummary("Initialize a process")
|
||||
.withLongDescription("""
|
||||
For a user to start running a process, this endpoint should be called, to start the process
|
||||
and run its first step(s) (any backend steps before the first frontend step).
|
||||
|
||||
Additional process-specific values should posted in a form param named `values`, as JSON object
|
||||
with keys defined by the process in question.
|
||||
|
||||
For a process which needs to operate on a set of records that a user selected, see
|
||||
`recordsParam`, and `recordIds` or `filterJSON`.
|
||||
|
||||
The response will include a `processUUID`, to be included in all subsequent requests relevant
|
||||
to the process.
|
||||
|
||||
Note that this request, if it takes longer than a given threshold* to complete, will return a
|
||||
a `jobUUID`, which should be sent to the `/processes/{processName}/{processUUID}/status/{jobUUID}`
|
||||
endpoint, to poll for a status update.
|
||||
|
||||
*This threshold has a default value of 3,000 ms., but can be set per-request via the form
|
||||
parameter `stepTimeoutMillis`.
|
||||
""");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public List<Parameter> defineRequestParameters()
|
||||
{
|
||||
return List.of(
|
||||
new Parameter()
|
||||
.withName("processName")
|
||||
.withDescription("Name of the process to initialize")
|
||||
.withRequired(true)
|
||||
.withSchema(new Schema().withType(Type.STRING))
|
||||
.withExample("samplePersonProcess")
|
||||
.withIn(In.PATH)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public RequestBody defineRequestBody()
|
||||
{
|
||||
return new RequestBody()
|
||||
.withContent(
|
||||
ContentType.MULTIPART_FORM_DATA.getMimeType(), new Content()
|
||||
.withSchema(new Schema()
|
||||
.withType(Type.OBJECT)
|
||||
.withProperty("values", new Schema()
|
||||
.withType(Type.OBJECT)
|
||||
.withDescription("Process-specific field names and values."))
|
||||
|
||||
.withProperty("recordsParam", new Schema()
|
||||
.withDescription("Specifies which other query-param will contain the indicator of initial records to pass in to the process.")
|
||||
.withType(Type.STRING)
|
||||
.withExample("recordIds", new Example().withValue("recordIds"))
|
||||
.withExample("filterJSON", new Example().withValue("recordIds")))
|
||||
|
||||
.withProperty("recordIds", new Schema()
|
||||
.withDescription("Comma-separated list of ids from the table this process is based on, to use as input records for the process. Needs `recordsParam=recordIds` value to be given as well.")
|
||||
.withType(Type.STRING)
|
||||
.withExample("one id", new Example().withValue("1701"))
|
||||
.withExample("multiple ids", new Example().withValue("42,47")))
|
||||
|
||||
.withProperty("filterJSON", new Schema()
|
||||
.withDescription("JSON encoded QQueryFilter object, to execute against the table this process is based on, to find input records for the process. Needs `recordsParam=filterJSON` value to be given as well.")
|
||||
.withType(Type.STRING)
|
||||
.withExample("empty filter (all records)", new Example().withValue("{}"))
|
||||
.withExample("filter by a condition", new Example().withValue(
|
||||
JsonUtils.toJson(new QQueryFilter().withCriteria(new QFilterCriteria("id", QCriteriaOperator.LESS_THAN, 10))))
|
||||
))
|
||||
|
||||
.withProperty("stepTimeoutMillis", new Schema()
|
||||
.withDescription("Optionally change the time that the server will wait for the job before letting it go asynchronous. Default value is 3000.")
|
||||
.withType(Type.INTEGER)
|
||||
.withExample("shorter timeout", new Example().withValue("500"))
|
||||
.withExample("longer timeout", new Example().withValue("60000")))
|
||||
|
||||
.withProperty("file", new Schema()
|
||||
.withType(Type.STRING)
|
||||
.withFormat("binary")
|
||||
.withDescription("A file upload, for processes which expect to be initialized with an uploaded file.")
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public ProcessInitOrStepInput buildInput(Context context) throws Exception
|
||||
{
|
||||
ProcessInitOrStepInput processInitOrStepInput = new ProcessInitOrStepInput();
|
||||
processInitOrStepInput.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.BREAK);
|
||||
|
||||
processInitOrStepInput.setProcessName(getRequestParam(context, "processName"));
|
||||
processInitOrStepInput.setStepTimeoutMillis(Objects.requireNonNullElse(getRequestParamInteger(context, "stepTimeoutMillis"), DEFAULT_ASYNC_STEP_TIMEOUT_MILLIS));
|
||||
processInitOrStepInput.setValues(getRequestParamMap(context, "values"));
|
||||
|
||||
String recordsParam = getRequestParam(context, "recordsParam");
|
||||
String recordIds = getRequestParam(context, "recordIds");
|
||||
String filterJSON = getRequestParam(context, "filterJSON");
|
||||
QQueryFilter initialRecordsFilter = buildProcessInitRecordsFilter(recordsParam, recordIds, filterJSON, processInitOrStepInput);
|
||||
processInitOrStepInput.setRecordsFilter(initialRecordsFilter);
|
||||
|
||||
// todo - uploaded files
|
||||
// todo - archive uploaded files?
|
||||
|
||||
return (processInitOrStepInput);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static QQueryFilter buildProcessInitRecordsFilter(String recordsParam, String recordIds, String filterJSON, ProcessInitOrStepInput processInitOrStepInput) throws IOException
|
||||
{
|
||||
QProcessMetaData process = QContext.getQInstance().getProcess(processInitOrStepInput.getProcessName());
|
||||
QTableMetaData table = QContext.getQInstance().getTable(process.getTableName());
|
||||
|
||||
if(table == null)
|
||||
{
|
||||
LOG.info("No table found in process - so not building an init records filter.");
|
||||
return (null);
|
||||
}
|
||||
String primaryKeyField = table.getPrimaryKeyField();
|
||||
|
||||
if(StringUtils.hasContent(recordsParam))
|
||||
{
|
||||
return switch(recordsParam)
|
||||
{
|
||||
case "recordIds" ->
|
||||
{
|
||||
Serializable[] idStrings = recordIds.split(",");
|
||||
yield (new QQueryFilter().withCriteria(new QFilterCriteria()
|
||||
.withFieldName(primaryKeyField)
|
||||
.withOperator(QCriteriaOperator.IN)
|
||||
.withValues(Arrays.stream(idStrings).toList())));
|
||||
}
|
||||
case "filterJSON" -> (JsonUtils.toObject(filterJSON, QQueryFilter.class));
|
||||
case "filterId" -> throw (new NotImplementedException("Saved filters are not yet implemented."));
|
||||
default -> throw (new IllegalArgumentException("Unrecognized value [" + recordsParam + "] for query parameter: recordsParam"));
|
||||
};
|
||||
}
|
||||
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public BasicResponse defineBasicSuccessResponse()
|
||||
{
|
||||
return new BasicResponse("""
|
||||
State of the initialization of the job, with different fields set, based on the
|
||||
status of the task.""",
|
||||
|
||||
ProcessSpecUtilsV1.getResponseSchemaRefName(),
|
||||
ProcessSpecUtilsV1.buildResponseExample()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void handleOutput(Context context, ProcessInitOrStepOrStatusResponseV1 output) throws Exception
|
||||
{
|
||||
ProcessSpecUtilsV1.handleOutput(context, output);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.ProcessMetaDataExecutor;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessMetaDataInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicOperation;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicResponse;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.ProcessMetaDataResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.TagsV1;
|
||||
import com.kingsrook.qqq.openapi.model.Example;
|
||||
import com.kingsrook.qqq.openapi.model.HttpMethod;
|
||||
import com.kingsrook.qqq.openapi.model.In;
|
||||
import com.kingsrook.qqq.openapi.model.Parameter;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import com.kingsrook.qqq.openapi.model.Type;
|
||||
import io.javalin.http.Context;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessMetaDataSpecV1 extends AbstractEndpointSpec<ProcessMetaDataInput, ProcessMetaDataResponseV1, ProcessMetaDataExecutor>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public BasicOperation defineBasicOperation()
|
||||
{
|
||||
return new BasicOperation()
|
||||
.withPath("/metaData/process/{processName}")
|
||||
.withHttpMethod(HttpMethod.GET)
|
||||
.withTag(TagsV1.PROCESSES)
|
||||
.withShortSummary("Get process metaData")
|
||||
.withLongDescription("""
|
||||
Load the full metadata for a single process, including all screens (aka, frontend steps), which a frontend
|
||||
needs to display to users."""
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public List<Parameter> defineRequestParameters()
|
||||
{
|
||||
return List.of(
|
||||
new Parameter()
|
||||
.withName("processName")
|
||||
.withDescription("Name of the process to load.")
|
||||
.withRequired(true)
|
||||
.withSchema(new Schema().withType(Type.STRING))
|
||||
.withExample("samplePersonProcess")
|
||||
.withIn(In.PATH)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public ProcessMetaDataInput buildInput(Context context) throws Exception
|
||||
{
|
||||
ProcessMetaDataInput input = new ProcessMetaDataInput();
|
||||
input.setProcessName(getRequestParam(context, "processName"));
|
||||
return (input);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Map<String, Schema> defineComponentSchemas()
|
||||
{
|
||||
return Map.of(ProcessMetaDataResponseV1.class.getSimpleName(), new ProcessMetaDataResponseV1().toSchema());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public BasicResponse defineBasicSuccessResponse()
|
||||
{
|
||||
Map<String, Example> examples = new LinkedHashMap<>();
|
||||
examples.put("TODO", new Example()
|
||||
.withValue(new ProcessMetaDataResponseV1())); // todo do
|
||||
|
||||
return new BasicResponse("""
|
||||
The full process metadata""",
|
||||
ProcessMetaDataResponseV1.class.getSimpleName(),
|
||||
examples
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void handleOutput(Context context, ProcessMetaDataResponseV1 output) throws Exception
|
||||
{
|
||||
context.result(JsonUtils.toJson(output.getProcessMetaData()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.ProcessStatusExecutor;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessStatusInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicOperation;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicResponse;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.ProcessInitOrStepOrStatusResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.ProcessSpecUtilsV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.TagsV1;
|
||||
import com.kingsrook.qqq.openapi.model.HttpMethod;
|
||||
import com.kingsrook.qqq.openapi.model.In;
|
||||
import com.kingsrook.qqq.openapi.model.Parameter;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import com.kingsrook.qqq.openapi.model.Type;
|
||||
import io.javalin.http.Context;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessStatusSpecV1 extends AbstractEndpointSpec<ProcessStatusInput, ProcessInitOrStepOrStatusResponseV1, ProcessStatusExecutor>
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public BasicOperation defineBasicOperation()
|
||||
{
|
||||
return new BasicOperation()
|
||||
.withPath("/processes/{processName}/{processUUID}/status/{jobUUID}")
|
||||
.withHttpMethod(HttpMethod.GET)
|
||||
.withTag(TagsV1.PROCESSES)
|
||||
.withShortSummary("Get job status")
|
||||
.withLongDescription("""
|
||||
Get the status of a running job for a process.
|
||||
|
||||
Response is the same format as for an init or step call that completed synchronously.
|
||||
"""
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public List<Parameter> defineRequestParameters()
|
||||
{
|
||||
return List.of(
|
||||
new Parameter()
|
||||
.withName("processName")
|
||||
.withDescription("Name of the process that is being ran")
|
||||
.withRequired(true)
|
||||
.withSchema(new Schema().withType(Type.STRING))
|
||||
.withExample("samplePersonProcess")
|
||||
.withIn(In.PATH),
|
||||
|
||||
new Parameter()
|
||||
.withName("processUUID")
|
||||
.withDescription("Unique identifier for this run of the process - as was returned by the `init` call.")
|
||||
.withRequired(true)
|
||||
.withSchema(new Schema().withType(Type.STRING).withFormat("uuid"))
|
||||
.withExample(ProcessSpecUtilsV1.EXAMPLE_PROCESS_UUID)
|
||||
.withIn(In.PATH),
|
||||
|
||||
new Parameter()
|
||||
.withName("jobUUID")
|
||||
.withDescription("Unique identifier for the asynchronous job being executed, as returned by an `init` or `step` call that went asynch.")
|
||||
.withRequired(true)
|
||||
.withSchema(new Schema().withType(Type.STRING).withFormat("uuid"))
|
||||
.withExample(ProcessSpecUtilsV1.EXAMPLE_JOB_UUID)
|
||||
.withIn(In.PATH)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** These aren't in the components sub-package, so they don't get auto-found.
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Map<String, Schema> defineComponentSchemas()
|
||||
{
|
||||
return Map.of(
|
||||
ProcessSpecUtilsV1.getResponseSchemaRefName(), new ProcessInitOrStepOrStatusResponseV1().toSchema(),
|
||||
"ProcessStepComplete", new ProcessInitOrStepOrStatusResponseV1.ProcessStepComplete().toSchema(),
|
||||
"ProcessStepJobStarted", new ProcessInitOrStepOrStatusResponseV1.ProcessStepJobStarted().toSchema(),
|
||||
"ProcessStepRunning", new ProcessInitOrStepOrStatusResponseV1.ProcessStepRunning().toSchema(),
|
||||
"ProcessStepError", new ProcessInitOrStepOrStatusResponseV1.ProcessStepError().toSchema()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public ProcessStatusInput buildInput(Context context) throws Exception
|
||||
{
|
||||
ProcessStatusInput input = new ProcessStatusInput();
|
||||
input.setProcessName(getRequestParam(context, "processName"));
|
||||
input.setProcessUUID(getRequestParam(context, "processUUID"));
|
||||
input.setJobUUID(getRequestParam(context, "jobUUID"));
|
||||
return (input);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public BasicResponse defineBasicSuccessResponse()
|
||||
{
|
||||
return new BasicResponse("""
|
||||
State of the backend's running of the specified job, with different fields set,
|
||||
based on the status of the job.""",
|
||||
// new ProcessInitOrStepOrStatusResponseV1().toSchema(),
|
||||
|
||||
ProcessSpecUtilsV1.getResponseSchemaRefName(),
|
||||
ProcessSpecUtilsV1.buildResponseExample()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void handleOutput(Context context, ProcessInitOrStepOrStatusResponseV1 output) throws Exception
|
||||
{
|
||||
ProcessSpecUtilsV1.handleOutput(context, output);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.ProcessInitOrStepExecutor;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessInitOrStepInput;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicOperation;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.BasicResponse;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.ProcessInitOrStepOrStatusResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.ProcessSpecUtilsV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.utils.TagsV1;
|
||||
import com.kingsrook.qqq.openapi.model.Content;
|
||||
import com.kingsrook.qqq.openapi.model.Example;
|
||||
import com.kingsrook.qqq.openapi.model.HttpMethod;
|
||||
import com.kingsrook.qqq.openapi.model.In;
|
||||
import com.kingsrook.qqq.openapi.model.Parameter;
|
||||
import com.kingsrook.qqq.openapi.model.RequestBody;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import com.kingsrook.qqq.openapi.model.Type;
|
||||
import io.javalin.http.ContentType;
|
||||
import io.javalin.http.Context;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessStepSpecV1 extends AbstractEndpointSpec<ProcessInitOrStepInput, ProcessInitOrStepOrStatusResponseV1, ProcessInitOrStepExecutor>
|
||||
{
|
||||
public static int DEFAULT_ASYNC_STEP_TIMEOUT_MILLIS = 3_000;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public BasicOperation defineBasicOperation()
|
||||
{
|
||||
return new BasicOperation()
|
||||
.withPath("/processes/{processName}/{processUUID}/step/{stepName}")
|
||||
.withHttpMethod(HttpMethod.POST)
|
||||
.withTag(TagsV1.PROCESSES)
|
||||
.withShortSummary("Run a step in a process")
|
||||
.withLongDescription("""
|
||||
To run the next step in a process, this endpoint should be called, with the `processName`
|
||||
and existing `processUUID`, as well as the step that was just completed in the frontend,
|
||||
given as `stepName`.
|
||||
|
||||
Additional process-specific values should posted in a form param named `values`, as JSON object
|
||||
with keys defined by the process in question.
|
||||
|
||||
Note that this request, if it takes longer than a given threshold* to complete, will return a
|
||||
a `jobUUID`, which should be sent to the `/processes/{processName}/{processUUID}/status/{jobUUID}`
|
||||
endpoint, to poll for a status update.
|
||||
|
||||
*This threshold has a default value of 3,000 ms., but can be set per-request via the form
|
||||
parameter `stepTimeoutMillis`.
|
||||
""");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public List<Parameter> defineRequestParameters()
|
||||
{
|
||||
return List.of(
|
||||
|
||||
new Parameter()
|
||||
.withName("processName")
|
||||
.withDescription("Name of the process to perform the step in.")
|
||||
.withRequired(true)
|
||||
.withExample("samplePersonProcess")
|
||||
.withSchema(new Schema().withType(Type.STRING))
|
||||
.withIn(In.PATH),
|
||||
|
||||
new Parameter()
|
||||
.withName("processUUID")
|
||||
.withDescription("Unique identifier for this run of the process - as was returned by the `init` call.")
|
||||
.withRequired(true)
|
||||
.withSchema(new Schema().withType(Type.STRING))
|
||||
.withExample(ProcessSpecUtilsV1.EXAMPLE_PROCESS_UUID)
|
||||
.withIn(In.PATH),
|
||||
|
||||
new Parameter()
|
||||
.withName("stepName")
|
||||
.withDescription("Name of the frontend step that the user has just completed.")
|
||||
.withRequired(true)
|
||||
.withSchema(new Schema().withType(Type.STRING))
|
||||
.withExample("inputForm")
|
||||
.withIn(In.PATH)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public RequestBody defineRequestBody()
|
||||
{
|
||||
return new RequestBody()
|
||||
.withContent(ContentType.MULTIPART_FORM_DATA.getMimeType(), new Content()
|
||||
.withSchema(new Schema()
|
||||
.withType(Type.OBJECT)
|
||||
.withProperty("values", new Schema()
|
||||
.withType(Type.OBJECT)
|
||||
.withDescription("Process-specific field names and values."))
|
||||
|
||||
.withProperty("stepTimeoutMillis", new Schema()
|
||||
.withDescription("Optionally change the time that the server will wait for the job before letting it go asynchronous. Default value is 3000.")
|
||||
.withType(Type.INTEGER)
|
||||
.withExample("shorter timeout", new Example().withValue("500"))
|
||||
.withExample("longer timeout", new Example().withValue("60000")))
|
||||
|
||||
.withProperty("file", new Schema()
|
||||
.withType(Type.STRING)
|
||||
.withFormat("binary")
|
||||
.withDescription("A file upload, for process steps which expect an uploaded file."))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public ProcessInitOrStepInput buildInput(Context context) throws Exception
|
||||
{
|
||||
ProcessInitOrStepInput processInitOrStepInput = new ProcessInitOrStepInput();
|
||||
processInitOrStepInput.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.BREAK);
|
||||
|
||||
processInitOrStepInput.setProcessName(getRequestParam(context, "processName"));
|
||||
processInitOrStepInput.setProcessUUID(getRequestParam(context, "processUUID"));
|
||||
processInitOrStepInput.setStartAfterStep(getRequestParam(context, "stepName"));
|
||||
processInitOrStepInput.setStepTimeoutMillis(Objects.requireNonNullElse(getRequestParamInteger(context, "stepTimeoutMillis"), DEFAULT_ASYNC_STEP_TIMEOUT_MILLIS));
|
||||
processInitOrStepInput.setValues(getRequestParamMap(context, "values"));
|
||||
|
||||
// todo - uploaded files
|
||||
// todo - archive uploaded files?
|
||||
|
||||
return (processInitOrStepInput);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public BasicResponse defineBasicSuccessResponse()
|
||||
{
|
||||
return new BasicResponse("""
|
||||
State of the backend's running of the next step(s) of the job, with different fields set,
|
||||
based on the status of the job.""",
|
||||
|
||||
ProcessSpecUtilsV1.getResponseSchemaRefName(),
|
||||
ProcessSpecUtilsV1.buildResponseExample()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void handleOutput(Context context, ProcessInitOrStepOrStatusResponseV1 output) throws Exception
|
||||
{
|
||||
ProcessSpecUtilsV1.handleOutput(context, output);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,340 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.authentication.Auth0AuthenticationMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.authentication.QAuthenticationMetaData;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.AuthenticationMetaDataOutputInterface;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIOneOf;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class AuthenticationMetaDataResponseV1 implements AuthenticationMetaDataOutputInterface, ToSchema
|
||||
{
|
||||
@OpenAPIDescription("""
|
||||
Specifier for the type of authentication module being used.
|
||||
|
||||
Frontends should use this value to determine how to prompt the user for authentication credentials.
|
||||
In addition, depending on this value, additional properties will be included in this object, as
|
||||
may be needed to complete the authorization workflow with the provider (e.g., a baseUrl, clientId,
|
||||
and audience for an OAuth type workflow).""")
|
||||
private String type;
|
||||
|
||||
@OpenAPIDescription("""
|
||||
Unique name for the authentication metaData object within the QInstance.
|
||||
""")
|
||||
private String name;
|
||||
|
||||
@OpenAPIDescription("""
|
||||
Additional values, as determined by the type of authentication provider.
|
||||
""")
|
||||
@OpenAPIOneOf()
|
||||
private Values values;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public sealed interface Values permits EmptyValues, Auth0Values
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("No additional values are used for some authentication providers.")
|
||||
public static final class EmptyValues implements Values
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Additional values used by the Auth0 type authentication provider.")
|
||||
public static final class Auth0Values implements Values
|
||||
{
|
||||
@OpenAPIDescription("ClientId for auth0")
|
||||
private String clientId;
|
||||
|
||||
@OpenAPIDescription("BaseUrl for auth0")
|
||||
private String baseUrl;
|
||||
|
||||
@OpenAPIDescription("Audience for auth0")
|
||||
private String audience;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for clientId
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getClientId()
|
||||
{
|
||||
return clientId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for clientId
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setClientId(String clientId)
|
||||
{
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for clientId
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Auth0Values withClientId(String clientId)
|
||||
{
|
||||
this.clientId = clientId;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for baseUrl
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getBaseUrl()
|
||||
{
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for baseUrl
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setBaseUrl(String baseUrl)
|
||||
{
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for baseUrl
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Auth0Values withBaseUrl(String baseUrl)
|
||||
{
|
||||
this.baseUrl = baseUrl;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for audience
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getAudience()
|
||||
{
|
||||
return audience;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for audience
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setAudience(String audience)
|
||||
{
|
||||
this.audience = audience;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for audience
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Auth0Values withAudience(String audience)
|
||||
{
|
||||
this.audience = audience;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setAuthenticationMetaData(QAuthenticationMetaData qAuthenticationMetaData)
|
||||
{
|
||||
setType(qAuthenticationMetaData.getType().name());
|
||||
setName(qAuthenticationMetaData.getName());
|
||||
|
||||
if(qAuthenticationMetaData instanceof Auth0AuthenticationMetaData auth0MetaData)
|
||||
{
|
||||
// values = new LinkedHashMap<>();
|
||||
// values.put("clientId", auth0MetaData.getClientId());
|
||||
// values.put("baseUrl", auth0MetaData.getBaseUrl());
|
||||
// values.put("audience", auth0MetaData.getAudience());
|
||||
Auth0Values auth0Values = new Auth0Values();
|
||||
values = auth0Values;
|
||||
auth0Values.setClientId(auth0MetaData.getClientId());
|
||||
auth0Values.setBaseUrl(auth0MetaData.getBaseUrl());
|
||||
auth0Values.setAudience(auth0MetaData.getAudience());
|
||||
}
|
||||
|
||||
/*
|
||||
JSONObject jsonObject = new JSONObject(JsonUtils.toJson(qAuthenticationMetaData));
|
||||
for(String key : jsonObject.keySet())
|
||||
{
|
||||
if("name".equals(key) || "type".equals(key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(values == null)
|
||||
{
|
||||
values = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
Object value = jsonObject.get(key);
|
||||
if(value instanceof Serializable s)
|
||||
{
|
||||
values.put(key, s);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for type
|
||||
*******************************************************************************/
|
||||
public String getType()
|
||||
{
|
||||
return (this.type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for type
|
||||
*******************************************************************************/
|
||||
public void setType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for type
|
||||
*******************************************************************************/
|
||||
public AuthenticationMetaDataResponseV1 withType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for name
|
||||
*******************************************************************************/
|
||||
public String getName()
|
||||
{
|
||||
return (this.name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for name
|
||||
*******************************************************************************/
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for name
|
||||
*******************************************************************************/
|
||||
public AuthenticationMetaDataResponseV1 withName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
*******************************************************************************/
|
||||
public Values getValues()
|
||||
{
|
||||
return (this.values);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
*******************************************************************************/
|
||||
public void setValues(Values values)
|
||||
{
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for values
|
||||
*******************************************************************************/
|
||||
public AuthenticationMetaDataResponseV1 withValues(Values values)
|
||||
{
|
||||
this.values = values;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class BasicErrorResponseV1 implements ToSchema
|
||||
{
|
||||
@OpenAPIDescription("Description of the error")
|
||||
private String error;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for error
|
||||
*******************************************************************************/
|
||||
public String getError()
|
||||
{
|
||||
return (this.error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for error
|
||||
*******************************************************************************/
|
||||
public void setError(String error)
|
||||
{
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for error
|
||||
*******************************************************************************/
|
||||
public BasicErrorResponseV1 withError(String error)
|
||||
{
|
||||
this.error = error;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ManageSessionOutputInterface;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIHasAdditionalProperties;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ManageSessionResponseV1 implements ManageSessionOutputInterface, ToSchema
|
||||
{
|
||||
@OpenAPIDescription("Unique identifier of the session. Required to be returned on subsequent requests in the sessionUUID Cookie, to prove authentication.")
|
||||
private String uuid;
|
||||
|
||||
@OpenAPIDescription("Optional object with application-defined values.")
|
||||
@OpenAPIHasAdditionalProperties()
|
||||
private Map<String, Serializable> values;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for uuid
|
||||
*******************************************************************************/
|
||||
public String getUuid()
|
||||
{
|
||||
return (this.uuid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for uuid
|
||||
*******************************************************************************/
|
||||
public void setUuid(String uuid)
|
||||
{
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for uuid
|
||||
*******************************************************************************/
|
||||
public ManageSessionResponseV1 withUuid(String uuid)
|
||||
{
|
||||
this.uuid = uuid;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getValues()
|
||||
{
|
||||
return (this.values);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
*******************************************************************************/
|
||||
public void setValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for values
|
||||
*******************************************************************************/
|
||||
public ManageSessionResponseV1 withValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.values = values;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendAppMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.MetaDataOutputInterface;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIMapValueType;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.AppMetaData;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.AppTreeNode;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.ProcessMetaDataLight;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.TableMetaDataLight;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class MetaDataResponseV1 implements MetaDataOutputInterface, ToSchema
|
||||
{
|
||||
@OpenAPIDescription("Map of all apps within the QQQ Instance (that the user has permission to see that they exist).")
|
||||
@OpenAPIMapValueType(value = AppMetaData.class, useRef = true)
|
||||
private Map<String, AppMetaData> apps;
|
||||
|
||||
@OpenAPIDescription("Tree of apps within the QQQ Instance, sorted and organized hierarchically, for presentation to a user.")
|
||||
@OpenAPIListItems(value = AppTreeNode.class, useRef = true)
|
||||
private List<AppTreeNode> appTree;
|
||||
|
||||
@OpenAPIDescription("Map of all tables within the QQQ Instance (that the user has permission to see that they exist).")
|
||||
@OpenAPIMapValueType(value = TableMetaDataLight.class, useRef = true)
|
||||
private Map<String, TableMetaDataLight> tables;
|
||||
|
||||
@OpenAPIDescription("Map of all processes within the QQQ Instance (that the user has permission to see that they exist).")
|
||||
@OpenAPIMapValueType(value = ProcessMetaDataLight.class, useRef = true)
|
||||
private Map<String, ProcessMetaDataLight> processes;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setMetaDataOutput(MetaDataOutput metaDataOutput)
|
||||
{
|
||||
apps = new HashMap<>();
|
||||
for(QFrontendAppMetaData app : CollectionUtils.nonNullMap(metaDataOutput.getApps()).values())
|
||||
{
|
||||
apps.put(app.getName(), new AppMetaData(app));
|
||||
}
|
||||
|
||||
appTree = new ArrayList<>();
|
||||
for(com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNode app : CollectionUtils.nonNullList(metaDataOutput.getAppTree()))
|
||||
{
|
||||
appTree.add(new AppTreeNode(app));
|
||||
}
|
||||
|
||||
tables = new HashMap<>();
|
||||
for(QFrontendTableMetaData table : CollectionUtils.nonNullMap(metaDataOutput.getTables()).values())
|
||||
{
|
||||
tables.put(table.getName(), new TableMetaDataLight(table));
|
||||
}
|
||||
|
||||
processes = new HashMap<>();
|
||||
for(QFrontendProcessMetaData process : CollectionUtils.nonNullMap(metaDataOutput.getProcesses()).values())
|
||||
{
|
||||
processes.put(process.getName(), new ProcessMetaDataLight(process));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for MetaDataOutput
|
||||
**
|
||||
*******************************************************************************/
|
||||
public MetaDataResponseV1 withMetaDataOutput(MetaDataOutput metaDataOutput)
|
||||
{
|
||||
setMetaDataOutput(metaDataOutput);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for apps
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, AppMetaData> getApps()
|
||||
{
|
||||
return apps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for appTree
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<AppTreeNode> getAppTree()
|
||||
{
|
||||
return appTree;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tables
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, TableMetaDataLight> getTables()
|
||||
{
|
||||
return tables;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processes
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, ProcessMetaDataLight> getProcesses()
|
||||
{
|
||||
return processes;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,444 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessInitOrStepOrStatusOutputInterface;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.SchemaBuilder;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIIncludeProperties;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIOneOf;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.FieldMetaData;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.FrontendStep;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.ProcessMetaDataAdjustment;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessInitOrStepOrStatusResponseV1 implements ProcessInitOrStepOrStatusOutputInterface, ToSchema
|
||||
{
|
||||
private TypedResponse typedResponse;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIOneOf()
|
||||
public static sealed class TypedResponse implements ToSchema permits ProcessStepComplete, ProcessStepJobStarted, ProcessStepRunning, ProcessStepError
|
||||
{
|
||||
@OpenAPIDescription("What kind of response has been received. Determines what additional fields will be set.")
|
||||
private String type;
|
||||
|
||||
@OpenAPIDescription("Unique identifier for a running instance the process.")
|
||||
private String processUUID;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for type
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processUUID
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getProcessUUID()
|
||||
{
|
||||
return processUUID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIIncludeProperties(ancestorClasses = { TypedResponse.class })
|
||||
@OpenAPIDescription("Data returned after the job is complete (whether it was synchronous, or asynchronous)")
|
||||
public static final class ProcessStepComplete extends TypedResponse
|
||||
{
|
||||
@OpenAPIDescription("Name of the next process step that needs to run (a frontend step). If there are no more steps in the process, this field will not be included. ")
|
||||
private String nextStep;
|
||||
|
||||
@OpenAPIDescription("Current values for fields used by the process.Keys are Strings, values can be any type, as determined by the application & process.")
|
||||
private Map<String, Serializable> values;
|
||||
|
||||
@OpenAPIDescription("Changes to be made to the process's metaData.")
|
||||
private ProcessMetaDataAdjustment processMetaDataAdjustment;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for nextStep
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getNextStep()
|
||||
{
|
||||
return nextStep;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getValues()
|
||||
{
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processMetaDataAdjustment
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessMetaDataAdjustment getProcessMetaDataAdjustment()
|
||||
{
|
||||
return processMetaDataAdjustment;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIIncludeProperties(ancestorClasses = { TypedResponse.class })
|
||||
@OpenAPIDescription("In case the backend needs more time, this is a UUID of the background job that has been started.")
|
||||
public static final class ProcessStepJobStarted extends TypedResponse
|
||||
{
|
||||
@OpenAPIDescription("Unique identifier for a running step of the process. Must be passed into `status` check calls.")
|
||||
private String jobUUID;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for jobUUID
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getJobUUID()
|
||||
{
|
||||
return jobUUID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIIncludeProperties(ancestorClasses = { TypedResponse.class })
|
||||
@OpenAPIDescription("Response to a status check for a backgrounded job.")
|
||||
public static final class ProcessStepRunning extends TypedResponse
|
||||
{
|
||||
@OpenAPIDescription("Status message regarding the running process step.")
|
||||
private String message;
|
||||
|
||||
@OpenAPIDescription("Optional indicator of progress (e.g., `current` of `total`, as in (`1 of 10`).")
|
||||
private Integer current;
|
||||
|
||||
@OpenAPIDescription("Optional indicator of progress (e.g., `current` of `total`, as in (`1 of 10`).")
|
||||
private Integer total;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for message
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for current
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getCurrent()
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for total
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getTotal()
|
||||
{
|
||||
return total;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIIncludeProperties(ancestorClasses = { TypedResponse.class })
|
||||
@OpenAPIDescription("In case an error is thrown in the backend job.")
|
||||
public static final class ProcessStepError extends TypedResponse
|
||||
{
|
||||
@OpenAPIDescription("Exception message, in case the process step threw an error.")
|
||||
private String error;
|
||||
|
||||
@OpenAPIDescription("Optional user-facing exception message, in case the process step threw a user-facing error.")
|
||||
private String userFacingError;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for error
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getError()
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for userFacingError
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getUserFacingError()
|
||||
{
|
||||
return userFacingError;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setType(Type type)
|
||||
{
|
||||
this.typedResponse = switch(type)
|
||||
{
|
||||
case COMPLETE -> new ProcessStepComplete();
|
||||
case JOB_STARTED -> new ProcessStepJobStarted();
|
||||
case RUNNING -> new ProcessStepRunning();
|
||||
case ERROR -> new ProcessStepError();
|
||||
};
|
||||
|
||||
this.typedResponse.type = type.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setProcessUUID(String processUUID)
|
||||
{
|
||||
this.typedResponse.processUUID = processUUID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setNextStep(String nextStep)
|
||||
{
|
||||
if(this.typedResponse instanceof ProcessStepComplete complete)
|
||||
{
|
||||
complete.nextStep = nextStep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setValues(Map<String, Serializable> values)
|
||||
{
|
||||
if(this.typedResponse instanceof ProcessStepComplete complete)
|
||||
{
|
||||
complete.values = values;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setProcessMetaDataAdjustment(com.kingsrook.qqq.backend.core.model.actions.processes.ProcessMetaDataAdjustment processMetaDataAdjustment)
|
||||
{
|
||||
if(this.typedResponse instanceof ProcessStepComplete complete)
|
||||
{
|
||||
if(processMetaDataAdjustment == null)
|
||||
{
|
||||
complete.processMetaDataAdjustment = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
complete.processMetaDataAdjustment = new ProcessMetaDataAdjustment();
|
||||
|
||||
Map<String, FieldMetaData> updatedFields = processMetaDataAdjustment.getUpdatedFields().entrySet()
|
||||
.stream().collect(Collectors.toMap(e -> e.getKey(), f -> new FieldMetaData(f.getValue())));
|
||||
complete.processMetaDataAdjustment.setUpdatedFields(updatedFields);
|
||||
|
||||
List<FrontendStep> updatedFrontendSteps = processMetaDataAdjustment.getUpdatedFrontendStepList()
|
||||
.stream().map(f -> new FrontendStep(f)).toList();
|
||||
complete.processMetaDataAdjustment.setUpdatedFrontendStepList(updatedFrontendSteps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setJobUUID(String jobUUID)
|
||||
{
|
||||
if(this.typedResponse instanceof ProcessStepJobStarted jobStarted)
|
||||
{
|
||||
jobStarted.jobUUID = jobUUID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setMessage(String message)
|
||||
{
|
||||
if(this.typedResponse instanceof ProcessStepRunning running)
|
||||
{
|
||||
running.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setCurrent(Integer current)
|
||||
{
|
||||
if(this.typedResponse instanceof ProcessStepRunning running)
|
||||
{
|
||||
running.current = current;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setTotal(Integer total)
|
||||
{
|
||||
if(this.typedResponse instanceof ProcessStepRunning running)
|
||||
{
|
||||
running.total = total;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setError(String errorString)
|
||||
{
|
||||
if(this.typedResponse instanceof ProcessStepError error)
|
||||
{
|
||||
error.error = errorString;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setUserFacingError(String userFacingError)
|
||||
{
|
||||
if(this.typedResponse instanceof ProcessStepError error)
|
||||
{
|
||||
error.userFacingError = userFacingError;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Schema toSchema()
|
||||
{
|
||||
return new SchemaBuilder().classToSchema(TypedResponse.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for typedResponse
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TypedResponse getTypedResponse()
|
||||
{
|
||||
return typedResponse;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessMetaDataOutputInterface;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.SchemaBuilder;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.ProcessMetaData;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessMetaDataResponseV1 implements ProcessMetaDataOutputInterface, ToSchema
|
||||
{
|
||||
private ProcessMetaData processMetaData;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void setProcessMetaData(QFrontendProcessMetaData frontendProcessMetaData)
|
||||
{
|
||||
this.processMetaData = new ProcessMetaData(frontendProcessMetaData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Schema toSchema()
|
||||
{
|
||||
return new SchemaBuilder().classToSchema(ProcessMetaData.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for processMetaData
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessMetaData getProcessMetaData()
|
||||
{
|
||||
return processMetaData;
|
||||
}
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendAppMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIMapValueType;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class AppMetaData implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QFrontendAppMetaData wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AppMetaData(QFrontendAppMetaData wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AppMetaData()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Unique name for this app within the QQQ Instance")
|
||||
public String getName()
|
||||
{
|
||||
return (this.wrapped.getName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("User-facing name for this app")
|
||||
public String getLabel()
|
||||
{
|
||||
return (this.wrapped.getLabel());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Name of an icon for the app, from the material UI icon set")
|
||||
public String getIconName()
|
||||
{
|
||||
return (this.wrapped.getIconName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("List of widgets names that are part of this app. These strings should be keys to the widgets map in the QQQ Instance.")
|
||||
@OpenAPIListItems(value = String.class)
|
||||
public List<String> getWidgets()
|
||||
{
|
||||
return (this.wrapped.getWidgets());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("List of other apps, tables, process, and reports, which are contained within this app.")
|
||||
@OpenAPIListItems(value = AppTreeNode.class, useRef = true)
|
||||
public List<AppTreeNode> getChildren()
|
||||
{
|
||||
return (CollectionUtils.nonNullList(this.wrapped.getChildren()).stream().map(a -> new AppTreeNode(a)).toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Map of other apps, tables, process, and reports, which are contained within this app. Same contents as the children list, just structured as a map.")
|
||||
@OpenAPIMapValueType(value = AppTreeNode.class, useRef = true)
|
||||
public Map<String, AppTreeNode> getChildMap()
|
||||
{
|
||||
return (CollectionUtils.nonNullMap(this.wrapped.getChildMap()).entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> new AppTreeNode(e.getValue()))));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("List of sections - sub-divisions of the app, to further organize its children.")
|
||||
@OpenAPIListItems(value = AppSection.class, useRef = true) // todo local type
|
||||
public List<AppSection> getSections()
|
||||
{
|
||||
return (CollectionUtils.nonNullList(this.wrapped.getSections()).stream().map(s -> new AppSection(s)).toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Additional meta-data describing the app, which may not be known to the QQQ backend core module.")
|
||||
public Map<String, Object> getSupplementalAppMetaData()
|
||||
{
|
||||
return (new LinkedHashMap<>(CollectionUtils.nonNullMap(this.wrapped.getSupplementalAppMetaData())));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppSection;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIMapKnownEntries;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class AppSection implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QAppSection wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AppSection(QAppSection wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AppSection()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Unique (within the app) name for this section.")
|
||||
public String getName()
|
||||
{
|
||||
return (this.wrapped.getName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("User-facing name of the section.")
|
||||
public String getLabel()
|
||||
{
|
||||
return (this.wrapped.getLabel());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Icon to display for the section.")
|
||||
@OpenAPIMapKnownEntries(value = Icon.class, useRef = true)
|
||||
public Icon getIcon()
|
||||
{
|
||||
return (this.wrapped.getIcon() == null ? null : new Icon(this.wrapped.getIcon()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("List of table names for the section")
|
||||
@OpenAPIListItems(value = String.class)
|
||||
public List<String> getTables()
|
||||
{
|
||||
return (this.wrapped.getTables());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("List of process names for the section")
|
||||
@OpenAPIListItems(value = String.class)
|
||||
public List<String> getProcesses()
|
||||
{
|
||||
return (this.wrapped.getProcesses());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("List of report names for the section")
|
||||
@OpenAPIListItems(value = String.class)
|
||||
public List<String> getReports()
|
||||
{
|
||||
return (this.wrapped.getReports());
|
||||
}
|
||||
|
||||
}
|
@ -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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class AppTreeNode implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNode wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AppTreeNode(com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNode wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AppTreeNode()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("The type of node (table, process, report, app)")
|
||||
public String getType()
|
||||
{
|
||||
return (this.wrapped.getType() == null ? null : this.wrapped.getType().name());
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Unique (within its type) name for this element. e.g., for type = 'table', the table's name.")
|
||||
public String getName()
|
||||
{
|
||||
return (this.wrapped.getName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("User-facing name of the element.")
|
||||
public String getLabel()
|
||||
{
|
||||
return (this.wrapped.getLabel());
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Child elements. Only applies for type='app', which contains additional apps under it")
|
||||
@OpenAPIListItems(value = AppTreeNode.class, useRef = true)
|
||||
public List<AppTreeNode> getChildren()
|
||||
{
|
||||
return (CollectionUtils.nonNullList(this.wrapped.getChildren()).stream().map(a -> new AppTreeNode(a)).toList());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class FieldMetaData implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QFieldMetaData wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public FieldMetaData(QFieldMetaData wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public FieldMetaData()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Unique name for this field within its container (table or process)")
|
||||
public String getName()
|
||||
{
|
||||
return (this.wrapped.getName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("User-facing name for this field")
|
||||
public String getLabel()
|
||||
{
|
||||
return (this.wrapped.getLabel());
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Data-type for this field") // todo enum
|
||||
public String getType()
|
||||
{
|
||||
return (this.wrapped.getType() == null ? null : this.wrapped.getType().name());
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Indicate if a value in this field is required.")
|
||||
public Boolean getIsRequired()
|
||||
{
|
||||
return (this.wrapped.getIsRequired());
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Indicate if user may edit the value in this field.")
|
||||
public Boolean getIsEditable()
|
||||
{
|
||||
return (this.wrapped.getIsEditable());
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Indicate if this field should be hidden from users")
|
||||
public Boolean getIsHidden()
|
||||
{
|
||||
return (this.wrapped.getIsHidden());
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Indicator of 'heavy' fields, which are not loaded by default. e.g., some blobs or long-texts")
|
||||
public Boolean getIsHeavy()
|
||||
{
|
||||
return (this.wrapped.getIsHeavy());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("C-style format specifier for displaying values in this field.")
|
||||
public String getDisplayFormat()
|
||||
{
|
||||
return (this.wrapped.getDisplayFormat());
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Default value to use in this field.")
|
||||
public String getDefaultValue()
|
||||
{
|
||||
return (this.wrapped.getDefaultValue() == null ? null : String.valueOf(this.wrapped.getDefaultValue()));
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("If this field's values should come from a possible value source, then that PVS is named here.")
|
||||
public String getPossibleValueSourceName()
|
||||
{
|
||||
return (this.wrapped.getPossibleValueSourceName());
|
||||
}
|
||||
|
||||
// todo - PVS filter!!
|
||||
|
||||
// todo - inline PVS
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("For String fields, the max length the field supports.")
|
||||
public Integer getMaxLength()
|
||||
{
|
||||
return (this.wrapped.getMaxLength());
|
||||
}
|
||||
|
||||
// todo behaviors?
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Special UI dressings to add to the field.")
|
||||
@OpenAPIListItems(value = FieldAdornment.class) // todo!
|
||||
public List<FieldAdornment> getAdornments()
|
||||
{
|
||||
return (this.wrapped.getAdornments());
|
||||
}
|
||||
|
||||
// todo help content
|
||||
|
||||
// todo supplemental...
|
||||
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QComponentType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendComponentMetaData;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIMapKnownEntries;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class FrontendComponent implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QFrontendComponentMetaData wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public FrontendComponent(QFrontendComponentMetaData wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public FrontendComponent()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("The type of this component. e.g., what kind of UI element(s) should be presented to the user.")
|
||||
public QComponentType getType()
|
||||
{
|
||||
return (this.wrapped.getType());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
**
|
||||
*******************************************************************************/
|
||||
@OpenAPIDescription("Name-value pairs specific to the type of component.")
|
||||
@OpenAPIMapKnownEntries(value = FrontendComponentValues.class, useRef = true)
|
||||
public Map<String, Serializable> getValues()
|
||||
{
|
||||
return (this.wrapped.getValues() == null ? null : new FrontendComponentValues(this.wrapped.getValues()).toMap());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.AbstractBlockWidgetData;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIHasAdditionalProperties;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@OpenAPIDescription("""
|
||||
These are the known values that can appear in the values map under a FrontendComponent, to control
|
||||
how that component should be presented to the user.
|
||||
|
||||
Note that additional properties may appear as well.
|
||||
|
||||
In addition, components are expected to use values from an active process's `values` map (e.g., as included in
|
||||
a `ProcessStepComplete` object), with the following contract between component-types and expected values:
|
||||
|
||||
- For component type=`HTML`, there will be a process value with key=`${stepName}.html` (e.g., `resultScreen.html`),
|
||||
whose value is the HTML to display on that screen.
|
||||
- For component type=`HELP_TEXT`: There will be a process value with key=`text`, whose value is the text to display on that screen.
|
||||
There may also be a process value with key=`previewText`, which, if present, can be shown before the full text is shown,
|
||||
e.g., with a toggle control to hide/show the `text` value.
|
||||
""")
|
||||
@OpenAPIHasAdditionalProperties()
|
||||
public class FrontendComponentValues implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private Map<String, Serializable> wrapped;
|
||||
|
||||
@OpenAPIDescription("""
|
||||
Components of type=`WIDGET`, which do not reference a widget defined in the QQQ Instance, but instead,
|
||||
are defined as a list of blocks within a frontend step component, will have a this value set to true.""")
|
||||
private Boolean isAdHocWidget;
|
||||
|
||||
@OpenAPIDescription("""
|
||||
Components of type=`WIDGET`, which are set as `isAdHocWidget=true`, should include a list of WidgetBlocks in this value.""")
|
||||
@OpenAPIListItems(value = WidgetBlock.class, useRef = true)
|
||||
private List<WidgetBlock> blocks;
|
||||
|
||||
@OpenAPIDescription("""
|
||||
Components of type=`WIDGET`, which should render a widget defined in the QQQ instance, this value specifies
|
||||
the name of that widget. Contrast with ad-hoc widgets.
|
||||
""")
|
||||
private String widgetName;
|
||||
|
||||
@OpenAPIDescription("""
|
||||
Components of type=`EDIT_FORM` can specify a subset of field names to include. This can be used to break a form up into
|
||||
sections, by including multiple EDIT_FORM components, with different lists of `includeFieldNames`.
|
||||
""")
|
||||
@OpenAPIListItems(String.class)
|
||||
private List<String> includeFieldNames;
|
||||
|
||||
@OpenAPIDescription("""
|
||||
Components of type=`EDIT_FORM` can specify a user-facing text label to show on screen.
|
||||
""")
|
||||
private String sectionLabel;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public FrontendComponentValues(Map<String, Serializable> values)
|
||||
{
|
||||
this.wrapped = values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public FrontendComponentValues()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public Map<String, Serializable> toMap()
|
||||
{
|
||||
if(wrapped == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
Map<String, Serializable> rs = new HashMap<>();
|
||||
for(Map.Entry<String, Serializable> entry : wrapped.entrySet())
|
||||
{
|
||||
String key = entry.getKey();
|
||||
Serializable value = entry.getValue();
|
||||
|
||||
if(key.equals("blocks"))
|
||||
{
|
||||
ArrayList<WidgetBlock> resultList = new ArrayList<>();
|
||||
|
||||
List<AbstractBlockWidgetData<?, ?, ?, ?>> sourceList = (List<AbstractBlockWidgetData<?, ?, ?, ?>>) value;
|
||||
for(AbstractBlockWidgetData<?, ?, ?, ?> abstractBlockWidgetData : sourceList)
|
||||
{
|
||||
resultList.add(new WidgetBlock(abstractBlockWidgetData));
|
||||
}
|
||||
|
||||
value = resultList;
|
||||
}
|
||||
|
||||
rs.put(key, value);
|
||||
}
|
||||
|
||||
return (rs);
|
||||
}
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class FrontendStep implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QFrontendStepMetaData wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public FrontendStep(QFrontendStepMetaData wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public FrontendStep()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("The unique name for this step within its process")
|
||||
public String getName()
|
||||
{
|
||||
return (this.wrapped.getName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("The user-facing name for this step")
|
||||
public String getLabel()
|
||||
{
|
||||
return (this.wrapped.getLabel());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("The components that make up this screen")
|
||||
@OpenAPIListItems(value = FrontendComponent.class, useRef = true)
|
||||
public List<FrontendComponent> getComponents()
|
||||
{
|
||||
return (CollectionUtils.nonNullList(this.wrapped.getComponents()).stream().map(f -> new FrontendComponent(f)).toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Fields used as form fields (inputs) on this step/screen")
|
||||
@OpenAPIListItems(value = FieldMetaData.class, useRef = true)
|
||||
public List<FieldMetaData> getFormFields()
|
||||
{
|
||||
return (CollectionUtils.nonNullList(this.wrapped.getFormFields()).stream().map(f -> new FieldMetaData(f)).toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Fields used as view-only fields on this step/screen")
|
||||
@OpenAPIListItems(value = FieldMetaData.class, useRef = true)
|
||||
public List<FieldMetaData> getViewFields()
|
||||
{
|
||||
return (CollectionUtils.nonNullList(this.wrapped.getViewFields()).stream().map(f -> new FieldMetaData(f)).toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Fields used in record-lists shown on the step/screen.")
|
||||
@OpenAPIListItems(value = FieldMetaData.class, useRef = true)
|
||||
public List<FieldMetaData> getRecordListFields()
|
||||
{
|
||||
return (CollectionUtils.nonNullList(this.wrapped.getRecordListFields()).stream().map(f -> new FieldMetaData(f)).toList());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class Icon implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QIcon wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Icon(QIcon wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Icon()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("A material UI icon name.")
|
||||
public String getName()
|
||||
{
|
||||
return (this.wrapped.getName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("A color code to use for displaying the icon")
|
||||
public String getColor()
|
||||
{
|
||||
return (this.wrapped.getColor());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("A path to an image file that can be requested from the server, to serve as the icon image instead of a material UI icon.")
|
||||
public String getPath()
|
||||
{
|
||||
return (this.wrapped.getPath());
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIIncludeProperties;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIIncludeProperties(ancestorClasses = ProcessMetaDataLight.class)
|
||||
public class ProcessMetaData extends ProcessMetaDataLight implements ToSchema
|
||||
{
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessMetaData(QFrontendProcessMetaData wrapped)
|
||||
{
|
||||
super(wrapped);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessMetaData()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Frontend steps (aka, Screens) for this process.")
|
||||
@OpenAPIListItems(value = FrontendStep.class, useRef = true)
|
||||
public List<FrontendStep> getFrontendSteps()
|
||||
{
|
||||
return (CollectionUtils.nonNullList(this.wrapped.getFrontendSteps()).stream().map(f -> new FrontendStep(f)).toList());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIMapValueType;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessMetaDataAdjustment
|
||||
{
|
||||
@OpenAPIDescription("""
|
||||
In case the backend has changed the list of frontend steps, it will be set in this field.""")
|
||||
@OpenAPIListItems(FrontendStep.class)
|
||||
private List<FrontendStep> updatedFrontendStepList = null;
|
||||
|
||||
@OpenAPIDescription("""
|
||||
Fields whose meta-data has changed. e.g., changing a label, or required status, or inline-possible-values.""")
|
||||
@OpenAPIMapValueType(value = FieldMetaData.class, useRef = true)
|
||||
private Map<String, FieldMetaData> updatedFields = null;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for updatedFrontendStepList
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<FrontendStep> getUpdatedFrontendStepList()
|
||||
{
|
||||
return updatedFrontendStepList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for updatedFrontendStepList
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setUpdatedFrontendStepList(List<FrontendStep> updatedFrontendStepList)
|
||||
{
|
||||
this.updatedFrontendStepList = updatedFrontendStepList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for updatedFrontendStepList
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessMetaDataAdjustment withUpdatedFrontendStepList(List<FrontendStep> updatedFrontendStepList)
|
||||
{
|
||||
this.updatedFrontendStepList = updatedFrontendStepList;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for updatedFields
|
||||
*******************************************************************************/
|
||||
public Map<String, FieldMetaData> getUpdatedFields()
|
||||
{
|
||||
return (this.updatedFields);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for updatedFields
|
||||
*******************************************************************************/
|
||||
public void setUpdatedFields(Map<String, FieldMetaData> updatedFields)
|
||||
{
|
||||
this.updatedFields = updatedFields;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for updatedFields
|
||||
*******************************************************************************/
|
||||
public ProcessMetaDataAdjustment withUpdatedFields(Map<String, FieldMetaData> updatedFields)
|
||||
{
|
||||
this.updatedFields = updatedFields;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class ProcessMetaDataLight implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
protected QFrontendProcessMetaData wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessMetaDataLight(QFrontendProcessMetaData wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ProcessMetaDataLight()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Unique name for this process within the QQQ Instance")
|
||||
public String getName()
|
||||
{
|
||||
return (this.wrapped.getName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("User-facing name for this process")
|
||||
public String getLabel()
|
||||
{
|
||||
return (this.wrapped.getLabel());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("If this process is associated with a table, the table name is given here")
|
||||
public String getTableName()
|
||||
{
|
||||
return (this.wrapped.getTableName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Boolean indicator of whether the process should be shown to users or not")
|
||||
public Boolean getIsHidden()
|
||||
{
|
||||
return (this.wrapped.getIsHidden());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Indicator of the Step Flow used by the process. Possible values are: LINEAR, STATE_MACHINE.")
|
||||
public String getStepFlow()
|
||||
{
|
||||
return (this.wrapped.getStepFlow());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Name of an icon for the process, from the material UI icon set")
|
||||
public String getIconName()
|
||||
{
|
||||
return (this.wrapped.getIconName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Boolean to indicate if the user has permission for the process.")
|
||||
public Boolean getHasPermission()
|
||||
{
|
||||
return (this.wrapped.getHasPermission());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.help.QHelpContent;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public class TableMetaDataLight implements ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private QFrontendTableMetaData wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableMetaDataLight(QFrontendTableMetaData wrapped)
|
||||
{
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TableMetaDataLight()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Unique name for this table within the QQQ Instance")
|
||||
public String getName()
|
||||
{
|
||||
return (this.wrapped.getName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("User-facing name for this table")
|
||||
public String getLabel()
|
||||
{
|
||||
return (this.wrapped.getLabel());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Boolean indicator of whether the table should be shown to users or not")
|
||||
public Boolean getIsHidden()
|
||||
{
|
||||
return (this.wrapped.getIsHidden());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Name of an icon for the table, from the material UI icon set")
|
||||
public String getIconName()
|
||||
{
|
||||
return (this.wrapped.getIconName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("List of strings describing actions that are supported by the backend application for the table.")
|
||||
@OpenAPIListItems(value = String.class) // todo - better, enum
|
||||
public List<String> getCapabilities()
|
||||
{
|
||||
return (new ArrayList<>(this.wrapped.getCapabilities()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Boolean to indicate if the user has read permission for the table.")
|
||||
public Boolean getReadPermission()
|
||||
{
|
||||
return (this.wrapped.getReadPermission());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Boolean to indicate if the user has insert permission for the table.")
|
||||
public Boolean getInsertPermission()
|
||||
{
|
||||
return (this.wrapped.getInsertPermission());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Boolean to indicate if the user has edit permission for the table.")
|
||||
public Boolean getEditPermission()
|
||||
{
|
||||
return (this.wrapped.getEditPermission());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Boolean to indicate if the user has delete permission for the table.")
|
||||
public Boolean getDeletePermission()
|
||||
{
|
||||
return (this.wrapped.getDeletePermission());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("If the table uses variants, this is the user-facing label for the table that supplies variants for this table.")
|
||||
public String getVariantTableLabel()
|
||||
{
|
||||
return (this.wrapped.getVariantTableLabel());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Help Contents for this table.") // todo describe more
|
||||
public Map<String, List<QHelpContent>> getHelpContents()
|
||||
{
|
||||
return (this.wrapped.getHelpContents());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.CompositeWidgetData;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.AbstractBlockWidgetData;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIEnumSubSet;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIListItems;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIOneOf;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class WidgetBlock implements Serializable, ToSchema
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private static final QLogger LOG = QLogger.getLogger(WidgetBlock.class);
|
||||
|
||||
@OpenAPIExclude()
|
||||
private final AbstractBlockWidgetData<?, ?, ?, ?> wrapped;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public WidgetBlock(AbstractBlockWidgetData<?, ?, ?, ?> abstractBlockWidgetData)
|
||||
{
|
||||
this.wrapped = abstractBlockWidgetData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Unique identifier for this block within it widget. Used as a key for helpContents.")
|
||||
public String getBlockId()
|
||||
{
|
||||
return (this.wrapped.getBlockId());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public enum BlockType
|
||||
{
|
||||
ACTION_BUTTON,
|
||||
AUDIO,
|
||||
BIG_NUMBER,
|
||||
COMPOSITE,
|
||||
DIVIDER,
|
||||
IMAGE,
|
||||
INPUT_FIELD,
|
||||
NUMBER_ICON_BADGE,
|
||||
PROGRESS_BAR,
|
||||
// todo? REVEAL,
|
||||
TABLE_SUB_ROW_DETAIL_ROW,
|
||||
TEXT,
|
||||
UP_OR_DOWN_NUMBER
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("What type of block to render.")
|
||||
public BlockType getBlockType()
|
||||
{
|
||||
return (BlockType.valueOf(this.wrapped.getBlockTypeName()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Values to show in the block, or otherwise control its behavior. Different fields based on blockType.")
|
||||
@OpenAPIOneOf()
|
||||
public WidgetBlockValues getValues()
|
||||
{
|
||||
return (WidgetBlockValues.of(this.wrapped.getValues()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Styles to apply to the block. Different fields based on blockType.")
|
||||
@OpenAPIOneOf()
|
||||
public WidgetBlockStyles getStyles()
|
||||
{
|
||||
return (WidgetBlockStyles.of(this.wrapped.getStyles()));
|
||||
}
|
||||
|
||||
// todo link, links
|
||||
|
||||
// todo tooltip, tooltips
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Optional field name (e.g,. from a process's set of fields) to act as a 'guard' for the block - e.g., only include it in the UI if the value for this field is true")
|
||||
public String getConditional()
|
||||
{
|
||||
return (this.wrapped.getConditional());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("For COMPOSITE type blocks, a list of sub-blocks.")
|
||||
@OpenAPIListItems(value = WidgetBlock.class, useRef = true)
|
||||
public List<WidgetBlock> getSubBlocks()
|
||||
{
|
||||
if(this.wrapped instanceof CompositeWidgetData compositeWidgetData)
|
||||
{
|
||||
return (compositeWidgetData.getBlocks() == null ? null : compositeWidgetData.getBlocks().stream().map(b -> new WidgetBlock(b)).toList());
|
||||
}
|
||||
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static class LayoutSubSet implements OpenAPIEnumSubSet.EnumSubSet<CompositeWidgetData.Layout>
|
||||
{
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public EnumSet<CompositeWidgetData.Layout> getSubSet()
|
||||
{
|
||||
return EnumSet.of(
|
||||
CompositeWidgetData.Layout.FLEX_COLUMN,
|
||||
CompositeWidgetData.Layout.FLEX_ROW_WRAPPED,
|
||||
CompositeWidgetData.Layout.FLEX_ROW_SPACE_BETWEEN,
|
||||
CompositeWidgetData.Layout.FLEX_ROW_CENTER,
|
||||
CompositeWidgetData.Layout.TABLE_SUB_ROW_DETAILS,
|
||||
CompositeWidgetData.Layout.BADGES_WRAPPER
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("For COMPOSITE type blocks, an indicator of how the sub-blocks should be laid out")
|
||||
@OpenAPIEnumSubSet(LayoutSubSet.class)
|
||||
public CompositeWidgetData.Layout getLayout()
|
||||
{
|
||||
if(this.wrapped instanceof CompositeWidgetData compositeWidgetData && compositeWidgetData.getLayout() != null)
|
||||
{
|
||||
CompositeWidgetData.Layout layout = compositeWidgetData.getLayout();
|
||||
if(new LayoutSubSet().getSubSet().contains(layout))
|
||||
{
|
||||
return (layout);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.info("Layout [" + layout + "] is not in the subset used by this version. It will not be returned.");
|
||||
}
|
||||
}
|
||||
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
/* todo
|
||||
private Map<String, Serializable> styleOverrides = new HashMap<>();
|
||||
private String overlayHtml;
|
||||
private Map<String, Serializable> overlayStyleOverrides = new HashMap<>();
|
||||
*/
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.actionbutton.ActionButtonValues;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@OpenAPIDescription("Values used for an ACTION_BUTTON type widget block")
|
||||
public final class WidgetBlockActionButtonValues implements WidgetBlockValues
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private ActionButtonValues wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public WidgetBlockActionButtonValues(ActionButtonValues actionButtonValues)
|
||||
{
|
||||
this.wrapped = actionButtonValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public WidgetBlockActionButtonValues()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("User-facing label to display in the button")
|
||||
public String getLabel()
|
||||
{
|
||||
return (this.wrapped.getLabel());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Code used within the app as the value submitted when the button is clicked")
|
||||
public String getActionCode()
|
||||
{
|
||||
return (this.wrapped.getActionCode());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.inputfield.InputFieldValues;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@OpenAPIDescription("Values used for an INPUT_FIELD type widget block")
|
||||
public final class WidgetBlockInputFieldValues implements WidgetBlockValues
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private InputFieldValues wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public WidgetBlockInputFieldValues(InputFieldValues textValues)
|
||||
{
|
||||
this.wrapped = textValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public WidgetBlockInputFieldValues()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Metadata to define the field that this block controls")
|
||||
public FieldMetaData getFieldMetaData()
|
||||
{
|
||||
return (new FieldMetaData(this.wrapped.getFieldMetaData()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Indicate whether this field should auto-focus when it is rendered")
|
||||
public Boolean getAutoFocus()
|
||||
{
|
||||
return (this.wrapped.getAutoFocus());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Indicate whether the form that this field is on should be submitted when Enter is pressed")
|
||||
public Boolean getSubmitOnEnter()
|
||||
{
|
||||
return (this.wrapped.getSubmitOnEnter());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.BlockStylesInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.text.TextStyles;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public sealed interface WidgetBlockStyles extends ToSchema permits
|
||||
WidgetBlockTextStyles
|
||||
{
|
||||
@OpenAPIExclude
|
||||
QLogger LOG = QLogger.getLogger(WidgetBlockStyles.class);
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
static WidgetBlockStyles of(BlockStylesInterface blockStyles)
|
||||
{
|
||||
if(blockStyles == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
if(blockStyles instanceof TextStyles s)
|
||||
{
|
||||
return (new WidgetBlockTextStyles(s));
|
||||
}
|
||||
|
||||
LOG.warn("Unrecognized block value type: " + blockStyles.getClass().getName());
|
||||
return (null);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.text.TextStyles;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public final class WidgetBlockTextStyles implements WidgetBlockStyles
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private TextStyles wrapped;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public WidgetBlockTextStyles(TextStyles textStyles)
|
||||
{
|
||||
this.wrapped = textStyles;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public WidgetBlockTextStyles()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("Indicate if the text should be displayed as an alert (e.g., modal popup)")
|
||||
public Boolean getIsAlert()
|
||||
{
|
||||
return (this.wrapped.getIsAlert());
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("A Standard Color to display the text in (e.g., not a hex or RGB code).")
|
||||
public TextStyles.StandardColor getStandardColor()
|
||||
{
|
||||
return (this.wrapped.getStandardColor());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.text.TextValues;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIDescription;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@OpenAPIDescription("Values used for a TEXT type widget block")
|
||||
public final class WidgetBlockTextValues implements WidgetBlockValues
|
||||
{
|
||||
@OpenAPIExclude()
|
||||
private TextValues wrapped;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public WidgetBlockTextValues(TextValues textValues)
|
||||
{
|
||||
this.wrapped = textValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public WidgetBlockTextValues()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@OpenAPIDescription("The text to display in the block")
|
||||
public String getText()
|
||||
{
|
||||
return (this.wrapped.getText());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.responses.components;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.BlockValuesInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.actionbutton.ActionButtonValues;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.inputfield.InputFieldValues;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks.text.TextValues;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.ToSchema;
|
||||
import com.kingsrook.qqq.middleware.javalin.schemabuilder.annotations.OpenAPIExclude;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public sealed interface WidgetBlockValues extends ToSchema permits
|
||||
WidgetBlockActionButtonValues,
|
||||
WidgetBlockTextValues,
|
||||
WidgetBlockInputFieldValues
|
||||
{
|
||||
@OpenAPIExclude
|
||||
QLogger LOG = QLogger.getLogger(WidgetBlockValues.class);
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
static WidgetBlockValues of(BlockValuesInterface blockValues)
|
||||
{
|
||||
if(blockValues == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
if(blockValues instanceof TextValues v)
|
||||
{
|
||||
return (new WidgetBlockTextValues(v));
|
||||
}
|
||||
else if(blockValues instanceof InputFieldValues v)
|
||||
{
|
||||
return (new WidgetBlockInputFieldValues(v));
|
||||
}
|
||||
else if(blockValues instanceof ActionButtonValues v)
|
||||
{
|
||||
return (new WidgetBlockActionButtonValues(v));
|
||||
}
|
||||
|
||||
LOG.warn("Unrecognized block value type: " + blockValues.getClass().getName());
|
||||
return (null);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.utils;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessMetaDataAdjustment;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.QUploadedFile;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
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.QComponentType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendComponentMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.collections.MapBuilder;
|
||||
import com.kingsrook.qqq.backend.javalin.QJavalinImplementation;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.ProcessInitOrStepOrStatusOutputInterface;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.ProcessInitOrStepOrStatusResponseV1;
|
||||
import com.kingsrook.qqq.openapi.model.Example;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import io.javalin.http.Context;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ProcessSpecUtilsV1
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(ProcessSpecUtilsV1.class);
|
||||
|
||||
public static final String EXAMPLE_PROCESS_UUID = "01234567-89AB-CDEF-0123-456789ABCDEF";
|
||||
public static final String EXAMPLE_JOB_UUID = "98765432-10FE-DCBA-9876-543210FEDCBA";
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static String getResponseSchemaRefName()
|
||||
{
|
||||
return ("ProcessStepResponseV1");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static Schema buildResponseSchema()
|
||||
{
|
||||
return new Schema().withOneOf(List.of(
|
||||
new Schema().withRef("#/components/schemas/ProcessStepComplete"),
|
||||
new Schema().withRef("#/components/schemas/ProcessStepJobStarted"),
|
||||
new Schema().withRef("#/components/schemas/ProcessStepRunning"),
|
||||
new Schema().withRef("#/components/schemas/ProcessStepError")
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static LinkedHashMap<String, Example> buildResponseExample()
|
||||
{
|
||||
ProcessInitOrStepOrStatusResponseV1 completeResponse = new ProcessInitOrStepOrStatusResponseV1();
|
||||
completeResponse.setType(ProcessInitOrStepOrStatusOutputInterface.Type.COMPLETE);
|
||||
completeResponse.setProcessUUID(EXAMPLE_PROCESS_UUID);
|
||||
Map<String, Serializable> values = new LinkedHashMap<>();
|
||||
values.put("totalAge", 32768);
|
||||
values.put("firstLastName", "Aabramson");
|
||||
completeResponse.setValues(values);
|
||||
completeResponse.setNextStep("reviewScreen");
|
||||
|
||||
ProcessInitOrStepOrStatusResponseV1 completeResponseWithMetaDataAdjustment = new ProcessInitOrStepOrStatusResponseV1();
|
||||
completeResponseWithMetaDataAdjustment.setType(ProcessInitOrStepOrStatusOutputInterface.Type.COMPLETE);
|
||||
completeResponseWithMetaDataAdjustment.setProcessUUID(EXAMPLE_PROCESS_UUID);
|
||||
completeResponseWithMetaDataAdjustment.setValues(values);
|
||||
completeResponseWithMetaDataAdjustment.setNextStep("inputScreen");
|
||||
completeResponseWithMetaDataAdjustment.setProcessMetaDataAdjustment(new ProcessMetaDataAdjustment()
|
||||
.withUpdatedField(new QFieldMetaData("someField", QFieldType.STRING).withIsRequired(true))
|
||||
.withUpdatedFrontendStepList(List.of(
|
||||
new QFrontendStepMetaData()
|
||||
.withName("inputScreen")
|
||||
.withComponent(new QFrontendComponentMetaData().withType(QComponentType.EDIT_FORM))
|
||||
.withFormField(new QFieldMetaData("someField", QFieldType.STRING)),
|
||||
new QFrontendStepMetaData()
|
||||
.withName("resultScreen")
|
||||
.withComponent(new QFrontendComponentMetaData().withType(QComponentType.PROCESS_SUMMARY_RESULTS))
|
||||
)));
|
||||
|
||||
ProcessInitOrStepOrStatusResponseV1 jobStartedResponse = new ProcessInitOrStepOrStatusResponseV1();
|
||||
jobStartedResponse.setType(ProcessInitOrStepOrStatusOutputInterface.Type.JOB_STARTED);
|
||||
jobStartedResponse.setProcessUUID(EXAMPLE_PROCESS_UUID);
|
||||
jobStartedResponse.setJobUUID(EXAMPLE_JOB_UUID);
|
||||
|
||||
ProcessInitOrStepOrStatusResponseV1 runningResponse = new ProcessInitOrStepOrStatusResponseV1();
|
||||
runningResponse.setType(ProcessInitOrStepOrStatusOutputInterface.Type.RUNNING);
|
||||
runningResponse.setProcessUUID(EXAMPLE_PROCESS_UUID);
|
||||
runningResponse.setMessage("Processing person records");
|
||||
runningResponse.setCurrent(47);
|
||||
runningResponse.setTotal(1701);
|
||||
|
||||
ProcessInitOrStepOrStatusResponseV1 errorResponse = new ProcessInitOrStepOrStatusResponseV1();
|
||||
errorResponse.setType(ProcessInitOrStepOrStatusOutputInterface.Type.RUNNING);
|
||||
errorResponse.setProcessUUID(EXAMPLE_PROCESS_UUID);
|
||||
errorResponse.setError("Illegal Argument Exception: NaN");
|
||||
errorResponse.setUserFacingError("The process could not be completed due to invalid input.");
|
||||
|
||||
return MapBuilder.of(() -> new LinkedHashMap<String, Example>())
|
||||
.with("COMPLETE", new Example().withValue(completeResponse))
|
||||
.with("COMPLETE with metaDataAdjustment", new Example().withValue(completeResponseWithMetaDataAdjustment))
|
||||
.with("JOB_STARTED", new Example().withValue(jobStartedResponse))
|
||||
.with("RUNNING", new Example().withValue(runningResponse))
|
||||
.with("ERROR", new Example().withValue(errorResponse))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static void handleOutput(Context context, ProcessInitOrStepOrStatusResponseV1 output)
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// normally, we like the JsonUtils behavior of excluding null/empty elements. //
|
||||
// but it turns out we want those in the values sub-map. //
|
||||
// so, go through a loop of object → JSON String → JSONObject → String... //
|
||||
// also - work with the TypedResponse sub-object within this response class //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
ProcessInitOrStepOrStatusResponseV1.TypedResponse typedOutput = output.getTypedResponse();
|
||||
|
||||
String outputJson = JsonUtils.toJson(typedOutput);
|
||||
JSONObject outputJsonObject = new JSONObject(outputJson);
|
||||
|
||||
if(typedOutput instanceof ProcessInitOrStepOrStatusResponseV1.ProcessStepComplete complete)
|
||||
{
|
||||
Map<String, Serializable> values = complete.getValues();
|
||||
if(values != null)
|
||||
{
|
||||
String serializedValues = JsonUtils.toJson(values, mapper ->
|
||||
{
|
||||
mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
|
||||
});
|
||||
|
||||
outputJsonObject.put("values", new JSONObject(serializedValues));
|
||||
}
|
||||
}
|
||||
|
||||
context.result(outputJsonObject.toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void archiveUploadedFile(String processName, QUploadedFile qUploadedFile)
|
||||
{
|
||||
String fileName = QValueFormatter.formatDate(LocalDate.now())
|
||||
+ File.separator + processName
|
||||
+ File.separator + qUploadedFile.getFilename();
|
||||
|
||||
InsertInput insertInput = new InsertInput();
|
||||
insertInput.setTableName(QJavalinImplementation.getJavalinMetaData().getUploadedFileArchiveTableName());
|
||||
insertInput.setRecords(List.of(new QRecord()
|
||||
.withValue("fileName", fileName)
|
||||
.withValue("contents", qUploadedFile.getBytes())
|
||||
));
|
||||
|
||||
new InsertAction().executeAsync(insertInput);
|
||||
}
|
||||
}
|
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.utils;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.middleware.javalin.executors.io.QueryMiddlewareInput;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.collections.MapBuilder;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import com.kingsrook.qqq.openapi.model.Type;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QuerySpecUtils
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static Schema defineQueryJoinsSchema()
|
||||
{
|
||||
Schema queryJoinsSchema = new Schema()
|
||||
.withType(Type.ARRAY)
|
||||
.withItems(new Schema()
|
||||
.withProperties(MapBuilder.of(
|
||||
"joinTable", new Schema()
|
||||
.withType(Type.STRING),
|
||||
"select", new Schema()
|
||||
.withType(Type.BOOLEAN),
|
||||
"type", new Schema()
|
||||
.withType(Type.STRING)
|
||||
.withEnumValues(Arrays.stream(QueryJoin.Type.values()).map(o -> o.name()).toList()),
|
||||
"alias", new Schema()
|
||||
.withType(Type.STRING),
|
||||
"baseTableOrAlias", new Schema()
|
||||
.withType(Type.STRING)
|
||||
))
|
||||
);
|
||||
return queryJoinsSchema;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static Schema defineQQueryFilterSchema()
|
||||
{
|
||||
Schema qQueryFilterSchema = new Schema()
|
||||
.withType(Type.OBJECT)
|
||||
.withExample(List.of(
|
||||
JsonUtils.toJson(new QQueryFilter(new QFilterCriteria("id", QCriteriaOperator.LESS_THAN, 5)))
|
||||
))
|
||||
.withProperties(MapBuilder.of(
|
||||
"criteria", new Schema()
|
||||
.withType(Type.ARRAY)
|
||||
.withItems(new Schema()
|
||||
.withProperties(MapBuilder.of(
|
||||
"fieldName", new Schema()
|
||||
.withType(Type.STRING),
|
||||
"operator", new Schema()
|
||||
.withType(Type.STRING)
|
||||
.withEnumValues(Arrays.stream(QCriteriaOperator.values()).map(o -> o.name()).toList()),
|
||||
"values", new Schema()
|
||||
.withType(Type.ARRAY)
|
||||
.withItems(new Schema().withOneOf(List.of(
|
||||
new Schema().withType(Type.INTEGER),
|
||||
new Schema().withType(Type.STRING)
|
||||
)))
|
||||
))
|
||||
),
|
||||
"orderBys", new Schema()
|
||||
.withType(Type.ARRAY)
|
||||
.withItems(new Schema()
|
||||
.withProperties(MapBuilder.of(
|
||||
"fieldName", new Schema()
|
||||
.withType(Type.STRING),
|
||||
"isAscending", new Schema()
|
||||
.withType(Type.BOOLEAN)))
|
||||
),
|
||||
"booleanOperator", new Schema().withType(Type.STRING).withEnumValues(Arrays.stream(QQueryFilter.BooleanOperator.values()).map(o -> o.name()).toList()),
|
||||
"skip", new Schema().withType(Type.INTEGER),
|
||||
"limit", new Schema().withType(Type.INTEGER)
|
||||
// todo - subfilters??
|
||||
));
|
||||
return qQueryFilterSchema;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static Schema getQueryResponseSchema()
|
||||
{
|
||||
Schema schema = new Schema()
|
||||
.withDescription("Records found by the query. May be empty.")
|
||||
.withType(Type.OBJECT)
|
||||
.withProperties(MapBuilder.of(
|
||||
"records", new Schema()
|
||||
.withType(Type.ARRAY)
|
||||
.withItems(new Schema()
|
||||
.withType(Type.OBJECT)
|
||||
.withProperties(MapBuilder.of(
|
||||
"recordLabel", new Schema().withType(Type.STRING),
|
||||
"tableName", new Schema().withType(Type.STRING),
|
||||
"values", new Schema().withType(Type.OBJECT).withDescription("Keys for each field in the table"),
|
||||
"displayValues", new Schema().withType(Type.OBJECT)
|
||||
))
|
||||
)
|
||||
));
|
||||
return schema;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static QueryMiddlewareInput buildInput(Map<String, String> paramMap) throws IOException
|
||||
{
|
||||
|
||||
QQueryFilter filter = null;
|
||||
String filterParam = paramMap.get("filter");
|
||||
if(StringUtils.hasContent(filterParam))
|
||||
{
|
||||
filter = JsonUtils.toObject(filterParam, QQueryFilter.class);
|
||||
}
|
||||
|
||||
List<QueryJoin> queryJoins = null;
|
||||
String queryJoinsParam = paramMap.get("queryJoins");
|
||||
if(StringUtils.hasContent(queryJoinsParam))
|
||||
{
|
||||
queryJoins = new ArrayList<>();
|
||||
|
||||
JSONArray queryJoinsJSON = new JSONArray(queryJoinsParam);
|
||||
for(int i = 0; i < queryJoinsJSON.length(); i++)
|
||||
{
|
||||
QueryJoin queryJoin = new QueryJoin();
|
||||
queryJoins.add(queryJoin);
|
||||
|
||||
JSONObject jsonObject = queryJoinsJSON.getJSONObject(i);
|
||||
queryJoin.setJoinTable(jsonObject.optString("joinTable"));
|
||||
|
||||
if(jsonObject.has("baseTableOrAlias") && !jsonObject.isNull("baseTableOrAlias"))
|
||||
{
|
||||
queryJoin.setBaseTableOrAlias(jsonObject.optString("baseTableOrAlias"));
|
||||
}
|
||||
|
||||
if(jsonObject.has("alias") && !jsonObject.isNull("alias"))
|
||||
{
|
||||
queryJoin.setAlias(jsonObject.optString("alias"));
|
||||
}
|
||||
|
||||
queryJoin.setSelect(jsonObject.optBoolean("select"));
|
||||
|
||||
if(jsonObject.has("type") && !jsonObject.isNull("type"))
|
||||
{
|
||||
queryJoin.setType(QueryJoin.Type.valueOf(jsonObject.getString("type")));
|
||||
}
|
||||
|
||||
if(jsonObject.has("joinName") && !jsonObject.isNull("joinName"))
|
||||
{
|
||||
queryJoin.setJoinMetaData(QContext.getQInstance().getJoin(jsonObject.getString("joinName")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new QueryMiddlewareInput()
|
||||
.withTable(paramMap.get("table"))
|
||||
.withFilter(filter)
|
||||
.withQueryJoins(queryJoins);
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1.utils;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.TagsInterface;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public enum TagsV1 implements TagsInterface
|
||||
{
|
||||
AUTHENTICATION("Authentication"),
|
||||
GENERAL("General"),
|
||||
QUERY("Query"),
|
||||
INSERT("Insert"),
|
||||
UPDATE("Update"),
|
||||
DELETE("Delete"),
|
||||
PROCESSES("Processes"),
|
||||
REPORTS("Reports"),
|
||||
WIDGETS("Widgets");
|
||||
|
||||
|
||||
private final String text;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
TagsV1(String text)
|
||||
{
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for text
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getText()
|
||||
{
|
||||
return text;
|
||||
}
|
||||
}
|
1614
qqq-middleware-javalin/src/main/resources/openapi/v1/openapi.yaml
Normal file
1614
qqq-middleware-javalin/src/main/resources/openapi/v1/openapi.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,356 @@
|
||||
/*
|
||||
* 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.wip;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import io.javalin.config.Key;
|
||||
import io.javalin.http.Context;
|
||||
import io.javalin.http.HandlerType;
|
||||
import io.javalin.http.HttpStatus;
|
||||
import io.javalin.json.JsonMapper;
|
||||
import io.javalin.plugin.ContextPlugin;
|
||||
import io.javalin.security.RouteRole;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TestContext implements Context
|
||||
{
|
||||
private Map<String, String> queryParams = new LinkedHashMap<>();
|
||||
private Map<String, String> pathParams = new LinkedHashMap<>();
|
||||
private Map<String, String> formParams = new LinkedHashMap<>();
|
||||
|
||||
private InputStream result;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public TestContext()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public TestContext withQueryParam(String key, String value)
|
||||
{
|
||||
queryParams.put(key, value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public TestContext withPathParam(String key, String value)
|
||||
{
|
||||
pathParams.put(key, value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public TestContext withFormParam(String key, String value)
|
||||
{
|
||||
formParams.put(key, value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public String queryParam(String key)
|
||||
{
|
||||
return queryParams.get(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public String formParam(String key)
|
||||
{
|
||||
return formParams.get(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public boolean strictContentTypes()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public HttpServletRequest req()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public HttpServletResponse res()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public HandlerType handlerType()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public String matchedPath()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public String endpointHandlerPath()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public <T> T appData(Key<T> key)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public JsonMapper jsonMapper()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public <T> T with(Class<? extends ContextPlugin<?, T>> aClass)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public String pathParam(String key)
|
||||
{
|
||||
return pathParams.get(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Map<String, String> pathParamMap()
|
||||
{
|
||||
return pathParams;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public ServletOutputStream outputStream()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Context minSizeForCompression(int i)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Context result(InputStream inputStream)
|
||||
{
|
||||
this.result = inputStream;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public InputStream resultInputStream()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void future(Supplier<? extends CompletableFuture<?>> supplier)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void redirect(String s, HttpStatus httpStatus)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public void writeJsonStream(Stream<?> stream)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Context skipRemainingHandlers()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Set<RouteRole> routeRoles()
|
||||
{
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for response
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getResultAsString() throws IOException
|
||||
{
|
||||
byte[] bytes = IOUtils.readFully(result, result.available());
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.wip;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import com.kingsrook.qqq.openapi.model.Type;
|
||||
import org.assertj.core.api.AbstractStringAssert;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class TestUtils
|
||||
{
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static void assertStringVsSchema(String string, Schema schema, String path)
|
||||
{
|
||||
String description = "At path " + path;
|
||||
final AbstractStringAssert<?> assertion = assertThat(string).describedAs(description);
|
||||
|
||||
Type type = Type.valueOf(schema.getType().toUpperCase());
|
||||
switch(type)
|
||||
{
|
||||
case OBJECT ->
|
||||
{
|
||||
assertion.startsWith("{");
|
||||
JSONObject object = new JSONObject(string);
|
||||
|
||||
for(Map.Entry<String, Schema> entry : schema.getProperties().entrySet())
|
||||
{
|
||||
// todo deal with optional
|
||||
Object subObject = object.get(entry.getKey());
|
||||
assertStringVsSchema(subObject.toString(), entry.getValue(), path + "/" + entry.getKey());
|
||||
}
|
||||
}
|
||||
case ARRAY ->
|
||||
{
|
||||
assertion.startsWith("[");
|
||||
JSONArray array = new JSONArray(string);
|
||||
|
||||
for(int i = 0; i < array.length(); i++)
|
||||
{
|
||||
Object subObject = array.get(i);
|
||||
assertStringVsSchema(subObject.toString(), schema.getItems(), path + "[" + i + "]");
|
||||
}
|
||||
}
|
||||
case BOOLEAN ->
|
||||
{
|
||||
assertion.matches("(true|false)");
|
||||
}
|
||||
case INTEGER ->
|
||||
{
|
||||
assertion.matches("-?\\d+");
|
||||
}
|
||||
case NUMBER ->
|
||||
{
|
||||
assertion.matches("-?\\d+(\\.\\d+)?");
|
||||
}
|
||||
case STRING ->
|
||||
{
|
||||
assertion.matches("\".*\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.wip.v1;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.api.wip.TestContext;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for QueryGetSpecV1
|
||||
*******************************************************************************/
|
||||
class QueryGetSpecV1Test
|
||||
{
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Test
|
||||
void testBuildInput() throws Exception
|
||||
{
|
||||
TestContext context = new TestContext()
|
||||
.withPathParam("table", "person")
|
||||
.withQueryParam("filter", "{}");
|
||||
|
||||
// QueryMiddlewareInput queryMiddlewareInput = new QueryGetSpecV1().buildInput(context);
|
||||
// assertEquals("person", queryMiddlewareInput.getTable());
|
||||
// assertNotNull(queryMiddlewareInput.getFilter());
|
||||
// assertEquals(0, queryMiddlewareInput.getFilter().getCriteria().size());
|
||||
// assertEquals(0, queryMiddlewareInput.getFilter().getOrderBys().size());
|
||||
// assertNull(queryMiddlewareInput.getQueryJoins());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Test
|
||||
void testBuildOutput() throws Exception
|
||||
{
|
||||
TestContext context = new TestContext();
|
||||
QueryOutput queryOutput = new QueryOutput(new QueryInput());
|
||||
queryOutput.addRecord(new QRecord().withValue("firstName", "Darin").withDisplayValue("firstName", "Darin"));
|
||||
|
||||
// QueryGetSpecV1 queryGetSpecV1 = new QueryGetSpecV1();
|
||||
// queryGetSpecV1.buildOutput(context, new QueryMiddlewareOutput(queryOutput));
|
||||
// String resultJson = context.getResultAsString();
|
||||
// TestUtils.assertResultJsonVsSpec(queryGetSpecV1.defineSimpleSuccessResponse(), resultJson);
|
||||
}
|
||||
|
||||
}
|
@ -57,6 +57,7 @@ class QJavalinProcessHandlerTest extends QJavalinTestBase
|
||||
/*******************************************************************************
|
||||
** test running a process
|
||||
**
|
||||
** Note: ported to v1
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void test_processGreetInit()
|
||||
@ -73,6 +74,7 @@ class QJavalinProcessHandlerTest extends QJavalinTestBase
|
||||
/*******************************************************************************
|
||||
** test running a process that requires rows, but we didn't tell it how to get them.
|
||||
**
|
||||
** Note: ported to v1
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void test_processRequiresRowsButNotSpecified()
|
||||
@ -90,6 +92,7 @@ class QJavalinProcessHandlerTest extends QJavalinTestBase
|
||||
/*******************************************************************************
|
||||
** test running a process and telling it rows to load via recordIds param
|
||||
**
|
||||
** Note: ported to v1
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void test_processRequiresRowsWithRecordIdParam()
|
||||
@ -108,6 +111,7 @@ class QJavalinProcessHandlerTest extends QJavalinTestBase
|
||||
/*******************************************************************************
|
||||
** test running a process and telling it rows to load via filter JSON
|
||||
**
|
||||
** Note: ported to v1
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void test_processRequiresRowsWithFilterJSON()
|
||||
@ -169,6 +173,7 @@ class QJavalinProcessHandlerTest extends QJavalinTestBase
|
||||
/*******************************************************************************
|
||||
** test running a process with field values on the query string
|
||||
**
|
||||
** Note: ported to v1
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void test_processGreetInitWithQueryValues()
|
||||
@ -185,6 +190,7 @@ class QJavalinProcessHandlerTest extends QJavalinTestBase
|
||||
/*******************************************************************************
|
||||
** test init'ing a process that goes async
|
||||
**
|
||||
** Note: ported to v1, but needs todo more - the status part too in a higher-level
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void test_processInitGoingAsync() throws InterruptedException
|
||||
@ -221,6 +227,7 @@ class QJavalinProcessHandlerTest extends QJavalinTestBase
|
||||
/*******************************************************************************
|
||||
** test init'ing a process that does NOT goes async
|
||||
**
|
||||
** Note: not ported to v1, but feels redundant, so, not going to.
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void test_processInitNotGoingAsync()
|
||||
|
@ -24,11 +24,17 @@ package com.kingsrook.qqq.backend.javalin;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import io.javalin.config.Key;
|
||||
import io.javalin.http.Context;
|
||||
import io.javalin.http.HandlerType;
|
||||
import io.javalin.http.HttpStatus;
|
||||
import io.javalin.json.JsonMapper;
|
||||
import io.javalin.plugin.ContextPlugin;
|
||||
import io.javalin.security.RouteRole;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@ -133,6 +139,14 @@ class QJavalinUtilsTest
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean strictContentTypes()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@ -157,17 +171,6 @@ class QJavalinUtilsTest
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public <T> T appAttribute(@NotNull String s)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@ -204,6 +207,30 @@ class QJavalinUtilsTest
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T appData(@NotNull Key<T> key)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull JsonMapper jsonMapper()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T with(@NotNull Class<? extends ContextPlugin<?, T>> aClass)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@ -240,6 +267,14 @@ class QJavalinUtilsTest
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull Context minSizeForCompression(int i)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@ -283,5 +318,29 @@ class QJavalinUtilsTest
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void writeJsonStream(@NotNull Stream<?> stream)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull Context skipRemainingHandlers()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull Set<RouteRole> routeRoles()
|
||||
{
|
||||
return Set.of();
|
||||
}
|
||||
}
|
||||
}
|
@ -62,6 +62,10 @@ import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.permissions.PermissionLevel;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.permissions.QPermissionRules;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PVSValueFormatAndFields;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSourceType;
|
||||
@ -189,11 +193,35 @@ public class TestUtils
|
||||
throw new IllegalStateException("Error adding script tables to instance");
|
||||
}
|
||||
|
||||
defineApps(qInstance);
|
||||
|
||||
return (qInstance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void defineApps(QInstance qInstance)
|
||||
{
|
||||
QAppMetaData childApp = new QAppMetaData()
|
||||
.withName("childApp")
|
||||
.withLabel("Child App")
|
||||
.withIcon(new QIcon().withName("child_friendly"))
|
||||
.withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED))
|
||||
.withChild(qInstance.getProcess(PROCESS_NAME_GREET_PEOPLE_INTERACTIVE));
|
||||
qInstance.addApp(childApp);
|
||||
|
||||
QAppMetaData exampleApp = new QAppMetaData()
|
||||
.withName("homeApp")
|
||||
.withLabel("Home App")
|
||||
.withIcon(new QIcon().withName("home"))
|
||||
.withPermissionRules(new QPermissionRules().withLevel(PermissionLevel.NOT_PROTECTED))
|
||||
.withChild(childApp)
|
||||
.withChild(qInstance.getTable(TABLE_NAME_PERSON));
|
||||
qInstance.addApp(exampleApp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -690,7 +718,7 @@ public class TestUtils
|
||||
{
|
||||
return (new RenderWidgetOutput(new RawHTML("title",
|
||||
QContext.getQSession().getValue(QSession.VALUE_KEY_USER_TIMEZONE_OFFSET_MINUTES)
|
||||
+ "|" + QContext.getQSession().getValue(QSession.VALUE_KEY_USER_TIMEZONE)
|
||||
+ "|" + QContext.getQSession().getValue(QSession.VALUE_KEY_USER_TIMEZONE)
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.middleware.javalin.schemabuilder;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.AuthenticationMetaDataResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.MetaDataResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.ProcessInitOrStepOrStatusResponseV1;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.v1.responses.components.AppTreeNode;
|
||||
import com.kingsrook.qqq.openapi.model.Schema;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for SchemaBuilder
|
||||
*******************************************************************************/
|
||||
class SchemaBuilderTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testIncludesAOneOf()
|
||||
{
|
||||
Schema schema = new SchemaBuilder().classToSchema(AuthenticationMetaDataResponseV1.class);
|
||||
System.out.println(schema);
|
||||
|
||||
Schema valuesSchema = schema.getProperties().get("values");
|
||||
List<Schema> oneOf = valuesSchema.getOneOf();
|
||||
assertEquals(2, oneOf.size());
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testUsesIncludeProperties()
|
||||
{
|
||||
Schema schema = new SchemaBuilder().classToSchema(ProcessInitOrStepOrStatusResponseV1.TypedResponse.class);
|
||||
for(Schema oneOf : schema.getOneOf())
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// all of the wrapped one-of schemas should contain these fields from the parent class //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
assertTrue(oneOf.getProperties().containsKey("type"));
|
||||
assertTrue(oneOf.getProperties().containsKey("processUUID"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testDescriptionOnGetters()
|
||||
{
|
||||
Schema schema = new SchemaBuilder().classToSchema(MetaDataResponseV1.class);
|
||||
assertTrue(schema.getProperties().containsKey("apps"));
|
||||
assertNotNull(schema.getProperties().get("apps").getDescription());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testRecursive()
|
||||
{
|
||||
Schema schema = new SchemaBuilder().classToSchema(AppTreeNode.class);
|
||||
Schema childrenSchema = schema.getProperties().get("children");
|
||||
assertNotNull(childrenSchema.getItems());
|
||||
System.out.println(schema);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore;
|
||||
import com.kingsrook.qqq.backend.javalin.TestUtils;
|
||||
import io.javalin.Javalin;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public abstract class SpecTestBase
|
||||
{
|
||||
private static int PORT = 6263;
|
||||
|
||||
protected static Javalin service;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
protected abstract AbstractEndpointSpec<?, ?, ?> getSpec();
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
protected abstract String getVersion();
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
protected String getBaseUrlAndPath()
|
||||
{
|
||||
return "http://localhost:" + PORT + "/qqq/" + getVersion();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@BeforeEach
|
||||
@AfterEach
|
||||
void beforeAndAfterEach()
|
||||
{
|
||||
MemoryRecordStore.fullReset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// during initial dev here, we were having issues running multiple tests together, //
|
||||
// where the second (but not first, and not any after second) would fail w/ javalin //
|
||||
// not responding... so, this "works" - to constantly change our port, and stop //
|
||||
// and restart aggresively... could be optimized, but it works. //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
PORT++;
|
||||
if(service != null)
|
||||
{
|
||||
service.stop();
|
||||
service = null;
|
||||
}
|
||||
|
||||
if(service == null)
|
||||
{
|
||||
service = Javalin.create(config ->
|
||||
{
|
||||
config.router.apiBuilder(() -> getSpec().defineRoute(getVersion()));
|
||||
}
|
||||
).start(PORT);
|
||||
}
|
||||
|
||||
TestUtils.primeTestDatabase();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@AfterAll
|
||||
static void afterAll()
|
||||
{
|
||||
if(service != null)
|
||||
{
|
||||
service.stop();
|
||||
service = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.SpecTestBase;
|
||||
import kong.unirest.HttpResponse;
|
||||
import kong.unirest.Unirest;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for AuthenticationMetaDataSpecV1
|
||||
*******************************************************************************/
|
||||
class AuthenticationMetaDataSpecV1Test extends SpecTestBase
|
||||
{
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected AbstractEndpointSpec<?, ?, ?> getSpec()
|
||||
{
|
||||
return new AuthenticationMetaDataSpecV1();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected String getVersion()
|
||||
{
|
||||
return "v1";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.get(getBaseUrlAndPath() + "/metaData/authentication").asString();
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertNotNull(jsonObject);
|
||||
assertTrue(jsonObject.has("name"));
|
||||
assertTrue(jsonObject.has("type"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.SpecTestBase;
|
||||
import kong.unirest.HttpResponse;
|
||||
import kong.unirest.Unirest;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for ManageSessionV1
|
||||
*******************************************************************************/
|
||||
class ManageSessionSpecV1Test extends SpecTestBase
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected AbstractEndpointSpec<?, ?, ?> getSpec()
|
||||
{
|
||||
return new ManageSessionSpecV1();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected String getVersion()
|
||||
{
|
||||
return "v1";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test()
|
||||
{
|
||||
String body = """
|
||||
{
|
||||
"accessToken": "abcdefg"
|
||||
}
|
||||
""";
|
||||
|
||||
HttpResponse<String> response = Unirest.post(getBaseUrlAndPath() + "/manageSession")
|
||||
.header("Content-Type", "application/json")
|
||||
.body(body)
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertNotNull(jsonObject);
|
||||
assertTrue(jsonObject.has("uuid"));
|
||||
assertThat(response.getHeaders().get("Set-Cookie")).anyMatch(s -> s.contains("sessionUUID"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.SpecTestBase;
|
||||
import kong.unirest.HttpResponse;
|
||||
import kong.unirest.Unirest;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for MetaDataSpecV1
|
||||
*******************************************************************************/
|
||||
class MetaDataSpecV1Test extends SpecTestBase
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected AbstractEndpointSpec<?, ?, ?> getSpec()
|
||||
{
|
||||
return new MetaDataSpecV1();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected String getVersion()
|
||||
{
|
||||
return "v1";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.get(getBaseUrlAndPath() + "/metaData").asString();
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertThat(jsonObject.getJSONObject("tables").length()).isGreaterThanOrEqualTo(1);
|
||||
assertThat(jsonObject.getJSONObject("processes").length()).isGreaterThanOrEqualTo(1);
|
||||
assertThat(jsonObject.getJSONObject("apps").length()).isGreaterThanOrEqualTo(1);
|
||||
assertThat(jsonObject.getJSONArray("appTree").length()).isGreaterThanOrEqualTo(1);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.logging.QCollectingLogger;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.javalin.TestUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.SpecTestBase;
|
||||
import kong.unirest.HttpResponse;
|
||||
import kong.unirest.Unirest;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for ProcessInitSpecV1
|
||||
*******************************************************************************/
|
||||
class ProcessInitSpecV1Test extends SpecTestBase
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected AbstractEndpointSpec<?, ?, ?> getSpec()
|
||||
{
|
||||
return new ProcessInitSpecV1();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected String getVersion()
|
||||
{
|
||||
return "v1";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@AfterEach
|
||||
void afterEach()
|
||||
{
|
||||
QLogger.deactivateCollectingLoggerForClass(MockBackendStep.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testGetInitialRecordsFromRecordIdsParam()
|
||||
{
|
||||
QCollectingLogger collectingLogger = QLogger.activateCollectingLoggerForClass(MockBackendStep.class);
|
||||
|
||||
HttpResponse<String> response = Unirest.post(getBaseUrlAndPath() + "/processes/greet/init")
|
||||
.multiPartContent()
|
||||
.field("recordsParam", "recordIds")
|
||||
.field("recordIds", "2,3")
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertNotNull(jsonObject);
|
||||
assertEquals("COMPLETE", jsonObject.getString("type"));
|
||||
assertEquals("null X null", jsonObject.getJSONObject("values").getString("outputMessage")); // these nulls are because we didn't pass values for some fields.
|
||||
|
||||
assertThat(collectingLogger.getCollectedMessages())
|
||||
.filteredOn(clm -> clm.getMessage().contains("We are mocking"))
|
||||
.hasSize(2);
|
||||
// todo - also request records
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testGetInitialRecordsFromFilterParam()
|
||||
{
|
||||
QCollectingLogger collectingLogger = QLogger.activateCollectingLoggerForClass(MockBackendStep.class);
|
||||
|
||||
QQueryFilter queryFilter = new QQueryFilter()
|
||||
.withCriteria(new QFilterCriteria()
|
||||
.withFieldName("id")
|
||||
.withOperator(QCriteriaOperator.IN)
|
||||
.withValues(List.of(3, 4, 5)));
|
||||
String filterJSON = JsonUtils.toJson(queryFilter);
|
||||
|
||||
HttpResponse<String> response = Unirest.post(getBaseUrlAndPath() + "/processes/greet/init")
|
||||
.multiPartContent()
|
||||
.field("recordsParam", "filterJSON")
|
||||
.field("filterJSON", filterJSON)
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertNotNull(jsonObject);
|
||||
assertEquals("COMPLETE", jsonObject.getString("type"));
|
||||
assertEquals("null X null", jsonObject.getJSONObject("values").getString("outputMessage"));
|
||||
|
||||
assertThat(collectingLogger.getCollectedMessages())
|
||||
.filteredOn(clm -> clm.getMessage().contains("We are mocking"))
|
||||
.hasSize(3);
|
||||
// todo - also request records
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testRequiresRowsButNotSpecified()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.post(getBaseUrlAndPath() + "/processes/greet/init")
|
||||
.multiPartContent()
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertNotNull(jsonObject);
|
||||
assertEquals("ERROR", jsonObject.getString("type"));
|
||||
assertTrue(jsonObject.has("error"));
|
||||
assertTrue(jsonObject.getString("error").contains("Missing input records"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testFieldValues()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.post(getBaseUrlAndPath() + "/processes/greet/init")
|
||||
.multiPartContent()
|
||||
.field("recordsParam", "recordIds")
|
||||
.field("recordIds", "2,3")
|
||||
.field("values", new JSONObject()
|
||||
.put("greetingPrefix", "Hey")
|
||||
.put("greetingSuffix", "Jude")
|
||||
.toString()
|
||||
)
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertNotNull(jsonObject);
|
||||
assertEquals("COMPLETE", jsonObject.getString("type"));
|
||||
assertEquals("Hey X Jude", jsonObject.getJSONObject("values").getString("outputMessage"));
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testInitGoingAsync()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.post(getBaseUrlAndPath() + "/processes/" + TestUtils.PROCESS_NAME_SIMPLE_SLEEP + "/init")
|
||||
.multiPartContent()
|
||||
.field("stepTimeoutMillis", "50")
|
||||
.field("values", new JSONObject()
|
||||
.put(TestUtils.SleeperStep.FIELD_SLEEP_MILLIS, 500)
|
||||
.toString()
|
||||
)
|
||||
.asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
String processUUID = jsonObject.getString("processUUID");
|
||||
String jobUUID = jsonObject.getString("jobUUID");
|
||||
assertNotNull(processUUID, "Process UUID should not be null.");
|
||||
assertNotNull(jobUUID, "Job UUID should not be null");
|
||||
|
||||
// todo - in a higher-level test, resume test_processInitGoingAsync at the // request job status before sleep is done // line
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.middleware.javalin.specs.v1;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.AbstractEndpointSpec;
|
||||
import com.kingsrook.qqq.middleware.javalin.specs.SpecTestBase;
|
||||
import kong.unirest.HttpResponse;
|
||||
import kong.unirest.Unirest;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for ProcessMetaDataSpecV1
|
||||
*******************************************************************************/
|
||||
class ProcessMetaDataSpecV1Test extends SpecTestBase
|
||||
{
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected AbstractEndpointSpec<?, ?, ?> getSpec()
|
||||
{
|
||||
return new ProcessMetaDataSpecV1();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
protected String getVersion()
|
||||
{
|
||||
return "v1";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.get(getBaseUrlAndPath() + "/metaData/process/greetInteractive").asString();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals("greetInteractive", jsonObject.getString("name"));
|
||||
assertEquals("Greet Interactive", jsonObject.getString("label"));
|
||||
assertEquals("person", jsonObject.getString("tableName"));
|
||||
|
||||
JSONArray frontendSteps = jsonObject.getJSONArray("frontendSteps");
|
||||
JSONObject setupStep = frontendSteps.getJSONObject(0);
|
||||
assertEquals("Setup", setupStep.getString("label"));
|
||||
JSONArray setupFields = setupStep.getJSONArray("formFields");
|
||||
assertEquals(2, setupFields.length());
|
||||
assertTrue(setupFields.toList().stream().anyMatch(field -> "greetingPrefix".equals(((Map<?, ?>) field).get("name"))));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** test the process-level meta-data endpoint for a non-real name
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void testNotFound()
|
||||
{
|
||||
HttpResponse<String> response = Unirest.get(getBaseUrlAndPath() + "/metaData/process/notAnActualProcess").asString();
|
||||
|
||||
assertEquals(HttpStatus.NOT_FOUND_404, response.getStatus());
|
||||
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||
assertEquals(1, jsonObject.keySet().size(), "Number of top-level keys");
|
||||
String error = jsonObject.getString("error");
|
||||
assertThat(error).contains("Process").contains("notAnActualProcess").contains("not found");
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user