From 8ca59e0a5bf22a019b6f20fbabdd56e15e1ba114 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Wed, 1 May 2024 16:53:12 -0500 Subject: [PATCH] CE-1068 - Move validateEmailAddresses to utils class; add validation when creating scheduled report --- .../ScheduledReportTableCustomizer.java | 20 ++++++ .../RenderSavedReportExecuteStep.java | 42 +---------- .../backend/core/utils/ValidationUtils.java | 72 +++++++++++++++++++ .../core/utils/ValidationUtilsTest.java | 62 ++++++++++++++++ 4 files changed, 156 insertions(+), 40 deletions(-) create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/utils/ValidationUtils.java create mode 100644 qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/utils/ValidationUtilsTest.java diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReportTableCustomizer.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReportTableCustomizer.java index a2a901ca..b7d339f7 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReportTableCustomizer.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/savedreports/ScheduledReportTableCustomizer.java @@ -31,6 +31,7 @@ import com.kingsrook.qqq.backend.core.actions.processes.QProcessCallbackFactory; import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction; import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction; import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput; @@ -46,6 +47,8 @@ import com.kingsrook.qqq.backend.core.model.scheduledjobs.ScheduledJob; import com.kingsrook.qqq.backend.core.model.statusmessages.BadInputStatusMessage; import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.StreamedETLWithFrontendProcess; import com.kingsrook.qqq.backend.core.utils.CollectionUtils; +import com.kingsrook.qqq.backend.core.utils.StringUtils; +import com.kingsrook.qqq.backend.core.utils.ValidationUtils; import org.quartz.CronScheduleBuilder; import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; @@ -99,6 +102,23 @@ public class ScheduledReportTableCustomizer implements TableCustomizerInterface { record.addError(new BadInputStatusMessage("Cron Expression [" + cronExpression + "] is not valid: " + e.getMessage())); } + + try + { + String toAddresses = record.getValueString("toAddresses"); + if(StringUtils.hasContent(toAddresses)) + { + ValidationUtils.parseAndValidateEmailAddresses(toAddresses); + } + } + catch(QUserFacingException ufe) + { + record.addError(new BadInputStatusMessage(ufe.getMessage())); + } + catch(Exception e) + { + record.addError(new BadInputStatusMessage("To Addresses is not valid: " + e.getMessage())); + } } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/savedreports/RenderSavedReportExecuteStep.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/savedreports/RenderSavedReportExecuteStep.java index adc0f3cc..d875b0aa 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/savedreports/RenderSavedReportExecuteStep.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/savedreports/RenderSavedReportExecuteStep.java @@ -30,7 +30,6 @@ import java.time.LocalTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.UUID; @@ -42,7 +41,6 @@ import com.kingsrook.qqq.backend.core.actions.tables.StorageAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; -import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.model.actions.messaging.Content; import com.kingsrook.qqq.backend.core.model.actions.messaging.MultiParty; @@ -68,7 +66,7 @@ import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport; import com.kingsrook.qqq.backend.core.utils.CollectionUtils; import com.kingsrook.qqq.backend.core.utils.ExceptionUtils; import com.kingsrook.qqq.backend.core.utils.StringUtils; -import org.apache.commons.validator.EmailValidator; +import com.kingsrook.qqq.backend.core.utils.ValidationUtils; import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; @@ -111,7 +109,7 @@ public class RenderSavedReportExecuteStep implements BackendStep List toEmailAddressList = new ArrayList<>(); if(StringUtils.hasContent(sendToEmailAddress)) { - toEmailAddressList = validateEmailAddresses(sendToEmailAddress); + toEmailAddressList = ValidationUtils.parseAndValidateEmailAddresses(sendToEmailAddress); } StorageAction storageAction = new StorageAction(); @@ -222,42 +220,6 @@ public class RenderSavedReportExecuteStep implements BackendStep - /******************************************************************************* - ** - *******************************************************************************/ - private List validateEmailAddresses(String sendToEmailAddress) throws QUserFacingException - { - //////////////////////////////////////////////////////////////// - // split email address string on spaces, comma, and semicolon // - //////////////////////////////////////////////////////////////// - List toEmailAddressList = Arrays.asList(sendToEmailAddress.split("[\\s,;]+")); - - ////////////////////////////////////////////////////// - // check each address keeping track of any bad ones // - ////////////////////////////////////////////////////// - List invalidEmails = new ArrayList<>(); - EmailValidator validator = EmailValidator.getInstance(); - for(String emailAddress : toEmailAddressList) - { - if(!validator.isValid(emailAddress)) - { - invalidEmails.add(emailAddress); - } - } - - /////////////////////////////////////// - // if bad one found, throw exception // - /////////////////////////////////////// - if(!invalidEmails.isEmpty()) - { - throw (new QUserFacingException("The following email addresses were invalid: " + StringUtils.join(",", invalidEmails))); - } - - return (toEmailAddressList); - } - - - /******************************************************************************* ** *******************************************************************************/ diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/utils/ValidationUtils.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/utils/ValidationUtils.java new file mode 100644 index 00000000..4674f66f --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/utils/ValidationUtils.java @@ -0,0 +1,72 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2024. 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 . + */ + +package com.kingsrook.qqq.backend.core.utils; + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; +import org.apache.commons.validator.EmailValidator; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class ValidationUtils +{ + + /******************************************************************************* + ** + *******************************************************************************/ + public static List parseAndValidateEmailAddresses(String emailAddresses) throws QUserFacingException + { + //////////////////////////////////////////////////////////////// + // split email address string on spaces, comma, and semicolon // + //////////////////////////////////////////////////////////////// + List toEmailAddressList = Arrays.asList(emailAddresses.split("[\\s,;]+")); + + ////////////////////////////////////////////////////// + // check each address keeping track of any bad ones // + ////////////////////////////////////////////////////// + List invalidEmails = new ArrayList<>(); + EmailValidator validator = EmailValidator.getInstance(); + for(String emailAddress : toEmailAddressList) + { + if(!validator.isValid(emailAddress)) + { + invalidEmails.add(emailAddress); + } + } + + /////////////////////////////////////// + // if bad one found, throw exception // + /////////////////////////////////////// + if(!invalidEmails.isEmpty()) + { + throw (new QUserFacingException("The following email addresses were invalid: " + StringUtils.join(",", invalidEmails))); + } + + return (toEmailAddressList); + } + +} diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/utils/ValidationUtilsTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/utils/ValidationUtilsTest.java new file mode 100644 index 00000000..79ba0351 --- /dev/null +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/utils/ValidationUtilsTest.java @@ -0,0 +1,62 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2024. 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 . + */ + +package com.kingsrook.qqq.backend.core.utils; + + +import java.util.List; +import com.kingsrook.qqq.backend.core.BaseTest; +import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; + + +/******************************************************************************* + ** Unit test for ValidationUtils + *******************************************************************************/ +class ValidationUtilsTest extends BaseTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test() throws QUserFacingException + { + assertThatThrownBy(() -> ValidationUtils.parseAndValidateEmailAddresses("notEmail")) + .isInstanceOf(QUserFacingException.class) + .hasMessageContaining("email addresses were invalid: notEmail"); + + assertThatThrownBy(() -> ValidationUtils.parseAndValidateEmailAddresses("foo@bar.com, whatever")) + .isInstanceOf(QUserFacingException.class) + .hasMessageContaining("email addresses were invalid: whatever"); + + assertThatThrownBy(() -> ValidationUtils.parseAndValidateEmailAddresses("foo whatever")) + .isInstanceOf(QUserFacingException.class) + .hasMessageContaining("email addresses were invalid: foo,whatever"); + + assertEquals(List.of("foo@bar.com"), ValidationUtils.parseAndValidateEmailAddresses("foo@bar.com ")); // space here intentional! + assertEquals(List.of("foo@bar.com"), ValidationUtils.parseAndValidateEmailAddresses("foo@bar.com;")); + assertEquals(List.of("foo@bar.com", "fiz@buz.com"), ValidationUtils.parseAndValidateEmailAddresses("foo@bar.com, fiz@buz.com")); + } + +} \ No newline at end of file