mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-21 22:48:44 +00:00
Merged dev into integration/sprint-35
This commit is contained in:
@ -91,20 +91,6 @@ public class DMLAuditAction extends AbstractQActionFunction<DMLAuditInput, DMLAu
|
|||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
DMLType dmlType = getDMLType(tableActionInput);
|
DMLType dmlType = getDMLType(tableActionInput);
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// currently, the table's primary key must be integer... so, log (once) and return early if not that //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
QFieldMetaData field = table.getField(table.getPrimaryKeyField());
|
|
||||||
if(!QFieldType.INTEGER.equals(field.getType()))
|
|
||||||
{
|
|
||||||
if(!loggedUnauditableTableNames.contains(table.getName()))
|
|
||||||
{
|
|
||||||
LOG.info("Cannot audit table without integer as its primary key", logPair("tableName", table.getName()));
|
|
||||||
loggedUnauditableTableNames.add(table.getName());
|
|
||||||
}
|
|
||||||
return (output);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
List<QRecord> recordList = CollectionUtils.nonNullList(input.getRecordList()).stream()
|
List<QRecord> recordList = CollectionUtils.nonNullList(input.getRecordList()).stream()
|
||||||
@ -119,6 +105,21 @@ public class DMLAuditAction extends AbstractQActionFunction<DMLAuditInput, DMLAu
|
|||||||
return (output);
|
return (output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// currently, the table's primary key must be integer... so, log (once) and return early if not that //
|
||||||
|
// (or, if no primary key!) //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
QFieldMetaData field = table.getFields().get(table.getPrimaryKeyField());
|
||||||
|
if(field == null || !QFieldType.INTEGER.equals(field.getType()))
|
||||||
|
{
|
||||||
|
if(!loggedUnauditableTableNames.contains(table.getName()))
|
||||||
|
{
|
||||||
|
LOG.info("Cannot audit table without integer as its primary key", logPair("tableName", table.getName()));
|
||||||
|
loggedUnauditableTableNames.add(table.getName());
|
||||||
|
}
|
||||||
|
return (output);
|
||||||
|
}
|
||||||
|
|
||||||
String contextSuffix = getContentSuffix(input);
|
String contextSuffix = getContentSuffix(input);
|
||||||
|
|
||||||
AuditInput auditInput = new AuditInput();
|
AuditInput auditInput = new AuditInput();
|
||||||
|
@ -186,7 +186,7 @@ public class QRecord implements Serializable
|
|||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// we know entry is serializable at this point, based on type param's bound //
|
// we know entry is serializable at this point, based on type param's bound //
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
LOG.info("Non-primitive serializable value in QRecord - calling SerializationUtils.clone...", logPair("key", entry.getKey()), logPair("type", value.getClass()));
|
LOG.debug("Non-primitive serializable value in QRecord - calling SerializationUtils.clone...", logPair("key", entry.getKey()), logPair("type", value.getClass()));
|
||||||
clone.put(entry.getKey(), (V) SerializationUtils.clone(entry.getValue()));
|
clone.put(entry.getKey(), (V) SerializationUtils.clone(entry.getValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,7 @@ public class Auth0AuthenticationModule implements QAuthenticationModuleInterface
|
|||||||
// process a sessionUUID - looks up userSession record - cannot create token this way. //
|
// process a sessionUUID - looks up userSession record - cannot create token this way. //
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
String sessionUUID = context.get(SESSION_UUID_KEY);
|
String sessionUUID = context.get(SESSION_UUID_KEY);
|
||||||
LOG.info("Creating session from sessionUUID (userSession)", logPair("sessionUUID", maskForLog(sessionUUID)));
|
LOG.debug("Creating session from sessionUUID (userSession)", logPair("sessionUUID", maskForLog(sessionUUID)));
|
||||||
if(sessionUUID != null)
|
if(sessionUUID != null)
|
||||||
{
|
{
|
||||||
accessToken = getAccessTokenFromSessionUUID(metaData, sessionUUID);
|
accessToken = getAccessTokenFromSessionUUID(metaData, sessionUUID);
|
||||||
|
@ -276,6 +276,7 @@ public abstract class AbstractTableSyncTransformStep extends AbstractTransformSt
|
|||||||
|
|
||||||
if(sourceKeyValue == null || "".equals(sourceKeyValue))
|
if(sourceKeyValue == null || "".equals(sourceKeyValue))
|
||||||
{
|
{
|
||||||
|
LOG.debug("Skipping record without a value in the sourceKeyField", logPair("keyField", sourceTableKeyField));
|
||||||
errorMissingKeyField.incrementCountAndAddPrimaryKey(sourcePrimaryKey);
|
errorMissingKeyField.incrementCountAndAddPrimaryKey(sourcePrimaryKey);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -176,6 +176,19 @@ public class StringUtils
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** safely appends a string to another, changing empty string if either value is null
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static String safeAppend(String input, String contentToAppend)
|
||||||
|
{
|
||||||
|
input = input != null ? input : "";
|
||||||
|
contentToAppend = contentToAppend != null ? contentToAppend : "";
|
||||||
|
return input + contentToAppend;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** returns input if not null, or nullOutput if input == null (as in SQL NVL)
|
** returns input if not null, or nullOutput if input == null (as in SQL NVL)
|
||||||
**
|
**
|
||||||
|
@ -400,4 +400,49 @@ class DMLAuditActionTest extends BaseTest
|
|||||||
QContext.popAction();
|
QContext.popAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testTableWithoutIntegerPrimaryKey() throws QException
|
||||||
|
{
|
||||||
|
QInstance qInstance = QContext.getQInstance();
|
||||||
|
new AuditsMetaDataProvider().defineAll(qInstance, TestUtils.MEMORY_BACKEND_NAME, null);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// we used to throw if table had no primary key. first, assert that we do not throw in that case //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
QContext.getQInstance().addTable(
|
||||||
|
new QTableMetaData()
|
||||||
|
.withName("nullPkey")
|
||||||
|
.withField(new QFieldMetaData("foo", QFieldType.STRING))
|
||||||
|
.withAuditRules(new QAuditRules().withAuditLevel(AuditLevel.FIELD)));
|
||||||
|
|
||||||
|
new DMLAuditAction().execute(new DMLAuditInput()
|
||||||
|
.withTableActionInput(new InsertInput("nullPkey"))
|
||||||
|
.withRecordList(List.of(new QRecord())));
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// next, make sure we don't throw (and don't record anything) if table's pkey isn't integer //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
QContext.getQInstance().addTable(
|
||||||
|
new QTableMetaData()
|
||||||
|
.withName("stringPkey")
|
||||||
|
.withField(new QFieldMetaData("idString", QFieldType.STRING))
|
||||||
|
.withPrimaryKeyField("idString")
|
||||||
|
.withAuditRules(new QAuditRules().withAuditLevel(AuditLevel.FIELD)));
|
||||||
|
|
||||||
|
new DMLAuditAction().execute(new DMLAuditInput()
|
||||||
|
.withTableActionInput(new InsertInput("stringPkey"))
|
||||||
|
.withRecordList(List.of(new QRecord())));
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
// make sure no audits happened //
|
||||||
|
//////////////////////////////////
|
||||||
|
List<QRecord> auditList = TestUtils.queryTable("audit");
|
||||||
|
assertTrue(auditList.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,20 @@ class StringUtilsTest extends BaseTest
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void test_safeAppend()
|
||||||
|
{
|
||||||
|
assertEquals("Foo", StringUtils.safeAppend("Foo", null));
|
||||||
|
assertEquals("Foo", StringUtils.safeAppend(null, "Foo"));
|
||||||
|
assertEquals("FooBar", StringUtils.safeAppend("Foo", "Bar"));
|
||||||
|
assertEquals("", StringUtils.safeAppend(null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -96,6 +96,7 @@ import org.apache.http.impl.client.HttpClientBuilder;
|
|||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.impl.client.HttpClients;
|
||||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||||
import org.apache.http.util.EntityUtils;
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.apache.logging.log4j.Level;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
||||||
@ -709,11 +710,11 @@ public class BaseAPIActionUtil
|
|||||||
|
|
||||||
if(backendMetaData.getAuthorizationType().equals(AuthorizationType.BASIC_AUTH_USERNAME_PASSWORD))
|
if(backendMetaData.getAuthorizationType().equals(AuthorizationType.BASIC_AUTH_USERNAME_PASSWORD))
|
||||||
{
|
{
|
||||||
request.addHeader("Authorization", getBasicAuthenticationHeader(record.getValueString(backendMetaData.getVariantOptionsTableUsernameField()), record.getValueString(backendMetaData.getVariantOptionsTablePasswordField())));
|
request.setHeader("Authorization", getBasicAuthenticationHeader(record.getValueString(backendMetaData.getVariantOptionsTableUsernameField()), record.getValueString(backendMetaData.getVariantOptionsTablePasswordField())));
|
||||||
}
|
}
|
||||||
else if(backendMetaData.getAuthorizationType().equals(AuthorizationType.API_KEY_HEADER))
|
else if(backendMetaData.getAuthorizationType().equals(AuthorizationType.API_KEY_HEADER))
|
||||||
{
|
{
|
||||||
request.addHeader("API-Key", record.getValueString(backendMetaData.getVariantOptionsTableApiKeyField()));
|
request.setHeader("API-Key", record.getValueString(backendMetaData.getVariantOptionsTableApiKeyField()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -727,10 +728,10 @@ public class BaseAPIActionUtil
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
switch(backendMetaData.getAuthorizationType())
|
switch(backendMetaData.getAuthorizationType())
|
||||||
{
|
{
|
||||||
case BASIC_AUTH_API_KEY -> request.addHeader("Authorization", getBasicAuthenticationHeader(backendMetaData.getApiKey()));
|
case BASIC_AUTH_API_KEY -> request.setHeader("Authorization", getBasicAuthenticationHeader(backendMetaData.getApiKey()));
|
||||||
case BASIC_AUTH_USERNAME_PASSWORD -> request.addHeader("Authorization", getBasicAuthenticationHeader(backendMetaData.getUsername(), backendMetaData.getPassword()));
|
case BASIC_AUTH_USERNAME_PASSWORD -> request.setHeader("Authorization", getBasicAuthenticationHeader(backendMetaData.getUsername(), backendMetaData.getPassword()));
|
||||||
case API_KEY_HEADER -> request.addHeader("API-Key", backendMetaData.getApiKey());
|
case API_KEY_HEADER -> request.setHeader("API-Key", backendMetaData.getApiKey());
|
||||||
case API_TOKEN -> request.addHeader("Authorization", "Token " + backendMetaData.getApiKey());
|
case API_TOKEN -> request.setHeader("Authorization", "Token " + backendMetaData.getApiKey());
|
||||||
case OAUTH2 -> request.setHeader("Authorization", "Bearer " + getOAuth2Token());
|
case OAUTH2 -> request.setHeader("Authorization", "Bearer " + getOAuth2Token());
|
||||||
case API_KEY_QUERY_PARAM ->
|
case API_KEY_QUERY_PARAM ->
|
||||||
{
|
{
|
||||||
@ -786,9 +787,9 @@ public class BaseAPIActionUtil
|
|||||||
|
|
||||||
if(setCredentialsInHeader)
|
if(setCredentialsInHeader)
|
||||||
{
|
{
|
||||||
request.addHeader("Authorization", getBasicAuthenticationHeader(backendMetaData.getClientId(), backendMetaData.getClientSecret()));
|
request.setHeader("Authorization", getBasicAuthenticationHeader(backendMetaData.getClientId(), backendMetaData.getClientSecret()));
|
||||||
}
|
}
|
||||||
request.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
|
request.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
|
||||||
|
|
||||||
HttpResponse response = executeOAuthTokenRequest(client, request);
|
HttpResponse response = executeOAuthTokenRequest(client, request);
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
int statusCode = response.getStatusLine().getStatusCode();
|
||||||
@ -850,7 +851,7 @@ public class BaseAPIActionUtil
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
protected void setupContentTypeInRequest(HttpRequestBase request)
|
protected void setupContentTypeInRequest(HttpRequestBase request)
|
||||||
{
|
{
|
||||||
request.addHeader("Content-Type", backendMetaData.getContentType());
|
request.setHeader("Content-Type", backendMetaData.getContentType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -872,7 +873,7 @@ public class BaseAPIActionUtil
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public void setupAdditionalHeaders(HttpRequestBase request)
|
public void setupAdditionalHeaders(HttpRequestBase request)
|
||||||
{
|
{
|
||||||
request.addHeader("Accept", "application/json");
|
request.setHeader("Accept", "application/json");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1081,7 +1082,7 @@ public class BaseAPIActionUtil
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// trim response body (just to keep logs smaller, or, in case someone consuming logs doesn't want such long lines) //
|
// trim response body (just to keep logs smaller, or, in case someone consuming logs doesn't want such long lines) //
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
LOG.info("Received successful response with code [" + qResponse.getStatusCode() + "] and content [" + StringUtils.safeTruncate(qResponse.getContent(), getMaxResponseMessageLengthForLog(), "...") + "].");
|
LOG.log(getAPIResponseLogLevel(), "Received successful response with code [" + qResponse.getStatusCode() + "] and content [" + StringUtils.safeTruncate(qResponse.getContent(), getMaxResponseMessageLengthForLog(), "...") + "].");
|
||||||
return (qResponse);
|
return (qResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1507,4 +1508,14 @@ public class BaseAPIActionUtil
|
|||||||
// nothing to do at this layer, meant to be overridden by subclasses //
|
// nothing to do at this layer, meant to be overridden by subclasses //
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
protected Level getAPIResponseLogLevel() throws QException
|
||||||
|
{
|
||||||
|
return (Level.DEBUG);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user