diff --git a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementationTest.java b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementationTest.java index 84382e57..8adbf274 100644 --- a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementationTest.java +++ b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementationTest.java @@ -31,6 +31,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException; import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat; import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType; @@ -556,7 +557,59 @@ class QJavalinImplementationTest extends QJavalinTestBase ** *******************************************************************************/ @Test - public void test_dataInsertMultipartForm() throws IOException + public void test_dataInsertMultipartForm() throws IOException, QException + { + HttpResponse response = Unirest.post(BASE_URL + "/data/person") + .header("Content-Type", "application/json") + .multiPartContent() + .field("firstName", "Bobby") + .field("lastName", "Hull") + .field("email", "bobby@hull.com") + .field("associations", """ + { + "pets": + [ + {"name": "Fido", "species": "dog"} + ] + } + """) + .asString(); + + assertEquals(200, response.getStatus()); + JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody()); + assertTrue(jsonObject.has("records")); + JSONArray records = jsonObject.getJSONArray("records"); + assertEquals(1, records.length()); + JSONObject record0 = records.getJSONObject(0); + Integer newPersonId = record0.getJSONObject("values").getInt("id"); + + ////////////////////////////////////////////////////////////////////////// + // get all the pets - assert a new one was inserted for this new person // + ////////////////////////////////////////////////////////////////////////// + HttpResponse petGetResponse = Unirest.get(BASE_URL + "/data/pet").asString(); + assertEquals(200, petGetResponse.getStatus()); + JSONObject petsJsonObject = JsonUtils.toJSONObject(petGetResponse.getBody()); + JSONArray petRecords = petsJsonObject.getJSONArray("records"); + boolean foundPetForNewPerson = false; + for(int i = 0; i < petRecords.length(); i++) + { + if(newPersonId.equals(petRecords.getJSONObject(i).getJSONObject("values").getInt("ownerPersonId"))) + { + assertEquals("Fido", petRecords.getJSONObject(i).getJSONObject("values").getString("name")); + foundPetForNewPerson = true; + } + } + assertTrue(foundPetForNewPerson); + } + + + + /******************************************************************************* + ** test an insert - posting a multipart form - including associations! + ** + *******************************************************************************/ + @Test + public void test_dataInsertMultipartFormWithAssocitions() throws IOException { try(InputStream photoInputStream = getClass().getResourceAsStream("/photo.png")) { @@ -972,6 +1025,44 @@ class QJavalinImplementationTest extends QJavalinTestBase + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testTimeZoneHeaders() + { + { + HttpResponse response = Unirest.get(BASE_URL + "/widget/timezoneWidget") + .header("X-QQQ-UserTimezoneOffsetMinutes", "300") + .header("X-QQQ-UserTimezone", "US/Central") + .asString(); + + JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody()); + assertEquals("300|US/Central", jsonObject.getString("html")); + } + + { + HttpResponse response = Unirest.get(BASE_URL + "/widget/timezoneWidget") + .header("X-QQQ-UserTimezoneOffsetMinutes", "-600") + .header("X-QQQ-UserTimezone", "SomeZone") + .asString(); + + JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody()); + assertEquals("-600|SomeZone", jsonObject.getString("html")); + } + + { + HttpResponse response = Unirest.get(BASE_URL + "/widget/timezoneWidget") + .header("X-QQQ-UserTimezoneOffsetMinutes", "foo") + .asString(); + + JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody()); + assertEquals("null|null", jsonObject.getString("html")); + } + } + + + /******************************************************************************* ** *******************************************************************************/ diff --git a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/TestUtils.java b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/TestUtils.java index fd9eb11a..1920e0e5 100644 --- a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/TestUtils.java +++ b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/TestUtils.java @@ -30,8 +30,10 @@ import java.util.Objects; import java.util.Optional; import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizerInterface; import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers; +import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; 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; import com.kingsrook.qqq.backend.core.exceptions.QValueException; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; @@ -41,6 +43,10 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperat 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.update.UpdateInput; +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.dashboard.widgets.RawHTML; +import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType; import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType; import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; @@ -71,9 +77,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData; import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportView; import com.kingsrook.qqq.backend.core.model.metadata.reporting.ReportType; import com.kingsrook.qqq.backend.core.model.metadata.tables.AssociatedScript; +import com.kingsrook.qqq.backend.core.model.metadata.tables.Association; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import com.kingsrook.qqq.backend.core.model.savedviews.SavedViewsMetaDataProvider; import com.kingsrook.qqq.backend.core.model.scripts.ScriptsMetaDataProvider; +import com.kingsrook.qqq.backend.core.model.session.QSession; import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage; import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule; import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep; @@ -93,6 +101,7 @@ public class TestUtils public static final String BACKEND_NAME_MEMORY = "memory"; public static final String TABLE_NAME_PERSON = "person"; + public static final String TABLE_NAME_PET = "pet"; public static final String PROCESS_NAME_GREET_PEOPLE_INTERACTIVE = "greetInteractive"; public static final String PROCESS_NAME_SIMPLE_SLEEP = "simpleSleep"; @@ -157,7 +166,9 @@ public class TestUtils qInstance.setAuthentication(defineAuthentication()); qInstance.addBackend(defineDefaultH2Backend()); qInstance.addTable(defineTablePerson()); + qInstance.addTable(defineTablePet()); qInstance.addJoin(definePersonJoinPartnerPerson()); + qInstance.addJoin(definePersonJoinPet()); qInstance.addProcess(defineProcessGreetPeople()); qInstance.addProcess(defineProcessGreetPeopleInteractive()); qInstance.addProcess(defineProcessSimpleSleep()); @@ -191,6 +202,12 @@ public class TestUtils qInstance.addWidget(new QWidgetMetaData() .withName(PersonsByCreateDateBarChart.class.getSimpleName()) .withCodeReference(new QCodeReference(PersonsByCreateDateBarChart.class))); + + qInstance.addWidget(new QWidgetMetaData() + .withName("timezoneWidget") + .withType(WidgetType.HTML.getType()) + .withCodeReference(new QCodeReference(TimezoneWidgetRenderer.class))); + } @@ -263,6 +280,7 @@ public class TestUtils .withField(new QFieldMetaData("testScriptId", QFieldType.INTEGER).withBackendName("test_script_id")) .withField(new QFieldMetaData("photo", QFieldType.BLOB).withBackendName("photo")) .withField(new QFieldMetaData("photoFileName", QFieldType.STRING).withBackendName("photo_file_name")) + .withAssociation(new Association().withName("pets").withJoinName("personJoinPet").withAssociatedTableName(TABLE_NAME_PET)) .withAssociatedScript(new AssociatedScript() .withFieldName("testScriptId") .withScriptTypeId(1) @@ -282,6 +300,31 @@ public class TestUtils + /******************************************************************************* + ** Define the pet table + ** + *******************************************************************************/ + public static QTableMetaData defineTablePet() + { + QTableMetaData qTableMetaData = new QTableMetaData() + .withName(TABLE_NAME_PET) + .withLabel("Pet") + .withRecordLabelFormat("%s") + .withRecordLabelFields("name") + .withBackendName(defineDefaultH2Backend().getName()) + .withPrimaryKeyField("id") + .withField(new QFieldMetaData("id", QFieldType.INTEGER)) + .withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withBackendName("create_date")) + .withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME).withBackendName("modify_date")) + .withField(new QFieldMetaData("ownerPersonId", QFieldType.INTEGER).withBackendName("owner_person_id")) + .withField(new QFieldMetaData("name", QFieldType.STRING).withBackendName("name")) + .withField(new QFieldMetaData("species", QFieldType.STRING).withBackendName("species")); + + return (qTableMetaData); + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -343,6 +386,21 @@ public class TestUtils + /******************************************************************************* + ** + *******************************************************************************/ + public static QJoinMetaData definePersonJoinPet() + { + return (new QJoinMetaData() + .withLeftTable(TABLE_NAME_PERSON) + .withRightTable(TABLE_NAME_PET) + .withType(JoinType.ONE_TO_MANY) + .withName("personJoinPet") + .withJoinOn(new JoinOn("id", "ownerPersonId"))); + } + + + /******************************************************************************* ** Define the 'greet people' process *******************************************************************************/ @@ -613,4 +671,24 @@ public class TestUtils new InsertAction().execute(insertInput); } + + + /*************************************************************************** + ** + ***************************************************************************/ + public static class TimezoneWidgetRenderer extends AbstractWidgetRenderer + { + + /*************************************************************************** + ** + ***************************************************************************/ + @Override + public RenderWidgetOutput render(RenderWidgetInput input) throws QException + { + return (new RenderWidgetOutput(new RawHTML("title", + QContext.getQSession().getValue(QSession.VALUE_KEY_USER_TIMEZONE_OFFSET_MINUTES) + + "|" + QContext.getQSession().getValue(QSession.VALUE_KEY_USER_TIMEZONE) + ))); + } + } } diff --git a/qqq-middleware-javalin/src/test/resources/prime-test-database.sql b/qqq-middleware-javalin/src/test/resources/prime-test-database.sql index bd233046..06e306e0 100644 --- a/qqq-middleware-javalin/src/test/resources/prime-test-database.sql +++ b/qqq-middleware-javalin/src/test/resources/prime-test-database.sql @@ -42,3 +42,18 @@ INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (3, 'Ti INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (4, 'Tyler', 'Samples', '1990-01-01', 'tsamples@mmltholdings.com'); INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (5, 'Garret', 'Richardson', '1981-01-01', 'grichardson@mmltholdings.com'); INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (6, 'Linda', 'Kelkhoff', '1976-01-01', 'not-linda.kelkhoff@gmail.com'); + +DROP TABLE IF EXISTS pet; +CREATE TABLE pet +( + id INT AUTO_INCREMENT, + create_date TIMESTAMP DEFAULT now(), + modify_date TIMESTAMP DEFAULT now(), + + name VARCHAR(80) NOT NULL, + species VARCHAR(80) NOT NULL, + owner_person_id INT +); + +INSERT INTO pet (id, name, species, owner_person_id) VALUES (1, 'Chester', 'dog', 1); +INSERT INTO pet (id, name, species, owner_person_id) VALUES (2, 'Lucy', 'dog', 1);