Merge branch 'feature/CTLE-421-migrate-to-use-api-keys' into integration/sprint-25

This commit is contained in:
Tim Chamberlain
2023-05-02 11:32:27 -05:00
7 changed files with 163 additions and 7 deletions

View File

@ -34,6 +34,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
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.data.QRecord; import com.kingsrook.qqq.backend.core.model.data.QRecord;
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.utils.CollectionUtils;
/******************************************************************************* /*******************************************************************************
@ -120,6 +121,11 @@ public abstract class ChildInserterPostInsertCustomizer extends AbstractPostInse
InsertOutput insertOutput = new InsertAction().execute(insertInput); InsertOutput insertOutput = new InsertAction().execute(insertInput);
Iterator<QRecord> insertedRecordIterator = insertOutput.getRecords().iterator(); Iterator<QRecord> insertedRecordIterator = insertOutput.getRecords().iterator();
/////////////////////////////////////////////////////////////////////////////////
// check for any errors when inserting the children, if any errors were found, //
// then set a warning in the parent with the details of the problem //
/////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
// iterate over the original list of records again - for any that need a child (e.g., are missing // // iterate over the original list of records again - for any that need a child (e.g., are missing //
// foreign key), set their foreign key to a newly inserted child's key, and add them to be updated. // // foreign key), set their foreign key to a newly inserted child's key, and add them to be updated. //
@ -130,7 +136,21 @@ public abstract class ChildInserterPostInsertCustomizer extends AbstractPostInse
Serializable primaryKey = record.getValue(table.getPrimaryKeyField()); Serializable primaryKey = record.getValue(table.getPrimaryKeyField());
if(record.getValue(getForeignKeyFieldName()) == null) if(record.getValue(getForeignKeyFieldName()) == null)
{ {
Serializable foreignKey = insertedRecordIterator.next().getValue(childTable.getPrimaryKeyField()); ///////////////////////////////////////////////////////////////////////////////////////////////////
// get the corresponding child record, if it has any errors, set that as a warning in the parent //
///////////////////////////////////////////////////////////////////////////////////////////////////
QRecord childRecord = insertedRecordIterator.next();
if(CollectionUtils.nullSafeHasContents(childRecord.getErrors()))
{
for(String childWarning : childRecord.getErrors())
{
record.addWarning("Error creating child " + childTable.getLabel() + " (" + childWarning + ")");
}
rs.add(record);
continue;
}
Serializable foreignKey = childRecord.getValue(childTable.getPrimaryKeyField());
recordsToUpdate.add(new QRecord().withValue(table.getPrimaryKeyField(), primaryKey).withValue(getForeignKeyFieldName(), foreignKey)); recordsToUpdate.add(new QRecord().withValue(table.getPrimaryKeyField(), primaryKey).withValue(getForeignKeyFieldName(), foreignKey));
record.setValue(getForeignKeyFieldName(), foreignKey); record.setValue(getForeignKeyFieldName(), foreignKey);
rs.add(record); rs.add(record);

View File

@ -53,7 +53,6 @@ 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.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;
@ -380,8 +379,12 @@ public class GetAction
Map<String, QFieldMetaData> fields = QContext.getQInstance().getTable(getInput.getTableName()).getFields(); Map<String, QFieldMetaData> fields = QContext.getQInstance().getTable(getInput.getTableName()).getFields();
for(String fieldName : fields.keySet()) for(String fieldName : fields.keySet())
{ {
QFieldType fieldType = fields.get(fieldName).getType(); QFieldMetaData field = fields.get(fieldName);
if(fieldType != null && fieldType.needsMasked()) if(getInput.getShouldOmitHiddenFields() && field.getIsHidden())
{
returnRecord.removeValue(fieldName);
}
else if(field.getType() != null && field.getType().needsMasked())
{ {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// empty out the value completely first (which will remove from // // empty out the value completely first (which will remove from //
@ -395,7 +398,6 @@ public class GetAction
} }
} }
} }
QValueFormatter.setDisplayValuesInRecords(getInput.getTable(), List.of(returnRecord));
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////

View File

@ -65,6 +65,7 @@ public class QRecord implements Serializable
private Map<String, String> displayValues = new LinkedHashMap<>(); private Map<String, String> displayValues = new LinkedHashMap<>();
private Map<String, Serializable> backendDetails = new LinkedHashMap<>(); private Map<String, Serializable> backendDetails = new LinkedHashMap<>();
private List<String> errors = new ArrayList<>(); private List<String> errors = new ArrayList<>();
private List<String> warnings = new ArrayList<>();
private Map<String, List<QRecord>> associatedRecords = new HashMap<>(); private Map<String, List<QRecord>> associatedRecords = new HashMap<>();
@ -652,4 +653,46 @@ public class QRecord implements Serializable
return (this); return (this);
} }
/*******************************************************************************
** Getter for warnings
*******************************************************************************/
public List<String> getWarnings()
{
return (this.warnings);
}
/*******************************************************************************
** Setter for warnings
*******************************************************************************/
public void setWarnings(List<String> warnings)
{
this.warnings = warnings;
}
/*******************************************************************************
** Fluent setter for warnings
*******************************************************************************/
public QRecord withWarnings(List<String> warnings)
{
this.warnings = warnings;
return (this);
}
/*******************************************************************************
** Add one warning to this record
**
*******************************************************************************/
public void addWarning(String warning)
{
this.warnings.add(warning);
}
} }

View File

@ -39,6 +39,7 @@ public enum AdornmentType
SIZE, SIZE,
CODE_EDITOR, CODE_EDITOR,
RENDER_HTML, RENDER_HTML,
REVEAL,
ERROR; ERROR;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// keep these values in sync with AdornmentType.ts in qqq-frontend-core // // keep these values in sync with AdornmentType.ts in qqq-frontend-core //

View File

@ -151,7 +151,7 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
if(context.containsKey(BASIC_AUTH_KEY)) if(context.containsKey(BASIC_AUTH_KEY))
{ {
AuthAPI auth = new AuthAPI(metaData.getBaseUrl(), metaData.getClientId(), metaData.getClientSecret()); AuthAPI auth = AuthAPI.newBuilder(metaData.getBaseUrl(), metaData.getClientId(), metaData.getClientSecret()).build();
try try
{ {
///////////////////////////////////////////////// /////////////////////////////////////////////////

View File

@ -902,7 +902,93 @@ public class QJavalinApiHandler
List<Map<String, Serializable>> response = ApiImplementation.bulkInsert(apiInstanceMetaData, version, tableApiName, context.body()); List<Map<String, Serializable>> response = ApiImplementation.bulkInsert(apiInstanceMetaData, version, tableApiName, context.body());
QJavalinAccessLogger.logEndSuccess(logPair("recordCount", response.size())); setupSession(context, insertInput, version, apiInstanceMetaData);
QJavalinAccessLogger.logStart("apiBulkInsert", logPair("table", tableName));
insertInput.setTableName(tableName);
PermissionsHelper.checkTablePermissionThrowing(insertInput, TablePermissionSubType.INSERT);
/////////////////
// build input //
/////////////////
try
{
if(!StringUtils.hasContent(context.body()))
{
throw (new QBadRequestException("Missing required POST body"));
}
ArrayList<QRecord> recordList = new ArrayList<>();
insertInput.setRecords(recordList);
JSONTokener jsonTokener = new JSONTokener(context.body().trim());
JSONArray jsonArray = new JSONArray(jsonTokener);
for(int i = 0; i < jsonArray.length(); i++)
{
JSONObject jsonObject = jsonArray.getJSONObject(i);
recordList.add(QRecordApiAdapter.apiJsonObjectToQRecord(jsonObject, tableName, apiInstanceMetaData.getName(), version, false));
}
if(jsonTokener.more())
{
throw (new QBadRequestException("Body contained more than a single JSON array."));
}
if(recordList.isEmpty())
{
throw (new QBadRequestException("No records were found in the POST body"));
}
}
catch(QBadRequestException qbre)
{
throw (qbre);
}
catch(Exception e)
{
throw (new QBadRequestException("Body could not be parsed as a JSON array: " + e.getMessage(), e));
}
//////////////
// execute! //
//////////////
InsertAction insertAction = new InsertAction();
InsertOutput insertOutput = insertAction.execute(insertInput);
///////////////////////////////////////
// process records to build response //
///////////////////////////////////////
List<Map<String, Serializable>> response = new ArrayList<>();
for(QRecord record : insertOutput.getRecords())
{
LinkedHashMap<String, Serializable> outputRecord = new LinkedHashMap<>();
response.add(outputRecord);
List<String> errors = record.getErrors();
List<String> warnings = record.getWarnings();
if(CollectionUtils.nullSafeHasContents(errors))
{
outputRecord.put("statusCode", HttpStatus.Code.BAD_REQUEST.getCode());
outputRecord.put("statusText", HttpStatus.Code.BAD_REQUEST.getMessage());
outputRecord.put("error", "Error inserting " + table.getLabel() + ": " + StringUtils.joinWithCommasAndAnd(errors));
}
else if(CollectionUtils.nullSafeHasContents(warnings))
{
outputRecord.put("statusCode", HttpStatus.Code.BAD_REQUEST.getCode());
outputRecord.put("statusText", HttpStatus.Code.BAD_REQUEST.getMessage());
outputRecord.put("error", "Warning inserting " + table.getLabel() + ", some data may have been inserted: " + StringUtils.joinWithCommasAndAnd(warnings));
}
else
{
outputRecord.put("statusCode", HttpStatus.Code.CREATED.getCode());
outputRecord.put("statusText", HttpStatus.Code.CREATED.getMessage());
outputRecord.put(table.getPrimaryKeyField(), record.getValue(table.getPrimaryKeyField()));
}
}
QJavalinAccessLogger.logEndSuccess(logPair("recordCount", insertInput.getRecords().size()));
context.status(HttpStatus.Code.MULTI_STATUS.getCode()); context.status(HttpStatus.Code.MULTI_STATUS.getCode());
String resultString = JsonUtils.toJson(response); String resultString = JsonUtils.toJson(response);
context.result(resultString); context.result(resultString);

View File

@ -687,6 +687,10 @@ public class QJavalinImplementation
{ {
throw (new QUserFacingException("Error inserting " + qInstance.getTable(tableName).getLabel() + ": " + insertOutput.getRecords().get(0).getErrors().get(0))); throw (new QUserFacingException("Error inserting " + qInstance.getTable(tableName).getLabel() + ": " + insertOutput.getRecords().get(0).getErrors().get(0)));
} }
if(CollectionUtils.nullSafeHasContents(insertOutput.getRecords().get(0).getWarnings()))
{
throw (new QUserFacingException("Warning inserting " + qInstance.getTable(tableName).getLabel() + ": " + insertOutput.getRecords().get(0).getWarnings().get(0)));
}
QJavalinAccessLogger.logEndSuccess(logPair("primaryKey", () -> (insertOutput.getRecords().get(0).getValue(qInstance.getTable(tableName).getPrimaryKeyField())))); QJavalinAccessLogger.logEndSuccess(logPair("primaryKey", () -> (insertOutput.getRecords().get(0).getValue(qInstance.getTable(tableName).getPrimaryKeyField()))));
context.result(JsonUtils.toJson(insertOutput)); context.result(JsonUtils.toJson(insertOutput));