Merge remote-tracking branch 'origin/integration/sprint-28' into feature/CTLE-503-optimization-weather-api-data

# Conflicts:
#	qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/QueryAction.java
#	qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendTableMetaData.java
#	qqq-backend-module-api/src/main/java/com/kingsrook/qqq/backend/module/api/actions/BaseAPIActionUtil.java
#	qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/QRecordApiAdapter.java
This commit is contained in:
2023-07-03 15:38:55 -05:00
104 changed files with 7092 additions and 516 deletions

View File

@ -34,6 +34,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;
@ -634,8 +635,50 @@ 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:
@ -781,7 +824,7 @@ public class BaseAPIActionUtil
** Helper method to create a value for an Authentication header, using just a
** username & password - encoded as Basic + base64(username:password)
*******************************************************************************/
protected String getBasicAuthenticationHeader(String username, String password)
public String getBasicAuthenticationHeader(String username, String password)
{
return "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
}

View File

@ -66,6 +66,8 @@ public class TestUtils
qInstance.addBackend(defineEasypostBackend());
qInstance.addTable(defineTableEasypostTracker());
qInstance.addTable(defineVariant());
return (qInstance);
}
@ -151,6 +153,29 @@ public class TestUtils
/*******************************************************************************
**
*******************************************************************************/
private static QTableMetaData defineVariant()
{
return (new QTableMetaData()
.withName("variant")
.withBackendName(MEMORY_BACKEND_NAME)
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
.withField(new QFieldMetaData("type", QFieldType.STRING))
.withField(new QFieldMetaData("apiKey", QFieldType.STRING))
.withField(new QFieldMetaData("username", QFieldType.STRING))
.withField(new QFieldMetaData("password", QFieldType.STRING))
.withPrimaryKeyField("id")
.withBackendDetails(new APITableBackendDetails()
.withTablePath("variant")
.withTableWrapperObjectName("variant")
)
);
}
/*******************************************************************************
**
*******************************************************************************/

View File

@ -22,12 +22,14 @@
package com.kingsrook.qqq.backend.module.api.actions;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
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.CountAction;
import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction;
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
@ -36,6 +38,7 @@ import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
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;
@ -59,6 +62,7 @@ import com.kingsrook.qqq.backend.module.api.model.OutboundAPILog;
import com.kingsrook.qqq.backend.module.api.model.OutboundAPILogMetaDataProvider;
import com.kingsrook.qqq.backend.module.api.model.metadata.APIBackendMetaData;
import org.apache.http.Header;
import org.apache.http.client.methods.HttpGet;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.jupiter.api.BeforeEach;
@ -81,11 +85,21 @@ class BaseAPIActionUtilTest extends BaseTest
**
*******************************************************************************/
@BeforeEach
void beforeEach()
void beforeEach() throws QException
{
mockApiUtilsHelper = new MockApiUtilsHelper();
mockApiUtilsHelper.setUseMock(true);
MockApiActionUtils.mockApiUtilsHelper = mockApiUtilsHelper;
QueryInput queryInput = new QueryInput();
queryInput.setTableName("variant");
QueryOutput output = new QueryAction().execute(queryInput);
List<Serializable> ids = output.getRecords().stream().map(r -> r.getValue("id")).toList();
DeleteInput deleteInput = new DeleteInput();
deleteInput.setTableName("variant");
deleteInput.setPrimaryKeys(ids);
new DeleteAction().execute(deleteInput);
}
@ -603,6 +617,72 @@ class BaseAPIActionUtilTest extends BaseTest
/*******************************************************************************
**
*******************************************************************************/
@Test
void testBackendWithVariantsApiKey() throws QException
{
APIBackendMetaData backend = (APIBackendMetaData) QContext.getQInstance().getBackend(TestUtils.MOCK_BACKEND_NAME);
backend.setAuthorizationType(AuthorizationType.API_KEY_HEADER);
backend.setUsesVariants(true);
backend.setVariantOptionsTableName("variant");
backend.setVariantOptionsTableIdField("id");
backend.setVariantOptionsTableApiKeyField("apiKey");
backend.setVariantOptionsTableTypeValue("API_KEY_TYPE");
InsertInput insertInput = new InsertInput();
insertInput.setTableName("variant");
insertInput.setRecords(List.of(new QRecord()
.withValue("type", "API_KEY_TYPE")
.withValue("apiKey", "abcdefg1234567")));
InsertOutput insertOutput = new InsertAction().execute(insertInput);
QContext.getQSession().setBackendVariants(Map.of("API_KEY_TYPE", insertOutput.getRecords().get(0).getValue("id")));
HttpGet httpGet = new HttpGet();
BaseAPIActionUtil util = new BaseAPIActionUtil();
util.setBackendMetaData(backend);
util.setupAuthorizationInRequest(httpGet);
Header authHeader = httpGet.getFirstHeader("API-Key");
assertTrue(authHeader.getValue().startsWith("abcde"));
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testBackendWithVariantsUsernamePassword() throws QException
{
APIBackendMetaData backend = (APIBackendMetaData) QContext.getQInstance().getBackend(TestUtils.MOCK_BACKEND_NAME);
backend.setAuthorizationType(AuthorizationType.BASIC_AUTH_USERNAME_PASSWORD);
backend.setUsesVariants(true);
backend.setVariantOptionsTableName("variant");
backend.setVariantOptionsTableIdField("id");
backend.setVariantOptionsTableUsernameField("username");
backend.setVariantOptionsTablePasswordField("password");
backend.setVariantOptionsTableTypeValue("USER_PASS");
InsertInput insertInput = new InsertInput();
insertInput.setTableName("variant");
insertInput.setRecords(List.of(new QRecord()
.withValue("type", "USER_PASS")
.withValue("username", "user")
.withValue("password", "pass")));
InsertOutput insertOutput = new InsertAction().execute(insertInput);
QContext.getQSession().setBackendVariants(Map.of("USER_PASS", insertOutput.getRecords().get(0).getValue("id")));
HttpGet httpGet = new HttpGet();
BaseAPIActionUtil util = new BaseAPIActionUtil();
util.setBackendMetaData(backend);
util.setupAuthorizationInRequest(httpGet);
Header authHeader = httpGet.getFirstHeader("Authorization");
assertTrue(authHeader.getValue().equals(util.getBasicAuthenticationHeader("user", "pass")));
}
/*******************************************************************************
**
*******************************************************************************/