diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java index 5b65f4c1..e18cb182 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java @@ -1224,11 +1224,10 @@ public class QInstanceValidator QScheduleMetaData schedule = process.getSchedule(); assertCondition(schedule.getRepeatMillis() != null || schedule.getRepeatSeconds() != null, "Either repeat millis or repeat seconds must be set on schedule in process " + processName); - if(schedule.getBackendVariant() != null) + if(schedule.getVariantBackend() != null) { - assertCondition(schedule.getVariantRunStrategy() != null, "A variant strategy was not set for " + schedule.getBackendVariant() + " on schedule in process " + processName); - assertCondition(schedule.getVariantTableName() != null, "A variant table name was not set for " + schedule.getBackendVariant() + " on schedule in process " + processName); - assertCondition(schedule.getVariantFieldName() != null, "A variant field name was not set for " + schedule.getBackendVariant() + " on schedule in process " + processName); + assertCondition(qInstance.getBackend(schedule.getVariantBackend()) != null, "A variant backend was not found for " + schedule.getVariantBackend()); + assertCondition(schedule.getVariantRunStrategy() != null, "A variant run strategy was not set for " + schedule.getVariantBackend() + " on schedule in process " + processName); } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QBackendMetaData.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QBackendMetaData.java index ef534824..e6cc7ece 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QBackendMetaData.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QBackendMetaData.java @@ -43,12 +43,19 @@ public class QBackendMetaData private String name; private String backendType; - private Boolean usesVariants = false; - private String variantOptionsTableName; - private Set enabledCapabilities = new HashSet<>(); private Set disabledCapabilities = new HashSet<>(); + private Boolean usesVariants = false; + private String variantOptionsTableIdField; + private String variantOptionsTableNameField; + private String variantOptionsTableTypeField; + private String variantOptionsTableTypeValue; + private String variantOptionsTableUsernameField; + private String variantOptionsTablePasswordField; + private String variantOptionsTableApiKeyField; + private String variantOptionsTableName; + // todo - at some point, we may want to apply this to secret properties on subclasses? // @JsonFilter("secretsFilter") @@ -381,7 +388,224 @@ public class QBackendMetaData /******************************************************************************* - ** Getter for variantsOptionTableName + ** Getter for variantOptionsTableIdField + *******************************************************************************/ + public String getVariantOptionsTableIdField() + { + return (this.variantOptionsTableIdField); + } + + + + /******************************************************************************* + ** Setter for variantOptionsTableIdField + *******************************************************************************/ + public void setVariantOptionsTableIdField(String variantOptionsTableIdField) + { + this.variantOptionsTableIdField = variantOptionsTableIdField; + } + + + + /******************************************************************************* + ** Fluent setter for variantOptionsTableIdField + *******************************************************************************/ + public QBackendMetaData withVariantOptionsTableIdField(String variantOptionsTableIdField) + { + this.variantOptionsTableIdField = variantOptionsTableIdField; + return (this); + } + + + + /******************************************************************************* + ** Getter for variantOptionsTableNameField + *******************************************************************************/ + public String getVariantOptionsTableNameField() + { + return (this.variantOptionsTableNameField); + } + + + + /******************************************************************************* + ** Setter for variantOptionsTableNameField + *******************************************************************************/ + public void setVariantOptionsTableNameField(String variantOptionsTableNameField) + { + this.variantOptionsTableNameField = variantOptionsTableNameField; + } + + + + /******************************************************************************* + ** Fluent setter for variantOptionsTableNameField + *******************************************************************************/ + public QBackendMetaData withVariantOptionsTableNameField(String variantOptionsTableNameField) + { + this.variantOptionsTableNameField = variantOptionsTableNameField; + return (this); + } + + + + /******************************************************************************* + ** Getter for variantOptionsTableTypeField + *******************************************************************************/ + public String getVariantOptionsTableTypeField() + { + return (this.variantOptionsTableTypeField); + } + + + + /******************************************************************************* + ** Setter for variantOptionsTableTypeField + *******************************************************************************/ + public void setVariantOptionsTableTypeField(String variantOptionsTableTypeField) + { + this.variantOptionsTableTypeField = variantOptionsTableTypeField; + } + + + + /******************************************************************************* + ** Fluent setter for variantOptionsTableTypeField + *******************************************************************************/ + public QBackendMetaData withVariantOptionsTableTypeField(String variantOptionsTableTypeField) + { + this.variantOptionsTableTypeField = variantOptionsTableTypeField; + return (this); + } + + + + /******************************************************************************* + ** Getter for variantOptionsTableTypeValue + *******************************************************************************/ + public String getVariantOptionsTableTypeValue() + { + return (this.variantOptionsTableTypeValue); + } + + + + /******************************************************************************* + ** Setter for variantOptionsTableTypeValue + *******************************************************************************/ + public void setVariantOptionsTableTypeValue(String variantOptionsTableTypeValue) + { + this.variantOptionsTableTypeValue = variantOptionsTableTypeValue; + } + + + + /******************************************************************************* + ** Fluent setter for variantOptionsTableTypeValue + *******************************************************************************/ + public QBackendMetaData withVariantOptionsTableTypeValue(String variantOptionsTableTypeValue) + { + this.variantOptionsTableTypeValue = variantOptionsTableTypeValue; + return (this); + } + + + + /******************************************************************************* + ** Getter for variantOptionsTableUsernameField + *******************************************************************************/ + public String getVariantOptionsTableUsernameField() + { + return (this.variantOptionsTableUsernameField); + } + + + + /******************************************************************************* + ** Setter for variantOptionsTableUsernameField + *******************************************************************************/ + public void setVariantOptionsTableUsernameField(String variantOptionsTableUsernameField) + { + this.variantOptionsTableUsernameField = variantOptionsTableUsernameField; + } + + + + /******************************************************************************* + ** Fluent setter for variantOptionsTableUsernameField + *******************************************************************************/ + public QBackendMetaData withVariantOptionsTableUsernameField(String variantOptionsTableUsernameField) + { + this.variantOptionsTableUsernameField = variantOptionsTableUsernameField; + return (this); + } + + + + /******************************************************************************* + ** Getter for variantOptionsTablePasswordField + *******************************************************************************/ + public String getVariantOptionsTablePasswordField() + { + return (this.variantOptionsTablePasswordField); + } + + + + /******************************************************************************* + ** Setter for variantOptionsTablePasswordField + *******************************************************************************/ + public void setVariantOptionsTablePasswordField(String variantOptionsTablePasswordField) + { + this.variantOptionsTablePasswordField = variantOptionsTablePasswordField; + } + + + + /******************************************************************************* + ** Fluent setter for variantOptionsTablePasswordField + *******************************************************************************/ + public QBackendMetaData withVariantOptionsTablePasswordField(String variantOptionsTablePasswordField) + { + this.variantOptionsTablePasswordField = variantOptionsTablePasswordField; + return (this); + } + + + + /******************************************************************************* + ** Getter for variantOptionsTableApiKeyField + *******************************************************************************/ + public String getVariantOptionsTableApiKeyField() + { + return (this.variantOptionsTableApiKeyField); + } + + + + /******************************************************************************* + ** Setter for variantOptionsTableApiKeyField + *******************************************************************************/ + public void setVariantOptionsTableApiKeyField(String variantOptionsTableApiKeyField) + { + this.variantOptionsTableApiKeyField = variantOptionsTableApiKeyField; + } + + + + /******************************************************************************* + ** Fluent setter for variantOptionsTableApiKeyField + *******************************************************************************/ + public QBackendMetaData withVariantOptionsTableApiKeyField(String variantOptionsTableApiKeyField) + { + this.variantOptionsTableApiKeyField = variantOptionsTableApiKeyField; + return (this); + } + + + + /******************************************************************************* + ** Getter for variantOptionsTableName *******************************************************************************/ public String getVariantOptionsTableName() { @@ -391,7 +615,7 @@ public class QBackendMetaData /******************************************************************************* - ** Setter for variantsOptionTableName + ** Setter for variantOptionsTableName *******************************************************************************/ public void setVariantOptionsTableName(String variantOptionsTableName) { @@ -401,11 +625,11 @@ public class QBackendMetaData /******************************************************************************* - ** Fluent setter for variantsOptionTableName + ** Fluent setter for variantOptionsTableName *******************************************************************************/ - public QBackendMetaData withVariantsOptionTableName(String variantsOptionTableName) + public QBackendMetaData withVariantOptionsTableName(String variantOptionsTableName) { - this.variantOptionsTableName = variantsOptionTableName; + this.variantOptionsTableName = variantOptionsTableName; return (this); } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendTableMetaData.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendTableMetaData.java index e524a970..afd031b2 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendTableMetaData.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendTableMetaData.java @@ -72,6 +72,9 @@ public class QFrontendTableMetaData private boolean editPermission; private boolean deletePermission; + private boolean usesVariants; + private String variantTableLabel; + ////////////////////////////////////////////////////////////////////////////////// // do not add setters. take values from the source-object in the constructor!! // ////////////////////////////////////////////////////////////////////////////////// @@ -135,6 +138,13 @@ public class QFrontendTableMetaData insertPermission = PermissionsHelper.hasTablePermission(actionInput, tableMetaData.getName(), TablePermissionSubType.INSERT); editPermission = PermissionsHelper.hasTablePermission(actionInput, tableMetaData.getName(), TablePermissionSubType.EDIT); deletePermission = PermissionsHelper.hasTablePermission(actionInput, tableMetaData.getName(), TablePermissionSubType.DELETE); + + QBackendMetaData backend = actionInput.getInstance().getBackend(tableMetaData.getBackendName()); + if(backend != null && backend.getUsesVariants()) + { + usesVariants = true; + variantTableLabel = actionInput.getInstance().getTable(backend.getVariantOptionsTableName()).getLabel(); + } } @@ -294,6 +304,17 @@ public class QFrontendTableMetaData + /******************************************************************************* + ** Getter for usesVariants + ** + *******************************************************************************/ + public boolean getUsesVariants() + { + return usesVariants; + } + + + /******************************************************************************* ** Getter for exposedJoins ** @@ -302,4 +323,15 @@ public class QFrontendTableMetaData { return exposedJoins; } + + + + /******************************************************************************* + ** Getter for variantTableLabel + *******************************************************************************/ + public String getVariantTableLabel() + { + return (this.variantTableLabel); + } + } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendVariant.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendVariant.java new file mode 100644 index 00000000..7e63c9eb --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendVariant.java @@ -0,0 +1,130 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. 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 . + */ + +package com.kingsrook.qqq.backend.core.model.metadata.frontend; + + +import java.io.Serializable; + + +/******************************************************************************* + ** Version of a variant for a frontend to see + *******************************************************************************/ +public class QFrontendVariant +{ + private Serializable id; + private String name; + private String type; + + + + /******************************************************************************* + ** Getter for id + *******************************************************************************/ + public Serializable getId() + { + return (this.id); + } + + + + /******************************************************************************* + ** Setter for id + *******************************************************************************/ + public void setId(Serializable id) + { + this.id = id; + } + + + + /******************************************************************************* + ** Fluent setter for id + *******************************************************************************/ + public QFrontendVariant withId(Serializable id) + { + this.id = id; + 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 QFrontendVariant withName(String name) + { + this.name = name; + return (this); + } + + + + /******************************************************************************* + ** 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 QFrontendVariant withType(String type) + { + this.type = type; + return (this); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/scheduleing/QScheduleMetaData.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/scheduleing/QScheduleMetaData.java index 03a66de1..ece9019a 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/scheduleing/QScheduleMetaData.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/scheduleing/QScheduleMetaData.java @@ -22,9 +22,6 @@ package com.kingsrook.qqq.backend.core.model.metadata.scheduleing; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; - - /******************************************************************************* ** Meta-data to define scheduled actions within QQQ. ** @@ -46,11 +43,8 @@ public class QScheduleMetaData private Integer initialDelaySeconds; private Integer initialDelayMillis; - private RunStrategy variantRunStrategy; - private String backendVariant; - private String variantTableName; - private QQueryFilter variantFilter; - private String variantFieldName; + private RunStrategy variantRunStrategy; + private String variantBackend; @@ -191,124 +185,31 @@ public class QScheduleMetaData /******************************************************************************* - ** Getter for backendVariant + ** Getter for variantBackend *******************************************************************************/ - public String getBackendVariant() + public String getVariantBackend() { - return (this.backendVariant); + return (this.variantBackend); } /******************************************************************************* - ** Setter for backendVariant + ** Setter for variantBackend *******************************************************************************/ - public void setBackendVariant(String backendVariant) + public void setVariantBackend(String variantBackend) { - this.backendVariant = backendVariant; + this.variantBackend = variantBackend; } /******************************************************************************* - ** Fluent setter for backendVariant + ** Fluent setter for variantBackend *******************************************************************************/ public QScheduleMetaData withBackendVariant(String backendVariant) { - this.backendVariant = backendVariant; - return (this); - } - - - - /******************************************************************************* - ** Getter for variantTableName - *******************************************************************************/ - public String getVariantTableName() - { - return (this.variantTableName); - } - - - - /******************************************************************************* - ** Setter for variantTableName - *******************************************************************************/ - public void setVariantTableName(String variantTableName) - { - this.variantTableName = variantTableName; - } - - - - /******************************************************************************* - ** Fluent setter for variantTableName - *******************************************************************************/ - public QScheduleMetaData withVariantTableName(String variantTableName) - { - this.variantTableName = variantTableName; - return (this); - } - - - - /******************************************************************************* - ** Getter for variantFilter - *******************************************************************************/ - public QQueryFilter getVariantFilter() - { - return (this.variantFilter); - } - - - - /******************************************************************************* - ** Setter for variantFilter - *******************************************************************************/ - public void setVariantFilter(QQueryFilter variantFilter) - { - this.variantFilter = variantFilter; - } - - - - /******************************************************************************* - ** Fluent setter for variantFilter - *******************************************************************************/ - public QScheduleMetaData withVariantFilter(QQueryFilter variantFilter) - { - this.variantFilter = variantFilter; - return (this); - } - - - - /******************************************************************************* - ** Getter for variantFieldName - *******************************************************************************/ - public String getVariantFieldName() - { - return (this.variantFieldName); - } - - - - /******************************************************************************* - ** Setter for variantFieldName - *******************************************************************************/ - public void setVariantFieldName(String variantFieldName) - { - this.variantFieldName = variantFieldName; - } - - - - /******************************************************************************* - ** Fluent setter for variantFieldName - *******************************************************************************/ - public QScheduleMetaData withVariantFieldName(String variantFieldName) - { - this.variantFieldName = variantFieldName; + this.variantBackend = backendVariant; return (this); } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/scheduler/ScheduleManager.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/scheduler/ScheduleManager.java index b8e91b99..755d2fb7 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/scheduler/ScheduleManager.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/scheduler/ScheduleManager.java @@ -38,9 +38,13 @@ import com.kingsrook.qqq.backend.core.instances.QMetaDataVariableInterpreter; import com.kingsrook.qqq.backend.core.logging.LogPair; 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.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 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.automation.QAutomationProviderMetaData; import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; @@ -142,7 +146,7 @@ public class ScheduleManager if(process.getSchedule() != null && allowedToStart(process.getName())) { QScheduleMetaData scheduleMetaData = process.getSchedule(); - if(process.getSchedule().getBackendVariant() == null || QScheduleMetaData.RunStrategy.SERIAL.equals(process.getSchedule().getVariantRunStrategy())) + if(process.getSchedule().getVariantBackend() == null || QScheduleMetaData.RunStrategy.SERIAL.equals(process.getSchedule().getVariantRunStrategy())) { /////////////////////////////////////////////// // if no variants, or variant is serial mode // @@ -156,11 +160,12 @@ public class ScheduleManager // running at the same time, get the variant records and schedule each separately // ///////////////////////////////////////////////////////////////////////////////////////////////////// QContext.init(qInstance, sessionSupplier.get()); + QBackendMetaData backendMetaData = qInstance.getBackend(scheduleMetaData.getVariantBackend()); for(QRecord qRecord : CollectionUtils.nonNullList(getBackendVariantFilteredRecords(process))) { try { - startProcess(process, MapBuilder.of(scheduleMetaData.getBackendVariant(), qRecord.getValue(scheduleMetaData.getVariantFieldName()))); + startProcess(process, MapBuilder.of(backendMetaData.getVariantOptionsTableTypeValue(), qRecord.getValue(backendMetaData.getVariantOptionsTableIdField()))); } catch(Exception e) { @@ -170,7 +175,7 @@ public class ScheduleManager } else { - LOG.error("Unsupported Schedule Run Strategy [" + process.getSchedule().getVariantFilter() + "] was provided."); + LOG.error("Unsupported Schedule Run Strategy [" + process.getSchedule().getVariantRunStrategy() + "] was provided."); } } } @@ -187,10 +192,11 @@ public class ScheduleManager try { QScheduleMetaData scheduleMetaData = processMetaData.getSchedule(); + QBackendMetaData backendMetaData = qInstance.getBackend(scheduleMetaData.getVariantBackend()); QueryInput queryInput = new QueryInput(); - queryInput.setTableName(scheduleMetaData.getVariantTableName()); - queryInput.setFilter(scheduleMetaData.getVariantFilter()); + queryInput.setTableName(backendMetaData.getVariantOptionsTableName()); + queryInput.setFilter(new QQueryFilter(new QFilterCriteria(backendMetaData.getVariantOptionsTableTypeField(), QCriteriaOperator.EQUALS, backendMetaData.getVariantOptionsTableTypeValue()))); QContext.init(qInstance, sessionSupplier.get()); QueryOutput queryOutput = new QueryAction().execute(queryInput); @@ -325,7 +331,7 @@ public class ScheduleManager try { - if(process.getSchedule().getBackendVariant() == null || QScheduleMetaData.RunStrategy.PARALLEL.equals(process.getSchedule().getVariantRunStrategy())) + if(process.getSchedule().getVariantBackend() == null || QScheduleMetaData.RunStrategy.PARALLEL.equals(process.getSchedule().getVariantRunStrategy())) { QContext.init(qInstance, sessionSupplier.get()); executeSingleProcess(process, backendVariantData); @@ -342,7 +348,8 @@ public class ScheduleManager { QContext.init(qInstance, sessionSupplier.get()); QScheduleMetaData scheduleMetaData = process.getSchedule(); - executeSingleProcess(process, MapBuilder.of(scheduleMetaData.getBackendVariant(), qRecord.getValue(scheduleMetaData.getVariantFieldName()))); + QBackendMetaData backendMetaData = qInstance.getBackend(scheduleMetaData.getVariantBackend()); + executeSingleProcess(process, MapBuilder.of(backendMetaData.getVariantOptionsTableTypeValue(), qRecord.getValue(backendMetaData.getVariantOptionsTableIdField()))); } catch(Exception e) { diff --git a/qqq-backend-module-api/src/main/java/com/kingsrook/qqq/backend/module/api/actions/BaseAPIActionUtil.java b/qqq-backend-module-api/src/main/java/com/kingsrook/qqq/backend/module/api/actions/BaseAPIActionUtil.java index 7f793e71..aa458872 100644 --- a/qqq-backend-module-api/src/main/java/com/kingsrook/qqq/backend/module/api/actions/BaseAPIActionUtil.java +++ b/qqq-backend-module-api/src/main/java/com/kingsrook/qqq/backend/module/api/actions/BaseAPIActionUtil.java @@ -32,6 +32,7 @@ import java.util.Base64; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; +import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; @@ -624,28 +625,57 @@ public class BaseAPIActionUtil ** ** Can be overridden if an API uses an authorization type we don't natively support. *******************************************************************************/ - protected void setupAuthorizationInRequest(HttpRequestBase request) throws QException + public void setupAuthorizationInRequest(HttpRequestBase request) throws QException { + /////////////////////////////////////////////////////////////////////////////////// + // if backend specifies that it uses variants, look for that data in the session // + /////////////////////////////////////////////////////////////////////////////////// + if(backendMetaData.getUsesVariants()) + { + QSession session = QContext.getQSession(); + if(session.getBackendVariants() == null || !session.getBackendVariants().containsKey(backendMetaData.getVariantOptionsTableTypeValue())) + { + throw (new QException("Could not find Backend Variant information for Backend '" + backendMetaData.getName() + "'")); + } + + Serializable variantId = session.getBackendVariants().get(backendMetaData.getVariantOptionsTableTypeValue()); + GetInput getInput = new GetInput(); + getInput.setShouldMaskPasswords(false); + getInput.setTableName(backendMetaData.getVariantOptionsTableName()); + getInput.setPrimaryKey(variantId); + GetOutput getOutput = new GetAction().execute(getInput); + + QRecord record = getOutput.getRecord(); + if(record == null) + { + throw (new QException("Could not find Backend Variant in table " + backendMetaData.getVariantOptionsTableName() + " with id '" + variantId + "'")); + } + + if(backendMetaData.getAuthorizationType().equals(AuthorizationType.BASIC_AUTH_USERNAME_PASSWORD)) + { + request.addHeader("Authorization", getBasicAuthenticationHeader(record.getValueString(backendMetaData.getVariantOptionsTableUsernameField()), record.getValueString(backendMetaData.getVariantOptionsTablePasswordField()))); + } + else if(backendMetaData.getAuthorizationType().equals(AuthorizationType.API_KEY_HEADER)) + { + request.addHeader("API-Key", record.getValueString(backendMetaData.getVariantOptionsTableApiKeyField())); + } + else + { + throw (new IllegalArgumentException("Unexpected variant authorization type specified: " + backendMetaData.getAuthorizationType())); + } + return; + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // if not using variants, the authorization data will be in the backend meta data object // + /////////////////////////////////////////////////////////////////////////////////////////// switch(backendMetaData.getAuthorizationType()) { - case BASIC_AUTH_API_KEY: - request.addHeader("Authorization", getBasicAuthenticationHeader(backendMetaData.getApiKey())); - break; - - case BASIC_AUTH_USERNAME_PASSWORD: - request.addHeader("Authorization", getBasicAuthenticationHeader(backendMetaData.getUsername(), backendMetaData.getPassword())); - break; - - case API_KEY_HEADER: - request.addHeader("API-Key", backendMetaData.getApiKey()); - break; - - case OAUTH2: - request.setHeader("Authorization", "Bearer " + getOAuth2Token()); - break; - - default: - throw new IllegalArgumentException("Unexpected authorization type: " + backendMetaData.getAuthorizationType()); + case BASIC_AUTH_API_KEY -> request.addHeader("Authorization", getBasicAuthenticationHeader(backendMetaData.getApiKey())); + case BASIC_AUTH_USERNAME_PASSWORD -> request.addHeader("Authorization", getBasicAuthenticationHeader(backendMetaData.getUsername(), backendMetaData.getPassword())); + case API_KEY_HEADER -> request.addHeader("API-Key", backendMetaData.getApiKey()); + case OAUTH2 -> request.setHeader("Authorization", "Bearer " + getOAuth2Token()); + default -> throw new IllegalArgumentException("Unexpected authorization type: " + backendMetaData.getAuthorizationType()); } } diff --git a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java index 297cffcc..15004bf0 100644 --- a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java +++ b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java @@ -87,6 +87,8 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput; import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; +import com.kingsrook.qqq.backend.core.model.actions.tables.query.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.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin; @@ -98,11 +100,13 @@ import com.kingsrook.qqq.backend.core.model.actions.values.SearchPossibleValueSo import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput; import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput; import com.kingsrook.qqq.backend.core.model.data.QRecord; +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.fields.AdornmentType; import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType; +import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendVariant; 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.model.session.QSession; @@ -114,6 +118,7 @@ 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 com.kingsrook.qqq.backend.core.utils.collections.MapBuilder; import com.kingsrook.qqq.backend.core.utils.lambdas.UnsafeConsumer; import com.kingsrook.qqq.backend.core.utils.lambdas.UnsafeFunction; import io.javalin.Javalin; @@ -348,6 +353,7 @@ public class QJavalinImplementation post("/", QJavalinImplementation::dataInsert); get("/count", QJavalinImplementation::dataCount); post("/count", QJavalinImplementation::dataCount); + get("/variants", QJavalinImplementation::variants); get("/export", QJavalinImplementation::dataExportWithoutFilename); post("/export", QJavalinImplementation::dataExportWithoutFilename); get("/export/{filename}", QJavalinImplementation::dataExportWithFilename); @@ -478,6 +484,13 @@ public class QJavalinImplementation QSession session = authenticationModule.createSession(qInstance, authenticationContext); QContext.init(qInstance, session, null, input); + String tableVariant = StringUtils.hasContent(context.formParam("tableVariant")) ? context.formParam("tableVariant") : context.queryParam("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 // ///////////////////////////////////////////////////////////////////////////////// @@ -970,6 +983,57 @@ public class QJavalinImplementation + /******************************************************************************* + * + *******************************************************************************/ + static void variants(Context context) + { + String table = context.pathParam("table"); + List variants = new ArrayList<>(); + + try + { + QueryInput queryInput = new QueryInput(); + setupSession(context, queryInput); + + //////////////////////////////////// + // get the backend for this table // + //////////////////////////////////// + QTableMetaData tableMetaData = QContext.getQInstance().getTable(table); + QBackendMetaData backend = QContext.getQInstance().getBackend(tableMetaData.getBackendName()); + + ///////////////////////////////////////////////////////////////////////////////////// + // if the backend uses variants, query for all possible variants of the given type // + ///////////////////////////////////////////////////////////////////////////////////// + if(backend != null && backend.getUsesVariants()) + { + queryInput.setTableName(backend.getVariantOptionsTableName()); + queryInput.setFilter(new QQueryFilter(new QFilterCriteria(backend.getVariantOptionsTableTypeField(), QCriteriaOperator.EQUALS, backend.getVariantOptionsTableTypeValue()))); + QueryOutput output = new QueryAction().execute(queryInput); + for(QRecord qRecord : output.getRecords()) + { + variants.add(new QFrontendVariant() + .withId(qRecord.getValue(backend.getVariantOptionsTableIdField())) + .withType(backend.getVariantOptionsTableTypeValue()) + .withName(qRecord.getValueString(backend.getVariantOptionsTableNameField())); + } + + QJavalinAccessLogger.logStartSilent("variants"); + PermissionsHelper.checkTablePermissionThrowing(queryInput, TablePermissionSubType.READ); + } + + QJavalinAccessLogger.logEndSuccessIfSlow(SLOW_LOG_THRESHOLD_MS, logPair("table", table), logPair("input", queryInput)); + context.result(JsonUtils.toJson(variants)); + } + catch(Exception e) + { + QJavalinAccessLogger.logEndFail(e, logPair("table", table)); + handleException(context, e); + } + } + + + /******************************************************************************* * * Filter parameter is a serialized QQueryFilter object, that is to say: