From a591f5759192df166b81d46508ea26a0aeb9a746 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Tue, 13 Feb 2024 09:15:17 -0600 Subject: [PATCH] QQQ Messaging WIP/POC - Initial checkin --- qqq-backend-core/pom.xml | 6 + .../actions/messaging/SendMessageAction.java | 64 ++++ .../model/actions/messaging/Attachment.java | 95 ++++++ .../core/model/actions/messaging/Content.java | 95 ++++++ .../model/actions/messaging/ContentRole.java | 39 +++ .../model/actions/messaging/MultiParty.java | 92 ++++++ .../core/model/actions/messaging/Party.java | 127 ++++++++ .../model/actions/messaging/PartyRole.java | 39 +++ .../actions/messaging/SendMessageInput.java | 278 ++++++++++++++++++ .../actions/messaging/SendMessageOutput.java | 33 +++ .../messaging/email/EmailContentRole.java | 35 +++ .../messaging/email/EmailPartyRole.java | 38 +++ .../core/model/metadata/QInstance.java | 49 +++ .../messaging/QMessagingProviderMetaData.java | 110 +++++++ .../email/EmailMessagingProvider.java | 56 ++++ .../email/EmailMessagingProviderMetaData.java | 116 ++++++++ .../messaging/email/SendEmailAction.java | 194 ++++++++++++ .../messaging/MessagingProviderInterface.java | 46 +++ .../QMessagingProviderDispatcher.java | 123 ++++++++ .../email/EmailMessagingProviderTest.java | 65 ++++ .../qqq/backend/core/utils/TestUtils.java | 19 ++ 21 files changed, 1719 insertions(+) create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/messaging/SendMessageAction.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/Attachment.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/Content.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/ContentRole.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/MultiParty.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/Party.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/PartyRole.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/SendMessageInput.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/SendMessageOutput.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/email/EmailContentRole.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/email/EmailPartyRole.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/QMessagingProviderMetaData.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/EmailMessagingProvider.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/EmailMessagingProviderMetaData.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/SendEmailAction.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/modules/messaging/MessagingProviderInterface.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/modules/messaging/QMessagingProviderDispatcher.java create mode 100644 qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/EmailMessagingProviderTest.java diff --git a/qqq-backend-core/pom.xml b/qqq-backend-core/pom.xml index 26a4848f..2b6fb128 100644 --- a/qqq-backend-core/pom.xml +++ b/qqq-backend-core/pom.xml @@ -186,6 +186,12 @@ 2.23.0 + + com.sun.mail + jakarta.mail + 2.0.1 + + org.apache.maven.plugins diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/messaging/SendMessageAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/messaging/SendMessageAction.java new file mode 100644 index 00000000..f0cccf1e --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/messaging/SendMessageAction.java @@ -0,0 +1,64 @@ +/* + * 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.actions.messaging; + + +import com.kingsrook.qqq.backend.core.actions.AbstractQActionFunction; +import com.kingsrook.qqq.backend.core.context.QContext; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.messaging.SendMessageInput; +import com.kingsrook.qqq.backend.core.model.actions.messaging.SendMessageOutput; +import com.kingsrook.qqq.backend.core.model.metadata.messaging.QMessagingProviderMetaData; +import com.kingsrook.qqq.backend.core.modules.messaging.MessagingProviderInterface; +import com.kingsrook.qqq.backend.core.modules.messaging.QMessagingProviderDispatcher; +import com.kingsrook.qqq.backend.core.utils.StringUtils; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class SendMessageAction extends AbstractQActionFunction +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public SendMessageOutput execute(SendMessageInput input) throws QException + { + if(!StringUtils.hasContent(input.getMessagingProviderName())) + { + throw (new QException("Messaging provider name was not given in SendMessageInput.")); + } + + QMessagingProviderMetaData messagingProvider = QContext.getQInstance().getMessagingProvider(input.getMessagingProviderName()); + if(messagingProvider == null) + { + throw (new QException("Messaging provider named [" + input.getMessagingProviderName() + "] was not found in this QInstance.")); + } + + MessagingProviderInterface messagingProviderInterface = new QMessagingProviderDispatcher().getMessagingProviderInterface(messagingProvider.getType()); + + return (messagingProviderInterface.sendMessage(input)); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/Attachment.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/Attachment.java new file mode 100644 index 00000000..f3720fac --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/Attachment.java @@ -0,0 +1,95 @@ +/* + * 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.model.actions.messaging; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class Attachment +{ + private byte[] contents; + private String name; + + + + /******************************************************************************* + ** Getter for contents + *******************************************************************************/ + public byte[] getContents() + { + return (this.contents); + } + + + + /******************************************************************************* + ** Setter for contents + *******************************************************************************/ + public void setContents(byte[] contents) + { + this.contents = contents; + } + + + + /******************************************************************************* + ** Fluent setter for contents + *******************************************************************************/ + public Attachment withContents(byte[] contents) + { + this.contents = contents; + return (this); + } + + + + /******************************************************************************* + ** Getter for name + *******************************************************************************/ + public String getName() + { + return (this.name); + } + + + + /******************************************************************************* + ** Setter for name + *******************************************************************************/ + public void setName(String name) + { + this.name = name; + } + + + + /******************************************************************************* + ** Fluent setter for name + *******************************************************************************/ + public Attachment withName(String name) + { + this.name = name; + return (this); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/Content.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/Content.java new file mode 100644 index 00000000..07d9cab0 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/Content.java @@ -0,0 +1,95 @@ +/* + * 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.model.actions.messaging; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class Content +{ + private String body; + private ContentRole contentRole; + + + + /******************************************************************************* + ** Getter for body + *******************************************************************************/ + public String getBody() + { + return (this.body); + } + + + + /******************************************************************************* + ** Setter for body + *******************************************************************************/ + public void setBody(String body) + { + this.body = body; + } + + + + /******************************************************************************* + ** Fluent setter for body + *******************************************************************************/ + public Content withBody(String body) + { + this.body = body; + return (this); + } + + + + /******************************************************************************* + ** Getter for contentRole + *******************************************************************************/ + public ContentRole getContentRole() + { + return (this.contentRole); + } + + + + /******************************************************************************* + ** Setter for contentRole + *******************************************************************************/ + public void setContentRole(ContentRole contentRole) + { + this.contentRole = contentRole; + } + + + + /******************************************************************************* + ** Fluent setter for contentRole + *******************************************************************************/ + public Content withContentRole(ContentRole contentRole) + { + this.contentRole = contentRole; + return (this); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/ContentRole.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/ContentRole.java new file mode 100644 index 00000000..d18dd03f --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/ContentRole.java @@ -0,0 +1,39 @@ +/* + * 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.model.actions.messaging; + + +/******************************************************************************* + ** + *******************************************************************************/ +public interface ContentRole +{ + + /******************************************************************************* + ** + *******************************************************************************/ + enum Default implements ContentRole + { + DEFAULT + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/MultiParty.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/MultiParty.java new file mode 100644 index 00000000..f736b3e7 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/MultiParty.java @@ -0,0 +1,92 @@ +/* + * 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.model.actions.messaging; + + +import java.util.ArrayList; +import java.util.List; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class MultiParty extends Party +{ + private List partyList; + + + + /******************************************************************************* + ** Getter for partyList + *******************************************************************************/ + public List getPartyList() + { + return (this.partyList); + } + + + + /******************************************************************************* + ** Setter for partyList + *******************************************************************************/ + public void setPartyList(List partyList) + { + this.partyList = partyList; + } + + + + /******************************************************************************* + ** Fluent setter for partyList + *******************************************************************************/ + public MultiParty withPartyList(List partyList) + { + this.partyList = partyList; + return (this); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public MultiParty withParty(Party party) + { + addParty(party); + return (this); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void addParty(Party party) + { + if(this.partyList == null) + { + this.partyList = new ArrayList<>(); + } + this.partyList.add(party); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/Party.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/Party.java new file mode 100644 index 00000000..13b378ba --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/Party.java @@ -0,0 +1,127 @@ +/* + * 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.model.actions.messaging; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class Party +{ + private String label; + private String address; + private PartyRole role; + + + + /******************************************************************************* + ** Getter for label + *******************************************************************************/ + public String getLabel() + { + return (this.label); + } + + + + /******************************************************************************* + ** Setter for label + *******************************************************************************/ + public void setLabel(String label) + { + this.label = label; + } + + + + /******************************************************************************* + ** Fluent setter for label + *******************************************************************************/ + public Party withLabel(String label) + { + this.label = label; + return (this); + } + + + + /******************************************************************************* + ** Getter for address + *******************************************************************************/ + public String getAddress() + { + return (this.address); + } + + + + /******************************************************************************* + ** Setter for address + *******************************************************************************/ + public void setAddress(String address) + { + this.address = address; + } + + + + /******************************************************************************* + ** Fluent setter for address + *******************************************************************************/ + public Party withAddress(String address) + { + this.address = address; + return (this); + } + + + + /******************************************************************************* + ** Getter for role + *******************************************************************************/ + public PartyRole getRole() + { + return (this.role); + } + + + + /******************************************************************************* + ** Setter for role + *******************************************************************************/ + public void setRole(PartyRole role) + { + this.role = role; + } + + + + /******************************************************************************* + ** Fluent setter for role + *******************************************************************************/ + public Party withRole(PartyRole role) + { + this.role = role; + return (this); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/PartyRole.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/PartyRole.java new file mode 100644 index 00000000..d70461b5 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/PartyRole.java @@ -0,0 +1,39 @@ +/* + * 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.model.actions.messaging; + + +/******************************************************************************* + ** + *******************************************************************************/ +public interface PartyRole +{ + + /******************************************************************************* + ** + *******************************************************************************/ + enum Default implements PartyRole + { + DEFAULT + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/SendMessageInput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/SendMessageInput.java new file mode 100644 index 00000000..f502dfa3 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/SendMessageInput.java @@ -0,0 +1,278 @@ +/* + * 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.model.actions.messaging; + + +import java.util.ArrayList; +import java.util.List; +import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class SendMessageInput extends AbstractActionInput +{ + private String messagingProviderName; + private Party to; + private Party from; + private String subject; + private List contentList; + private List attachmentList; + + + + /******************************************************************************* + ** Getter for to + *******************************************************************************/ + public Party getTo() + { + return (this.to); + } + + + + /******************************************************************************* + ** Setter for to + *******************************************************************************/ + public void setTo(Party to) + { + this.to = to; + } + + + + /******************************************************************************* + ** Fluent setter for to + *******************************************************************************/ + public SendMessageInput withTo(Party to) + { + this.to = to; + return (this); + } + + + + /******************************************************************************* + ** Getter for from + *******************************************************************************/ + public Party getFrom() + { + return (this.from); + } + + + + /******************************************************************************* + ** Setter for from + *******************************************************************************/ + public void setFrom(Party from) + { + this.from = from; + } + + + + /******************************************************************************* + ** Fluent setter for from + *******************************************************************************/ + public SendMessageInput withFrom(Party from) + { + this.from = from; + return (this); + } + + + + /******************************************************************************* + ** Getter for subject + *******************************************************************************/ + public String getSubject() + { + return (this.subject); + } + + + + /******************************************************************************* + ** Setter for subject + *******************************************************************************/ + public void setSubject(String subject) + { + this.subject = subject; + } + + + + /******************************************************************************* + ** Fluent setter for subject + *******************************************************************************/ + public SendMessageInput withSubject(String subject) + { + this.subject = subject; + return (this); + } + + + + /******************************************************************************* + ** Getter for contentList + *******************************************************************************/ + public List getContentList() + { + return (this.contentList); + } + + + + /******************************************************************************* + ** Setter for contentList + *******************************************************************************/ + public void setContentList(List contentList) + { + this.contentList = contentList; + } + + + + /******************************************************************************* + ** Fluent setter for contentList + *******************************************************************************/ + public SendMessageInput withContentList(List contentList) + { + this.contentList = contentList; + return (this); + } + + + + /******************************************************************************* + ** Getter for attachmentList + *******************************************************************************/ + public List getAttachmentList() + { + return (this.attachmentList); + } + + + + /******************************************************************************* + ** Setter for attachmentList + *******************************************************************************/ + public void setAttachmentList(List attachmentList) + { + this.attachmentList = attachmentList; + } + + + + /******************************************************************************* + ** Fluent setter for attachmentList + *******************************************************************************/ + public SendMessageInput withAttachmentList(List attachmentList) + { + this.attachmentList = attachmentList; + return (this); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public SendMessageInput withContent(Content content) + { + addContent(content); + return (this); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void addContent(Content content) + { + if(this.contentList == null) + { + this.contentList = new ArrayList<>(); + } + this.contentList.add(content); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public SendMessageInput withAttachment(Attachment attachment) + { + addAttachment(attachment); + return (this); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void addAttachment(Attachment attachment) + { + if(this.attachmentList == null) + { + this.attachmentList = new ArrayList<>(); + } + this.attachmentList.add(attachment); + } + + + + /******************************************************************************* + ** Getter for messagingProviderName + *******************************************************************************/ + public String getMessagingProviderName() + { + return (this.messagingProviderName); + } + + + + /******************************************************************************* + ** Setter for messagingProviderName + *******************************************************************************/ + public void setMessagingProviderName(String messagingProviderName) + { + this.messagingProviderName = messagingProviderName; + } + + + + /******************************************************************************* + ** Fluent setter for messagingProviderName + *******************************************************************************/ + public SendMessageInput withMessagingProviderName(String messagingProviderName) + { + this.messagingProviderName = messagingProviderName; + return (this); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/SendMessageOutput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/SendMessageOutput.java new file mode 100644 index 00000000..032064a7 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/SendMessageOutput.java @@ -0,0 +1,33 @@ +/* + * 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.model.actions.messaging; + + +import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class SendMessageOutput extends AbstractActionOutput +{ +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/email/EmailContentRole.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/email/EmailContentRole.java new file mode 100644 index 00000000..9c8bf0d3 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/email/EmailContentRole.java @@ -0,0 +1,35 @@ +/* + * 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.model.actions.messaging.email; + + +import com.kingsrook.qqq.backend.core.model.actions.messaging.ContentRole; + + +/******************************************************************************* + ** + *******************************************************************************/ +public enum EmailContentRole implements ContentRole +{ + TEXT, + HTML +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/email/EmailPartyRole.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/email/EmailPartyRole.java new file mode 100644 index 00000000..4c7c8e6f --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/messaging/email/EmailPartyRole.java @@ -0,0 +1,38 @@ +/* + * 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.model.actions.messaging.email; + + +import com.kingsrook.qqq.backend.core.model.actions.messaging.PartyRole; + + +/******************************************************************************* + ** + *******************************************************************************/ +public enum EmailPartyRole implements PartyRole +{ + TO, + CC, + BCC, + FROM, + REPLY_TO +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java index 255e4c7e..1c5ecbe6 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java @@ -46,6 +46,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNode; import com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNodeType; import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData; import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.messaging.QMessagingProviderMetaData; import com.kingsrook.qqq.backend.core.model.metadata.permissions.QPermissionRules; import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource; import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; @@ -78,6 +79,7 @@ public class QInstance private QAuthenticationMetaData authentication = null; private QBrandingMetaData branding = null; private Map automationProviders = new HashMap<>(); + private Map messagingProviders = new HashMap<>(); //////////////////////////////////////////////////////////////////////////////////////////// // Important to use LinkedHashmap here, to preserve the order in which entries are added. // @@ -739,6 +741,53 @@ public class QInstance + /******************************************************************************* + ** + *******************************************************************************/ + public void addMessagingProvider(QMessagingProviderMetaData messagingProvider) + { + String name = messagingProvider.getName(); + if(this.messagingProviders.containsKey(name)) + { + throw (new IllegalArgumentException("Attempted to add a second messagingProvider with name: " + name)); + } + this.messagingProviders.put(name, messagingProvider); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QMessagingProviderMetaData getMessagingProvider(String name) + { + return (this.messagingProviders.get(name)); + } + + + + /******************************************************************************* + ** Getter for messagingProviders + ** + *******************************************************************************/ + public Map getMessagingProviders() + { + return messagingProviders; + } + + + + /******************************************************************************* + ** Setter for messagingProviders + ** + *******************************************************************************/ + public void setMessagingProviders(Map messagingProviders) + { + this.messagingProviders = messagingProviders; + } + + + /******************************************************************************* ** Getter for hasBeenValidated ** diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/QMessagingProviderMetaData.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/QMessagingProviderMetaData.java new file mode 100644 index 00000000..116104ea --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/QMessagingProviderMetaData.java @@ -0,0 +1,110 @@ +/* + * 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.model.metadata.messaging; + + +import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.TopLevelMetaDataInterface; + + +/******************************************************************************* + ** Base class for qqq messaging-providers. e.g., a connection to an outbound + ** email service, or, for example, Slack. + *******************************************************************************/ +public class QMessagingProviderMetaData implements TopLevelMetaDataInterface +{ + private String name; + private String type; + + + + /******************************************************************************* + ** Getter for name + *******************************************************************************/ + public String getName() + { + return (this.name); + } + + + + /******************************************************************************* + ** Setter for name + *******************************************************************************/ + public void setName(String name) + { + this.name = name; + } + + + + /******************************************************************************* + ** Fluent setter for name + *******************************************************************************/ + public QMessagingProviderMetaData withName(String name) + { + this.name = name; + return (this); + } + + + + /******************************************************************************* + ** Getter for type + *******************************************************************************/ + public String getType() + { + return (this.type); + } + + + + /******************************************************************************* + ** Setter for type + *******************************************************************************/ + public void setType(String type) + { + this.type = type; + } + + + + /******************************************************************************* + ** Fluent setter for type + *******************************************************************************/ + public QMessagingProviderMetaData withType(String type) + { + this.type = type; + return (this); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public void addSelfToInstance(QInstance qInstance) + { + qInstance.addMessagingProvider(this); + } +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/EmailMessagingProvider.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/EmailMessagingProvider.java new file mode 100644 index 00000000..df920919 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/EmailMessagingProvider.java @@ -0,0 +1,56 @@ +/* + * 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.model.metadata.messaging.email; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.messaging.SendMessageInput; +import com.kingsrook.qqq.backend.core.model.actions.messaging.SendMessageOutput; +import com.kingsrook.qqq.backend.core.modules.messaging.MessagingProviderInterface; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class EmailMessagingProvider implements MessagingProviderInterface +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public String getType() + { + return (EmailMessagingProviderMetaData.TYPE); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public SendMessageOutput sendMessage(SendMessageInput sendMessageInput) throws QException + { + return new SendEmailAction().sendMessage(sendMessageInput); + } +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/EmailMessagingProviderMetaData.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/EmailMessagingProviderMetaData.java new file mode 100644 index 00000000..7fdb931a --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/EmailMessagingProviderMetaData.java @@ -0,0 +1,116 @@ +/* + * 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.model.metadata.messaging.email; + + +import com.kingsrook.qqq.backend.core.model.metadata.messaging.QMessagingProviderMetaData; +import com.kingsrook.qqq.backend.core.modules.messaging.QMessagingProviderDispatcher; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class EmailMessagingProviderMetaData extends QMessagingProviderMetaData +{ + private String smtpServer; + private String smtpPort; + + public static final String TYPE = "EMAIL"; + + static + { + QMessagingProviderDispatcher.registerMessagingProvider(new EmailMessagingProvider()); + } + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public EmailMessagingProviderMetaData() + { + super(); + setType(TYPE); + } + + + + /******************************************************************************* + ** Getter for smtpServer + *******************************************************************************/ + public String getSmtpServer() + { + return (this.smtpServer); + } + + + + /******************************************************************************* + ** Setter for smtpServer + *******************************************************************************/ + public void setSmtpServer(String smtpServer) + { + this.smtpServer = smtpServer; + } + + + + /******************************************************************************* + ** Fluent setter for smtpServer + *******************************************************************************/ + public EmailMessagingProviderMetaData withSmtpServer(String smtpServer) + { + this.smtpServer = smtpServer; + return (this); + } + + + + /******************************************************************************* + ** Getter for smtpPort + *******************************************************************************/ + public String getSmtpPort() + { + return (this.smtpPort); + } + + + + /******************************************************************************* + ** Setter for smtpPort + *******************************************************************************/ + public void setSmtpPort(String smtpPort) + { + this.smtpPort = smtpPort; + } + + + + /******************************************************************************* + ** Fluent setter for smtpPort + *******************************************************************************/ + public EmailMessagingProviderMetaData withSmtpPort(String smtpPort) + { + this.smtpPort = smtpPort; + return (this); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/SendEmailAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/SendEmailAction.java new file mode 100644 index 00000000..ebb67d98 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/SendEmailAction.java @@ -0,0 +1,194 @@ +/* + * 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.model.metadata.messaging.email; + + +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import com.kingsrook.qqq.backend.core.context.QContext; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.messaging.MultiParty; +import com.kingsrook.qqq.backend.core.model.actions.messaging.Party; +import com.kingsrook.qqq.backend.core.model.actions.messaging.PartyRole; +import com.kingsrook.qqq.backend.core.model.actions.messaging.SendMessageInput; +import com.kingsrook.qqq.backend.core.model.actions.messaging.SendMessageOutput; +import com.kingsrook.qqq.backend.core.model.actions.messaging.email.EmailPartyRole; +import com.kingsrook.qqq.backend.core.utils.StringUtils; +import jakarta.mail.Address; +import jakarta.mail.Message; +import jakarta.mail.Session; +import jakarta.mail.Transport; +import jakarta.mail.internet.AddressException; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; + + +/******************************************************************************* + ** + *******************************************************************************/ +public class SendEmailAction +{ + + /******************************************************************************* + ** + *******************************************************************************/ + public SendMessageOutput sendMessage(SendMessageInput sendMessageInput) throws QException + { + EmailMessagingProviderMetaData messagingProvider = (EmailMessagingProviderMetaData) QContext.getQInstance().getMessagingProvider(sendMessageInput.getMessagingProviderName()); + + ///////////////////////////////////////// + // set up properties to make a session // + ///////////////////////////////////////// + Properties properties = System.getProperties(); + properties.setProperty("mail.smtp.host", messagingProvider.getSmtpServer()); + properties.setProperty("mail.smtp.port", messagingProvider.getSmtpPort()); + Session session = Session.getDefaultInstance(properties); + + try + { + //////////////////////////////////////////// + // Construct a default MimeMessage object // + //////////////////////////////////////////// + MimeMessage emailMessage = new MimeMessage(session); + emailMessage.setSubject(sendMessageInput.getSubject()); + emailMessage.setText(sendMessageInput.getContentList().get(0).getBody()); + + Party to = sendMessageInput.getTo(); + if(to instanceof MultiParty toMultiParty) + { + for(Party party : toMultiParty.getPartyList()) + { + addRecipient(emailMessage, party); + } + } + else + { + addRecipient(emailMessage, to); + } + + Party from = sendMessageInput.getTo(); + if(from instanceof MultiParty fromMultiParty) + { + for(Party party : fromMultiParty.getPartyList()) + { + addSender(emailMessage, party); + } + } + else + { + addSender(emailMessage, from); + } + + ///////////// + // send it // + ///////////// + Transport.send(emailMessage); + System.out.println("Message dispatched successfully..."); + } + catch(Exception e) + { + throw (new QException("Error sending email", e)); + } + + return null; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + private void addSender(MimeMessage emailMessage, Party party) throws Exception + { + if(EmailPartyRole.REPLY_TO.equals(party.getRole())) + { + InternetAddress internetAddress = getInternetAddressFromParty(party); + Address[] replyTo = emailMessage.getReplyTo(); + if(replyTo == null || replyTo.length == 0) + { + emailMessage.setReplyTo(new Address[] { internetAddress }); + } + else + { + List
replyToList = Arrays.asList(replyTo); + replyToList.add(internetAddress); + emailMessage.setReplyTo(replyToList.toArray(new Address[0])); + } + } + else if(party.getRole() == null || PartyRole.Default.DEFAULT.equals(party.getRole()) || EmailPartyRole.FROM.equals(party.getRole())) + { + emailMessage.setFrom(getInternetAddressFromParty(party)); + } + else + { + throw (new QException("Unrecognized sender role [" + party.getRole() + "]")); + } + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + private void addRecipient(MimeMessage emailMessage, Party party) throws Exception + { + Message.RecipientType recipientType; + if(EmailPartyRole.CC.equals(party.getRole())) + { + recipientType = Message.RecipientType.CC; + } + else if(EmailPartyRole.BCC.equals(party.getRole())) + { + recipientType = Message.RecipientType.BCC; + } + else if(party.getRole() == null || PartyRole.Default.DEFAULT.equals(party.getRole()) || EmailPartyRole.TO.equals(party.getRole())) + { + recipientType = Message.RecipientType.TO; + } + else + { + throw (new QException("Unrecognized recipient role [" + party.getRole() + "]")); + } + + InternetAddress internetAddress = getInternetAddressFromParty(party); + emailMessage.addRecipient(recipientType, internetAddress); + System.out.println("add recipient: [" + recipientType + "] => [" + internetAddress + "]"); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + private static InternetAddress getInternetAddressFromParty(Party party) throws AddressException, UnsupportedEncodingException + { + InternetAddress internetAddress = new InternetAddress(party.getAddress()); + if(StringUtils.hasContent(party.getLabel())) + { + internetAddress.setPersonal(party.getLabel()); + } + return internetAddress; + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/modules/messaging/MessagingProviderInterface.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/modules/messaging/MessagingProviderInterface.java new file mode 100644 index 00000000..de7bdc74 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/modules/messaging/MessagingProviderInterface.java @@ -0,0 +1,46 @@ +/* + * 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.modules.messaging; + + +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.messaging.SendMessageInput; +import com.kingsrook.qqq.backend.core.model.actions.messaging.SendMessageOutput; + + +/******************************************************************************* + ** + *******************************************************************************/ +public interface MessagingProviderInterface +{ + + /******************************************************************************* + ** + *******************************************************************************/ + String getType(); + + /******************************************************************************* + ** + *******************************************************************************/ + SendMessageOutput sendMessage(SendMessageInput sendMessageInput) throws QException; + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/modules/messaging/QMessagingProviderDispatcher.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/modules/messaging/QMessagingProviderDispatcher.java new file mode 100644 index 00000000..4187fb39 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/modules/messaging/QMessagingProviderDispatcher.java @@ -0,0 +1,123 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2022. 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.modules.messaging; + + +import java.util.HashMap; +import java.util.Map; +import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException; +import com.kingsrook.qqq.backend.core.logging.QLogger; +import com.kingsrook.qqq.backend.core.model.metadata.messaging.QMessagingProviderMetaData; + + +/******************************************************************************* + ** This class is responsible for loading a messaging provider, by its name, and + ** returning an instance. + ** + *******************************************************************************/ +public class QMessagingProviderDispatcher +{ + private static final QLogger LOG = QLogger.getLogger(QMessagingProviderDispatcher.class); + + private static Map typeToProviderClassNameMap; + + + + /******************************************************************************* + ** + *******************************************************************************/ + public QMessagingProviderDispatcher() + { + initBackendTypeToModuleClassNameMap(); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + private static void initBackendTypeToModuleClassNameMap() + { + if(typeToProviderClassNameMap != null) + { + return; + } + + Map newMap = new HashMap<>(); + + typeToProviderClassNameMap = newMap; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public static void registerMessagingProvider(MessagingProviderInterface messagingProviderInstance) + { + initBackendTypeToModuleClassNameMap(); + String type = messagingProviderInstance.getType(); + if(typeToProviderClassNameMap.containsKey(type)) + { + LOG.info("Overwriting messagingProvider type [" + type + "] with [" + messagingProviderInstance.getClass() + "]"); + } + typeToProviderClassNameMap.put(type, messagingProviderInstance.getClass().getName()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public MessagingProviderInterface getMessagingProviderInterface(QMessagingProviderMetaData messagingProviderMetaData) throws QModuleDispatchException + { + return (getMessagingProviderInterface(messagingProviderMetaData.getType())); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public MessagingProviderInterface getMessagingProviderInterface(String type) throws QModuleDispatchException + { + try + { + String className = typeToProviderClassNameMap.get(type); + if(className == null) + { + throw (new QModuleDispatchException("Unrecognized messaging provider type [" + type + "] in dispatcher.")); + } + + Class moduleClass = Class.forName(className); + return (MessagingProviderInterface) moduleClass.getDeclaredConstructor().newInstance(); + } + catch(QModuleDispatchException qmde) + { + throw (qmde); + } + catch(Exception e) + { + throw (new QModuleDispatchException("Error getting messaging provider of type: " + type, e)); + } + } +} diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/EmailMessagingProviderTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/EmailMessagingProviderTest.java new file mode 100644 index 00000000..30d0fd04 --- /dev/null +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/messaging/email/EmailMessagingProviderTest.java @@ -0,0 +1,65 @@ +/* + * 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.model.metadata.messaging.email; + + +import com.kingsrook.qqq.backend.core.BaseTest; +import com.kingsrook.qqq.backend.core.actions.messaging.SendMessageAction; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.messaging.Content; +import com.kingsrook.qqq.backend.core.model.actions.messaging.MultiParty; +import com.kingsrook.qqq.backend.core.model.actions.messaging.Party; +import com.kingsrook.qqq.backend.core.model.actions.messaging.SendMessageInput; +import com.kingsrook.qqq.backend.core.model.actions.messaging.email.EmailContentRole; +import com.kingsrook.qqq.backend.core.model.actions.messaging.email.EmailPartyRole; +import com.kingsrook.qqq.backend.core.utils.TestUtils; +import org.junit.jupiter.api.Test; + + +/******************************************************************************* + ** Unit test for EmailMessagingProvider + *******************************************************************************/ +class EmailMessagingProviderTest extends BaseTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void test() throws QException + { + new SendMessageAction().execute(new SendMessageInput() + .withMessagingProviderName(TestUtils.EMAIL_MESSAGING_PROVIDER_NAME) + .withTo(new MultiParty() + .withParty(new Party().withAddress("darin.kelkhoff@gmail.com").withLabel("Darin Kelkhoff").withRole(EmailPartyRole.TO)) + .withParty(new Party().withAddress("james.maes@kingsrook.com").withLabel("Mames Maes").withRole(EmailPartyRole.CC)) + .withParty(new Party().withAddress("tyler.samples@kingsrook.com").withLabel("Tylers Ample").withRole(EmailPartyRole.BCC)) + ) + // .withFrom(new Party().withAddress("darin.kelkhoff@gmail.com").withLabel("Darin Kelkhoff")) + .withFrom(new Party().withAddress("tim.chamberlain@kingsrook.com").withLabel("Tim Chamberlain")) + .withSubject("This is another qqq test message.") + .withContent(new Content().withContentRole(EmailContentRole.TEXT).withBody("This is a text body")) + .withContent(new Content().withContentRole(EmailContentRole.HTML).withBody("This is an HTML body!")) + ); + } + +} \ No newline at end of file diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/utils/TestUtils.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/utils/TestUtils.java index 000afa15..3702ff4a 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/utils/TestUtils.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/utils/TestUtils.java @@ -74,6 +74,8 @@ import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn; import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinType; import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData; import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.messaging.QMessagingProviderMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.messaging.email.EmailMessagingProviderMetaData; import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PVSValueFormatAndFields; import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValue; import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource; @@ -180,6 +182,8 @@ public class TestUtils public static final String SECURITY_KEY_TYPE_STORE_NULL_BEHAVIOR = "storeNullBehavior"; public static final String SECURITY_KEY_TYPE_INTERNAL_OR_EXTERNAL = "internalOrExternal"; + public static final String EMAIL_MESSAGING_PROVIDER_NAME = "email"; + public static final String SIMPLE_SCHEDULER_NAME = "simpleScheduler"; public static final String TEST_SQS_QUEUE = "testSQSQueue"; @@ -242,6 +246,8 @@ public class TestUtils qInstance.addQueueProvider(defineSqsProvider()); qInstance.addQueue(defineTestSqsQueue()); + qInstance.addMessagingProvider(defineEmailMessagingProvider()); + defineWidgets(qInstance); defineApps(qInstance); @@ -252,6 +258,19 @@ public class TestUtils + /******************************************************************************* + ** + *******************************************************************************/ + private static QMessagingProviderMetaData defineEmailMessagingProvider() + { + return new EmailMessagingProviderMetaData() + .withSmtpServer("localhost") + .withSmtpPort("2500") + .withName(EMAIL_MESSAGING_PROVIDER_NAME); + } + + + /******************************************************************************* ** *******************************************************************************/