mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-17 20:50:44 +00:00
Merge remote-tracking branch 'origin/feature/CTLE-421-migrate-to-use-api-keys' into integration/sprint-25
This commit is contained in:
@ -56,6 +56,10 @@
|
|||||||
<groupId>software.amazon.awssdk</groupId>
|
<groupId>software.amazon.awssdk</groupId>
|
||||||
<artifactId>quicksight</artifactId>
|
<artifactId>quicksight</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>software.amazon.awssdk</groupId>
|
||||||
|
<artifactId>apigateway</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.amazonaws</groupId>
|
<groupId>com.amazonaws</groupId>
|
||||||
<artifactId>aws-java-sdk-secretsmanager</artifactId>
|
<artifactId>aws-java-sdk-secretsmanager</artifactId>
|
||||||
@ -100,8 +104,18 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.auth0</groupId>
|
<groupId>com.auth0</groupId>
|
||||||
<artifactId>mvc-auth-commons</artifactId>
|
<artifactId>auth0</artifactId>
|
||||||
<version>1.9.2</version>
|
<version>2.1.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.auth0</groupId>
|
||||||
|
<artifactId>java-jwt</artifactId>
|
||||||
|
<version>4.4.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.auth0</groupId>
|
||||||
|
<artifactId>jwks-rsa</artifactId>
|
||||||
|
<version>0.22.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.cdimascio</groupId>
|
<groupId>io.github.cdimascio</groupId>
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. 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.backend.core.actions.customizers;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public abstract class AbstractPreInsertCustomizer
|
||||||
|
{
|
||||||
|
protected InsertInput insertInput;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public abstract List<QRecord> apply(List<QRecord> records);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for insertInput
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public InsertInput getInsertInput()
|
||||||
|
{
|
||||||
|
return insertInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for insertInput
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setInsertInput(InsertInput insertInput)
|
||||||
|
{
|
||||||
|
this.insertInput = insertInput;
|
||||||
|
}
|
||||||
|
}
|
@ -29,16 +29,10 @@ package com.kingsrook.qqq.backend.core.actions.customizers;
|
|||||||
** Works with TableCustomizer (singular version of this name) objects, during
|
** Works with TableCustomizer (singular version of this name) objects, during
|
||||||
** instance validation, to provide validation of the referenced code (and to
|
** instance validation, to provide validation of the referenced code (and to
|
||||||
** make such validation from sub-backend-modules possible in the future).
|
** make such validation from sub-backend-modules possible in the future).
|
||||||
**
|
|
||||||
** The idea of the 3rd argument here is to provide a way that we can enforce
|
|
||||||
** the type-parameters for the custom code. E.g., if it's a Function - how
|
|
||||||
** can we check at run-time that the type-params are correct? We couldn't find
|
|
||||||
** how to do this "reflectively", so we can instead try to run the custom code,
|
|
||||||
** passing it objects of the type that this customizer expects, and a validation
|
|
||||||
** error will raise upon ClassCastException... This maybe could improve!
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public enum TableCustomizers
|
public enum TableCustomizers
|
||||||
{
|
{
|
||||||
|
PRE_INSERT_RECORD(new TableCustomizer("preInsertRecord", AbstractPreInsertCustomizer.class)),
|
||||||
POST_QUERY_RECORD(new TableCustomizer("postQueryRecord", AbstractPostQueryCustomizer.class)),
|
POST_QUERY_RECORD(new TableCustomizer("postQueryRecord", AbstractPostQueryCustomizer.class)),
|
||||||
POST_INSERT_RECORD(new TableCustomizer("postInsertRecord", AbstractPostInsertCustomizer.class));
|
POST_INSERT_RECORD(new TableCustomizer("postInsertRecord", AbstractPostInsertCustomizer.class));
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
|||||||
import com.kingsrook.qqq.backend.core.actions.interfaces.GetInterface;
|
import com.kingsrook.qqq.backend.core.actions.interfaces.GetInterface;
|
||||||
import com.kingsrook.qqq.backend.core.actions.values.QPossibleValueTranslator;
|
import com.kingsrook.qqq.backend.core.actions.values.QPossibleValueTranslator;
|
||||||
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
|
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
|
||||||
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.logging.LogPair;
|
import com.kingsrook.qqq.backend.core.logging.LogPair;
|
||||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||||
@ -51,6 +52,8 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
|||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
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.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.cache.CacheUseCase;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.cache.CacheUseCase;
|
||||||
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
|
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
|
||||||
@ -372,6 +375,29 @@ public class GetAction
|
|||||||
QValueFormatter.setDisplayValuesInRecords(getInput.getTable(), List.of(returnRecord));
|
QValueFormatter.setDisplayValuesInRecords(getInput.getTable(), List.of(returnRecord));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(getInput.getShouldOmitHiddenFields() || getInput.getShouldMaskPasswords())
|
||||||
|
{
|
||||||
|
Map<String, QFieldMetaData> fields = QContext.getQInstance().getTable(getInput.getTableName()).getFields();
|
||||||
|
for(String fieldName : fields.keySet())
|
||||||
|
{
|
||||||
|
QFieldType fieldType = fields.get(fieldName).getType();
|
||||||
|
if(fieldType != null && fieldType.needsMasked())
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// empty out the value completely first (which will remove from //
|
||||||
|
// display fields as well) then update display value if flag is set //
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
returnRecord.removeValue(fieldName);
|
||||||
|
returnRecord.setValue(fieldName, "************");
|
||||||
|
if(getInput.getShouldGenerateDisplayValues())
|
||||||
|
{
|
||||||
|
returnRecord.setDisplayValue(fieldName, record.getValueString(fieldName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QValueFormatter.setDisplayValuesInRecords(getInput.getTable(), List.of(returnRecord));
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// note - shouldFetchHeavyFields should be handled by the underlying action //
|
// note - shouldFetchHeavyFields should be handled by the underlying action //
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -38,6 +38,7 @@ import com.kingsrook.qqq.backend.core.actions.audits.DMLAuditAction;
|
|||||||
import com.kingsrook.qqq.backend.core.actions.automation.AutomationStatus;
|
import com.kingsrook.qqq.backend.core.actions.automation.AutomationStatus;
|
||||||
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationStatusUpdater;
|
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationStatusUpdater;
|
||||||
import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPostInsertCustomizer;
|
import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPostInsertCustomizer;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPreInsertCustomizer;
|
||||||
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
||||||
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.helpers.UniqueKeyHelper;
|
import com.kingsrook.qqq.backend.core.actions.tables.helpers.UniqueKeyHelper;
|
||||||
@ -86,6 +87,7 @@ public class InsertAction extends AbstractQActionFunction<InsertInput, InsertOut
|
|||||||
throw (new QException("Error: Undefined table: " + insertInput.getTableName()));
|
throw (new QException("Error: Undefined table: " + insertInput.getTableName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Optional<AbstractPreInsertCustomizer> preInsertCustomizer = QCodeLoader.getTableCustomizer(AbstractPreInsertCustomizer.class, table, TableCustomizers.PRE_INSERT_RECORD.getRole());
|
||||||
Optional<AbstractPostInsertCustomizer> postInsertCustomizer = QCodeLoader.getTableCustomizer(AbstractPostInsertCustomizer.class, table, TableCustomizers.POST_INSERT_RECORD.getRole());
|
Optional<AbstractPostInsertCustomizer> postInsertCustomizer = QCodeLoader.getTableCustomizer(AbstractPostInsertCustomizer.class, table, TableCustomizers.POST_INSERT_RECORD.getRole());
|
||||||
setAutomationStatusField(insertInput);
|
setAutomationStatusField(insertInput);
|
||||||
|
|
||||||
@ -97,6 +99,12 @@ public class InsertAction extends AbstractQActionFunction<InsertInput, InsertOut
|
|||||||
validateRequiredFields(insertInput);
|
validateRequiredFields(insertInput);
|
||||||
ValidateRecordSecurityLockHelper.validateSecurityFields(insertInput.getTable(), insertInput.getRecords(), ValidateRecordSecurityLockHelper.Action.INSERT);
|
ValidateRecordSecurityLockHelper.validateSecurityFields(insertInput.getTable(), insertInput.getRecords(), ValidateRecordSecurityLockHelper.Action.INSERT);
|
||||||
|
|
||||||
|
if(preInsertCustomizer.isPresent())
|
||||||
|
{
|
||||||
|
preInsertCustomizer.get().setInsertInput(insertInput);
|
||||||
|
insertInput.setRecords(preInsertCustomizer.get().apply(insertInput.getRecords()));
|
||||||
|
}
|
||||||
|
|
||||||
InsertOutput insertOutput = qModule.getInsertInterface().execute(insertInput);
|
InsertOutput insertOutput = qModule.getInsertInterface().execute(insertInput);
|
||||||
List<String> errors = insertOutput.getRecords().stream().flatMap(r -> r.getErrors().stream()).toList();
|
List<String> errors = insertOutput.getRecords().stream().flatMap(r -> r.getErrors().stream()).toList();
|
||||||
if(CollectionUtils.nullSafeHasContents(errors))
|
if(CollectionUtils.nullSafeHasContents(errors))
|
||||||
|
@ -27,6 +27,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||||
@ -45,6 +46,7 @@ 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.QueryInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
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.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.Association;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.Association;
|
||||||
@ -247,5 +249,59 @@ public class QueryAction
|
|||||||
{
|
{
|
||||||
QValueFormatter.setDisplayValuesInRecords(queryInput.getTable(), records);
|
QValueFormatter.setDisplayValuesInRecords(queryInput.getTable(), records);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
// mask any password fields //
|
||||||
|
//////////////////////////////
|
||||||
|
if(queryInput.getShouldOmitHiddenFields() || queryInput.getShouldMaskPasswords())
|
||||||
|
{
|
||||||
|
Set<String> maskedFields = new HashSet<>();
|
||||||
|
Set<String> hiddenFields = new HashSet<>();
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// build up sets of passwords and hidden fields //
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
Map<String, QFieldMetaData> fields = QContext.getQInstance().getTable(queryInput.getTableName()).getFields();
|
||||||
|
for(String fieldName : fields.keySet())
|
||||||
|
{
|
||||||
|
QFieldMetaData field = fields.get(fieldName);
|
||||||
|
if(queryInput.getShouldOmitHiddenFields() && field.getIsHidden())
|
||||||
|
{
|
||||||
|
hiddenFields.add(fieldName);
|
||||||
|
}
|
||||||
|
else if(field.getType() != null && field.getType().needsMasked())
|
||||||
|
{
|
||||||
|
maskedFields.add(fieldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
// iterate over records replacing values with mask //
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
for(QRecord record : records)
|
||||||
|
{
|
||||||
|
/////////////////////////
|
||||||
|
// clear hidden fields //
|
||||||
|
/////////////////////////
|
||||||
|
for(String hiddenFieldName : hiddenFields)
|
||||||
|
{
|
||||||
|
record.removeValue(hiddenFieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(String maskedFieldName : maskedFields)
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// empty out the value completely first (which will remove from //
|
||||||
|
// display fields as well) then update display value if flag is set //
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
record.removeValue(maskedFieldName);
|
||||||
|
record.setValue(maskedFieldName, "************");
|
||||||
|
if(queryInput.getShouldGenerateDisplayValues())
|
||||||
|
{
|
||||||
|
record.setDisplayValue(maskedFieldName, record.getValueString(maskedFieldName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -955,7 +955,8 @@ public class QInstanceEnricher
|
|||||||
{
|
{
|
||||||
for(String fieldName : table.getFields().keySet())
|
for(String fieldName : table.getFields().keySet())
|
||||||
{
|
{
|
||||||
if(!usedFieldNames.contains(fieldName))
|
QFieldMetaData field = table.getField(fieldName);
|
||||||
|
if(!field.getIsHidden() && !usedFieldNames.contains(fieldName))
|
||||||
{
|
{
|
||||||
otherSection.getFieldNames().add(fieldName);
|
otherSection.getFieldNames().add(fieldName);
|
||||||
usedFieldNames.add(fieldName);
|
usedFieldNames.add(fieldName);
|
||||||
|
@ -437,7 +437,14 @@ public class QInstanceValidator
|
|||||||
|
|
||||||
for(String fieldName : CollectionUtils.nonNullMap(table.getFields()).keySet())
|
for(String fieldName : CollectionUtils.nonNullMap(table.getFields()).keySet())
|
||||||
{
|
{
|
||||||
assertCondition(fieldNamesInSections.contains(fieldName), "Table " + tableName + " field " + fieldName + " is not listed in any field sections.");
|
if(table.getField(fieldName).getIsHidden())
|
||||||
|
{
|
||||||
|
assertCondition(!fieldNamesInSections.contains(fieldName), "Table " + tableName + " field " + fieldName + " is listed in a field section, but it is marked as hidden.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assertCondition(fieldNamesInSections.contains(fieldName), "Table " + tableName + " field " + fieldName + " is not listed in any field sections.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(table.getRecordLabelFields() != null && table.getFields() != null)
|
if(table.getRecordLabelFields() != null && table.getFields() != null)
|
||||||
|
@ -43,6 +43,8 @@ public class GetInput extends AbstractTableActionInput
|
|||||||
private boolean shouldTranslatePossibleValues = false;
|
private boolean shouldTranslatePossibleValues = false;
|
||||||
private boolean shouldGenerateDisplayValues = false;
|
private boolean shouldGenerateDisplayValues = false;
|
||||||
private boolean shouldFetchHeavyFields = true;
|
private boolean shouldFetchHeavyFields = true;
|
||||||
|
private boolean shouldOmitHiddenFields = true;
|
||||||
|
private boolean shouldMaskPasswords = true;
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -323,4 +325,66 @@ public class GetInput extends AbstractTableActionInput
|
|||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for shouldMaskPasswords
|
||||||
|
*******************************************************************************/
|
||||||
|
public boolean getShouldMaskPasswords()
|
||||||
|
{
|
||||||
|
return (this.shouldMaskPasswords);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for shouldMaskPasswords
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setShouldMaskPasswords(boolean shouldMaskPasswords)
|
||||||
|
{
|
||||||
|
this.shouldMaskPasswords = shouldMaskPasswords;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for shouldMaskPasswords
|
||||||
|
*******************************************************************************/
|
||||||
|
public GetInput withShouldMaskPasswords(boolean shouldMaskPasswords)
|
||||||
|
{
|
||||||
|
this.shouldMaskPasswords = shouldMaskPasswords;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for shouldOmitHiddenFields
|
||||||
|
*******************************************************************************/
|
||||||
|
public boolean getShouldOmitHiddenFields()
|
||||||
|
{
|
||||||
|
return (this.shouldOmitHiddenFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for shouldOmitHiddenFields
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setShouldOmitHiddenFields(boolean shouldOmitHiddenFields)
|
||||||
|
{
|
||||||
|
this.shouldOmitHiddenFields = shouldOmitHiddenFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for shouldOmitHiddenFields
|
||||||
|
*******************************************************************************/
|
||||||
|
public GetInput withShouldOmitHiddenFields(boolean shouldOmitHiddenFields)
|
||||||
|
{
|
||||||
|
this.shouldOmitHiddenFields = shouldOmitHiddenFields;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,8 @@ public class QueryInput extends AbstractTableActionInput
|
|||||||
private boolean shouldTranslatePossibleValues = false;
|
private boolean shouldTranslatePossibleValues = false;
|
||||||
private boolean shouldGenerateDisplayValues = false;
|
private boolean shouldGenerateDisplayValues = false;
|
||||||
private boolean shouldFetchHeavyFields = false;
|
private boolean shouldFetchHeavyFields = false;
|
||||||
|
private boolean shouldOmitHiddenFields = true;
|
||||||
|
private boolean shouldMaskPasswords = true;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// this field - only applies if shouldTranslatePossibleValues is true. //
|
// this field - only applies if shouldTranslatePossibleValues is true. //
|
||||||
@ -497,4 +499,66 @@ public class QueryInput extends AbstractTableActionInput
|
|||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for shouldMaskPasswords
|
||||||
|
*******************************************************************************/
|
||||||
|
public boolean getShouldMaskPasswords()
|
||||||
|
{
|
||||||
|
return (this.shouldMaskPasswords);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for shouldMaskPasswords
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setShouldMaskPasswords(boolean shouldMaskPasswords)
|
||||||
|
{
|
||||||
|
this.shouldMaskPasswords = shouldMaskPasswords;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for shouldMaskPasswords
|
||||||
|
*******************************************************************************/
|
||||||
|
public QueryInput withShouldMaskPasswords(boolean shouldMaskPasswords)
|
||||||
|
{
|
||||||
|
this.shouldMaskPasswords = shouldMaskPasswords;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for shouldOmitHiddenFields
|
||||||
|
*******************************************************************************/
|
||||||
|
public boolean getShouldOmitHiddenFields()
|
||||||
|
{
|
||||||
|
return (this.shouldOmitHiddenFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for shouldOmitHiddenFields
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setShouldOmitHiddenFields(boolean shouldOmitHiddenFields)
|
||||||
|
{
|
||||||
|
this.shouldOmitHiddenFields = shouldOmitHiddenFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for shouldOmitHiddenFields
|
||||||
|
*******************************************************************************/
|
||||||
|
public QueryInput withShouldOmitHiddenFields(boolean shouldOmitHiddenFields)
|
||||||
|
{
|
||||||
|
this.shouldOmitHiddenFields = shouldOmitHiddenFields;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,11 @@ public @interface QField
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
boolean isEditable() default true;
|
boolean isEditable() default true;
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
boolean isHidden() default false;
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -196,6 +196,17 @@ public class QRecord implements Serializable
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void removeValue(String fieldName)
|
||||||
|
{
|
||||||
|
values.remove(fieldName);
|
||||||
|
displayValues.remove(fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -54,6 +54,7 @@ public class QFieldMetaData implements Cloneable
|
|||||||
private QFieldType type;
|
private QFieldType type;
|
||||||
private boolean isRequired = false;
|
private boolean isRequired = false;
|
||||||
private boolean isEditable = true;
|
private boolean isEditable = true;
|
||||||
|
private boolean isHidden = false;
|
||||||
private boolean isHeavy = false;
|
private boolean isHeavy = false;
|
||||||
|
|
||||||
private FieldSecurityLock fieldSecurityLock;
|
private FieldSecurityLock fieldSecurityLock;
|
||||||
@ -183,6 +184,7 @@ public class QFieldMetaData implements Cloneable
|
|||||||
QField fieldAnnotation = optionalFieldAnnotation.get();
|
QField fieldAnnotation = optionalFieldAnnotation.get();
|
||||||
setIsRequired(fieldAnnotation.isRequired());
|
setIsRequired(fieldAnnotation.isRequired());
|
||||||
setIsEditable(fieldAnnotation.isEditable());
|
setIsEditable(fieldAnnotation.isEditable());
|
||||||
|
setIsHidden(fieldAnnotation.isHidden());
|
||||||
|
|
||||||
if(StringUtils.hasContent(fieldAnnotation.label()))
|
if(StringUtils.hasContent(fieldAnnotation.label()))
|
||||||
{
|
{
|
||||||
@ -851,4 +853,36 @@ public class QFieldMetaData implements Cloneable
|
|||||||
this.middlewareMetaData.put(middlewareMetaData.getType(), middlewareMetaData);
|
this.middlewareMetaData.put(middlewareMetaData.getType(), middlewareMetaData);
|
||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for isHidden
|
||||||
|
*******************************************************************************/
|
||||||
|
public boolean getIsHidden()
|
||||||
|
{
|
||||||
|
return (this.isHidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for isHidden
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setIsHidden(boolean isHidden)
|
||||||
|
{
|
||||||
|
this.isHidden = isHidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for isHidden
|
||||||
|
*******************************************************************************/
|
||||||
|
public QFieldMetaData withIsHidden(boolean isHidden)
|
||||||
|
{
|
||||||
|
this.isHidden = isHidden;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -108,4 +108,14 @@ public enum QFieldType
|
|||||||
{
|
{
|
||||||
return this == QFieldType.INTEGER || this == QFieldType.DECIMAL;
|
return this == QFieldType.INTEGER || this == QFieldType.DECIMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public boolean needsMasked()
|
||||||
|
{
|
||||||
|
return this == QFieldType.PASSWORD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ import com.auth0.jwt.exceptions.JWTDecodeException;
|
|||||||
import com.auth0.jwt.exceptions.JWTVerificationException;
|
import com.auth0.jwt.exceptions.JWTVerificationException;
|
||||||
import com.auth0.jwt.exceptions.TokenExpiredException;
|
import com.auth0.jwt.exceptions.TokenExpiredException;
|
||||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||||
|
import com.auth0.net.Response;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
@ -297,12 +298,12 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
// call auth0 with a login request //
|
// call auth0 with a login request //
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
TokenHolder result = auth.login(credentials.split(":")[0], credentials.split(":")[1].toCharArray())
|
Response<TokenHolder> result = auth.login(credentials.split(":")[0], credentials.split(":")[1].toCharArray())
|
||||||
.setScope("openid email nickname")
|
.setScope("openid email nickname")
|
||||||
.setAudience(metaData.getAudience())
|
.setAudience(metaData.getAudience())
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
return (result.getAccessToken());
|
return (result.getBody().getAccessToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ public class MockQueryAction implements QueryInterface
|
|||||||
|
|
||||||
for(String field : table.getFields().keySet())
|
for(String field : table.getFields().keySet())
|
||||||
{
|
{
|
||||||
Serializable value = field.equals("id") ? (i + 1) : getValue(table, field);
|
Serializable value = field.equals("id") ? (i + 1) : getMockValue(table, field);
|
||||||
record.setValue(field, value);
|
record.setValue(field, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ public class MockQueryAction implements QueryInterface
|
|||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@SuppressWarnings("checkstyle:MagicNumber")
|
@SuppressWarnings("checkstyle:MagicNumber")
|
||||||
private Serializable getValue(QTableMetaData table, String field)
|
public static Serializable getMockValue(QTableMetaData table, String field)
|
||||||
{
|
{
|
||||||
// @formatter:off // IJ can't do new-style switch correctly yet...
|
// @formatter:off // IJ can't do new-style switch correctly yet...
|
||||||
return switch(table.getField(field).getType())
|
return switch(table.getField(field).getType())
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
package com.kingsrook.qqq.backend.core.actions.tables;
|
package com.kingsrook.qqq.backend.core.actions.tables;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||||
@ -33,6 +34,7 @@ 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.QueryInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
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.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.backend.implementations.mock.MockQueryAction;
|
||||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -73,17 +75,40 @@ class QueryActionTest extends BaseTest
|
|||||||
// this SHOULD be empty, based on the default for the should //
|
// this SHOULD be empty, based on the default for the should //
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
assertThat(record.getDisplayValues()).isEmpty();
|
assertThat(record.getDisplayValues()).isEmpty();
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
// hidden field should not be in record //
|
||||||
|
//////////////////////////////////////////
|
||||||
|
assertThat(record.getValue("superSecret")).isNull();
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
// password field should be masked //
|
||||||
|
/////////////////////////////////////
|
||||||
|
assertThat(record.getValueString("ssn")).contains("****");
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
// now flip that field and re-run //
|
// now flip some fields, re-run, and validate results //
|
||||||
////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
queryInput.setShouldGenerateDisplayValues(true);
|
queryInput.setShouldGenerateDisplayValues(true);
|
||||||
|
queryInput.setShouldMaskPasswords(false);
|
||||||
|
queryInput.setShouldOmitHiddenFields(false);
|
||||||
assertThat(queryOutput.getRecords()).isNotEmpty();
|
assertThat(queryOutput.getRecords()).isNotEmpty();
|
||||||
queryOutput = new QueryAction().execute(queryInput);
|
queryOutput = new QueryAction().execute(queryInput);
|
||||||
for(QRecord record : queryOutput.getRecords())
|
for(QRecord record : queryOutput.getRecords())
|
||||||
{
|
{
|
||||||
assertThat(record.getDisplayValues()).isNotEmpty();
|
assertThat(record.getDisplayValues()).isNotEmpty();
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
// hidden field should now be in record //
|
||||||
|
//////////////////////////////////////////
|
||||||
|
assertThat(record.getValue("superSecret")).isNotNull();
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
// password field should be masked //
|
||||||
|
/////////////////////////////////////
|
||||||
|
Serializable mockValue = MockQueryAction.getMockValue(QContext.getQInstance().getTable("person"), "ssn");
|
||||||
|
assertThat(record.getValueString("ssn")).isEqualTo(mockValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,7 +528,8 @@ public class TestUtils
|
|||||||
.withField(new QFieldMetaData("noOfShoes", QFieldType.INTEGER).withDisplayFormat(DisplayFormat.COMMAS))
|
.withField(new QFieldMetaData("noOfShoes", QFieldType.INTEGER).withDisplayFormat(DisplayFormat.COMMAS))
|
||||||
.withField(new QFieldMetaData("cost", QFieldType.DECIMAL).withDisplayFormat(DisplayFormat.CURRENCY))
|
.withField(new QFieldMetaData("cost", QFieldType.DECIMAL).withDisplayFormat(DisplayFormat.CURRENCY))
|
||||||
.withField(new QFieldMetaData("price", QFieldType.DECIMAL).withDisplayFormat(DisplayFormat.CURRENCY))
|
.withField(new QFieldMetaData("price", QFieldType.DECIMAL).withDisplayFormat(DisplayFormat.CURRENCY))
|
||||||
;
|
.withField(new QFieldMetaData("ssn", QFieldType.STRING).withType(QFieldType.PASSWORD))
|
||||||
|
.withField(new QFieldMetaData("superSecret", QFieldType.STRING).withType(QFieldType.PASSWORD).withIsHidden(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
7
qqq-dev-tools/bin/open-jacoco-test-report.sh
Executable file
7
qqq-dev-tools/bin/open-jacoco-test-report.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
## open-jacoco-test-report.sh
|
||||||
|
## opens the jacoco generated file from the target directory in browser
|
||||||
|
############################################################################
|
||||||
|
open target/site/jacoco/index.html
|
@ -48,7 +48,7 @@ checkBuild()
|
|||||||
qqq-frontend-core) shortRepo="f'core";;
|
qqq-frontend-core) shortRepo="f'core";;
|
||||||
qqq-frontend-material-dashboard) shortRepo="m-db";;
|
qqq-frontend-material-dashboard) shortRepo="m-db";;
|
||||||
ColdTrack-Live) shortRepo="ctl";;
|
ColdTrack-Live) shortRepo="ctl";;
|
||||||
Nutrifresh-One-Scripts) shortRepo="nf1-scr";;
|
ColdTrack-Live-Scripts) shortRepo="ct1-scr";;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
timestamp=$(date -j -f "%Y-%m-%dT%H:%M:%S%z" $(echo "$startDate" | sed 's/\....Z/+0000/') +%s)
|
timestamp=$(date -j -f "%Y-%m-%dT%H:%M:%S%z" $(echo "$startDate" | sed 's/\....Z/+0000/') +%s)
|
||||||
|
Reference in New Issue
Block a user