mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-20 22:18:43 +00:00
CE-1068: checkpoint commit of SES support
This commit is contained in:
@ -30,7 +30,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.storage.StorageInput;
|
||||
|
||||
/*******************************************************************************
|
||||
** Interface for actions that a backend can perform, based on streaming data
|
||||
** into the backend's storage.
|
||||
** into the backend's storage.
|
||||
*******************************************************************************/
|
||||
public interface QStorageInterface
|
||||
{
|
||||
@ -46,4 +46,15 @@ public interface QStorageInterface
|
||||
*******************************************************************************/
|
||||
InputStream getInputStream(StorageInput storageInput) throws QException;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
default void makePublic(StorageInput storageInput) throws QException
|
||||
{
|
||||
//////////
|
||||
// noop //
|
||||
//////////
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -93,4 +93,16 @@ public class StorageAction
|
||||
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(backend);
|
||||
return (qModule);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void makePublic(StorageInput storageInput) throws QException
|
||||
{
|
||||
QBackendModuleInterface qBackendModuleInterface = preAction(storageInput);
|
||||
QStorageInterface storageInterface = qBackendModuleInterface.getStorageInterface();
|
||||
storageInterface.makePublic(storageInput);
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ public class SendEmailAction
|
||||
addRecipient(emailMessage, to);
|
||||
}
|
||||
|
||||
Party from = sendMessageInput.getTo();
|
||||
Party from = sendMessageInput.getFrom();
|
||||
if(from instanceof MultiParty fromMultiParty)
|
||||
{
|
||||
for(Party party : fromMultiParty.getPartyList())
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.messaging.ses;
|
||||
|
||||
|
||||
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 SESMessagingProvider implements MessagingProviderInterface
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String getType()
|
||||
{
|
||||
return (SESMessagingProviderMetaData.TYPE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public SendMessageOutput sendMessage(SendMessageInput sendMessageInput) throws QException
|
||||
{
|
||||
return new SendSESAction().sendMessage(sendMessageInput);
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.messaging.ses;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.messaging.QMessagingProviderMetaData;
|
||||
import com.kingsrook.qqq.backend.core.modules.messaging.QMessagingProviderDispatcher;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class SESMessagingProviderMetaData extends QMessagingProviderMetaData
|
||||
{
|
||||
private String accessKey;
|
||||
private String secretKey;
|
||||
private String region;
|
||||
|
||||
public static final String TYPE = "SES";
|
||||
|
||||
static
|
||||
{
|
||||
QMessagingProviderDispatcher.registerMessagingProvider(new SESMessagingProvider());
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SESMessagingProviderMetaData()
|
||||
{
|
||||
super();
|
||||
setType(TYPE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for accessKey
|
||||
*******************************************************************************/
|
||||
public String getAccessKey()
|
||||
{
|
||||
return (this.accessKey);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for accessKey
|
||||
*******************************************************************************/
|
||||
public void setAccessKey(String accessKey)
|
||||
{
|
||||
this.accessKey = accessKey;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for accessKey
|
||||
*******************************************************************************/
|
||||
public SESMessagingProviderMetaData withAccessKey(String accessKey)
|
||||
{
|
||||
this.accessKey = accessKey;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for secretKey
|
||||
*******************************************************************************/
|
||||
public String getSecretKey()
|
||||
{
|
||||
return (this.secretKey);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for secretKey
|
||||
*******************************************************************************/
|
||||
public void setSecretKey(String secretKey)
|
||||
{
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for secretKey
|
||||
*******************************************************************************/
|
||||
public SESMessagingProviderMetaData withSecretKey(String secretKey)
|
||||
{
|
||||
this.secretKey = secretKey;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for region
|
||||
*******************************************************************************/
|
||||
public String getRegion()
|
||||
{
|
||||
return (this.region);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for region
|
||||
*******************************************************************************/
|
||||
public void setRegion(String region)
|
||||
{
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for region
|
||||
*******************************************************************************/
|
||||
public SESMessagingProviderMetaData withRegion(String region)
|
||||
{
|
||||
this.region = region;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,335 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.messaging.ses;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
||||
import com.amazonaws.auth.BasicAWSCredentials;
|
||||
import com.amazonaws.services.simpleemail.AmazonSimpleEmailService;
|
||||
import com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClientBuilder;
|
||||
import com.amazonaws.services.simpleemail.model.Body;
|
||||
import com.amazonaws.services.simpleemail.model.Content;
|
||||
import com.amazonaws.services.simpleemail.model.Destination;
|
||||
import com.amazonaws.services.simpleemail.model.Message;
|
||||
import com.amazonaws.services.simpleemail.model.SendEmailRequest;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
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.EmailContentRole;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.messaging.email.EmailPartyRole;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class SendSESAction
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(SendSESAction.class);
|
||||
|
||||
private AmazonSimpleEmailService amazonSES;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SendMessageOutput sendMessage(SendMessageInput sendMessageInput) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
AmazonSimpleEmailService client = getAmazonSES(sendMessageInput);
|
||||
|
||||
///////////////////////////////////
|
||||
// build up a send email request //
|
||||
///////////////////////////////////
|
||||
SendEmailRequest request = new SendEmailRequest()
|
||||
.withSource(getSource(sendMessageInput))
|
||||
.withReplyToAddresses(getReplyTos(sendMessageInput))
|
||||
.withDestination(buildDestination(sendMessageInput))
|
||||
.withMessage(buildMessage(sendMessageInput));
|
||||
|
||||
client.sendEmail(request);
|
||||
LOG.info("SES Message [" + request.getMessage().getSubject().getData() + "] was sent to [" + request.getDestination().toString() + "].");
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
String message = "An unexpected error occurred sending an SES message.";
|
||||
throw (new QException(message, e));
|
||||
}
|
||||
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
Message buildMessage(SendMessageInput input) throws QException
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// iterate over all contents of our input, looking for an HTML and Text version of the email //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Body body = new Body();
|
||||
for(com.kingsrook.qqq.backend.core.model.actions.messaging.Content content : CollectionUtils.nonNullList(input.getContentList()))
|
||||
{
|
||||
if(EmailContentRole.TEXT.equals(content.getContentRole()))
|
||||
{
|
||||
body.setText(new Content().withCharset("UTF-8").withData(content.getBody()));
|
||||
}
|
||||
else if(EmailContentRole.HTML.equals(content.getContentRole()))
|
||||
{
|
||||
body.setHtml(new Content().withCharset("UTF-8").withData(content.getBody()));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// error if no text or html body was provided //
|
||||
////////////////////////////////////////////////
|
||||
if(body.getText() == null && body.getHtml() == null)
|
||||
{
|
||||
throw (new QException("Cannot send SES message because neither a 'Text' nor an 'HTML' body was provided."));
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// warning if no subject was provided //
|
||||
////////////////////////////////////////
|
||||
Message message = new Message();
|
||||
message.setBody(body);
|
||||
|
||||
/////////////////////////////////////
|
||||
// warn if no subject was provided //
|
||||
/////////////////////////////////////
|
||||
if(input.getSubject() == null)
|
||||
{
|
||||
LOG.warn("Sending SES message with no subject.");
|
||||
}
|
||||
else
|
||||
{
|
||||
message.setSubject(new Content().withCharset("UTF-8").withData(input.getSubject()));
|
||||
}
|
||||
|
||||
return (message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
List<String> getReplyTos(SendMessageInput input) throws QException
|
||||
{
|
||||
////////////////////////////
|
||||
// no input, no reply tos //
|
||||
////////////////////////////
|
||||
if(input == null)
|
||||
{
|
||||
return (Collections.emptyList());
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// build up a list of froms if multi //
|
||||
///////////////////////////////////////
|
||||
List<Party> partyList = getPartyListFromParty(input.getFrom());
|
||||
if(partyList == null)
|
||||
{
|
||||
return (Collections.emptyList());
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// only get reply to parties //
|
||||
///////////////////////////////
|
||||
List<Party> replyToParties = partyList.stream().filter(p -> EmailPartyRole.REPLY_TO.equals(p.getRole())).toList();
|
||||
|
||||
//////////////////////////////////
|
||||
// get addresses from reply tos //
|
||||
//////////////////////////////////
|
||||
List<String> replyTos = replyToParties.stream().map(Party::getAddress).toList();
|
||||
|
||||
/////////////////////////////
|
||||
// return the from address //
|
||||
/////////////////////////////
|
||||
return (replyTos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
String getSource(SendMessageInput input) throws QException
|
||||
{
|
||||
///////////////////////////////
|
||||
// error if no from provided //
|
||||
///////////////////////////////
|
||||
if(input.getFrom() == null)
|
||||
{
|
||||
throw (new QException("Cannot send SES message because a FROM was not provided."));
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// build up a list of froms if multi //
|
||||
///////////////////////////////////////
|
||||
List<Party> partyList = getPartyListFromParty(input.getFrom());
|
||||
|
||||
///////////////////////////////////////
|
||||
// remove any roles that aren't FROM //
|
||||
///////////////////////////////////////
|
||||
partyList.removeIf(p -> p.getRole() != null && !EmailPartyRole.FROM.equals(p.getRole()));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if no froms found, error, if more than one found, log a warning and use the first one //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
if(partyList.isEmpty())
|
||||
{
|
||||
throw (new QException("Cannot send SES message because a FROM was not provided."));
|
||||
}
|
||||
else if(partyList.size() > 1)
|
||||
{
|
||||
LOG.warn("More than one FROM value was found, will send using the first one found [" + partyList.get(0).getAddress() + "].");
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// return the from address //
|
||||
/////////////////////////////
|
||||
return (partyList.get(0).getAddress());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
List<Party> getPartyListFromParty(Party party)
|
||||
{
|
||||
//////////////////////////////////////////////
|
||||
// get all parties into one list of parties //
|
||||
//////////////////////////////////////////////
|
||||
List<Party> partyList = new ArrayList<>();
|
||||
if(party != null)
|
||||
{
|
||||
if(party instanceof MultiParty toMultiParty)
|
||||
{
|
||||
partyList.addAll(toMultiParty.getPartyList());
|
||||
}
|
||||
else
|
||||
{
|
||||
partyList.add(party);
|
||||
}
|
||||
}
|
||||
return (partyList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
Destination buildDestination(SendMessageInput input) throws QException
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// iterate over the parties putting it the proper party type list //
|
||||
////////////////////////////////////////////////////////////////////
|
||||
List<String> toList = new ArrayList<>();
|
||||
List<String> ccList = new ArrayList<>();
|
||||
List<String> bccList = new ArrayList<>();
|
||||
|
||||
List<Party> partyList = getPartyListFromParty(input.getTo());
|
||||
for(Party party : partyList)
|
||||
{
|
||||
if(EmailPartyRole.CC.equals(party.getRole()))
|
||||
{
|
||||
ccList.add(party.getAddress());
|
||||
}
|
||||
else if(EmailPartyRole.BCC.equals(party.getRole()))
|
||||
{
|
||||
bccList.add(party.getAddress());
|
||||
}
|
||||
else if(party.getRole() == null || PartyRole.Default.DEFAULT.equals(party.getRole()) || EmailPartyRole.TO.equals(party.getRole()))
|
||||
{
|
||||
toList.add(party.getAddress());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new QException("An unrecognized recipient role of [" + party.getRole() + "] was provided."));
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// if no to addresses, this is an error //
|
||||
//////////////////////////////////////////
|
||||
if(toList.isEmpty())
|
||||
{
|
||||
throw (new QException("Cannot send SES message because no TO addresses were provided."));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// build and return aws destination object //
|
||||
/////////////////////////////////////////////
|
||||
return (new Destination()
|
||||
.withToAddresses(toList)
|
||||
.withCcAddresses(ccList)
|
||||
.withBccAddresses(bccList));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Set the amazonSES object.
|
||||
*******************************************************************************/
|
||||
public void setAmazonSES(AmazonSimpleEmailService amazonSES)
|
||||
{
|
||||
this.amazonSES = amazonSES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Internal accessor for the amazonSES object - should always use this, not the field.
|
||||
*******************************************************************************/
|
||||
protected AmazonSimpleEmailService getAmazonSES(SendMessageInput sendMessageInput)
|
||||
{
|
||||
if(amazonSES == null)
|
||||
{
|
||||
SESMessagingProviderMetaData messagingProvider = (SESMessagingProviderMetaData) QContext.getQInstance().getMessagingProvider(sendMessageInput.getMessagingProviderName());
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// get credentials and build an SES client //
|
||||
/////////////////////////////////////////////
|
||||
BasicAWSCredentials credentials = new BasicAWSCredentials(messagingProvider.getAccessKey(), messagingProvider.getSecretKey());
|
||||
amazonSES = AmazonSimpleEmailServiceClientBuilder.standard()
|
||||
.withCredentials(new AWSStaticCredentialsProvider(credentials))
|
||||
.withRegion(messagingProvider.getRegion()).build();
|
||||
}
|
||||
|
||||
return amazonSES;
|
||||
}
|
||||
}
|
@ -31,13 +31,21 @@ import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import com.kingsrook.qqq.backend.core.actions.messaging.SendMessageAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.GenerateReportAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
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.logging.QLogger;
|
||||
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.model.actions.processes.RunBackendStepInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportDestination;
|
||||
@ -53,6 +61,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.savedreports.RenderedReport;
|
||||
import com.kingsrook.qqq.backend.core.model.savedreports.RenderedReportStatus;
|
||||
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 static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
||||
@ -82,10 +91,14 @@ public class RenderSavedReportExecuteStep implements BackendStep
|
||||
////////////////////////////////
|
||||
String storageTableName = runBackendStepInput.getValueString(RenderSavedReportMetaDataProducer.FIELD_NAME_STORAGE_TABLE_NAME);
|
||||
ReportFormat reportFormat = ReportFormat.fromString(runBackendStepInput.getValueString(RenderSavedReportMetaDataProducer.FIELD_NAME_REPORT_FORMAT));
|
||||
String sendToEmailAddress = runBackendStepInput.getValueString(RenderSavedReportMetaDataProducer.FIELD_NAME_EMAIL_ADDRESS);
|
||||
SavedReport savedReport = new SavedReport(runBackendStepInput.getRecords().get(0));
|
||||
String downloadFileBaseName = getDownloadFileBaseName(runBackendStepInput, savedReport);
|
||||
String storageReference = LocalDate.now() + "/" + LocalTime.now().toString().replaceAll(":", "").replaceFirst("\\..*", "") + "/" + UUID.randomUUID() + "/" + downloadFileBaseName + "." + reportFormat.getExtension();
|
||||
OutputStream outputStream = new StorageAction().createOutputStream(new StorageInput(storageTableName).withReference(storageReference));
|
||||
|
||||
StorageAction storageAction = new StorageAction();
|
||||
StorageInput storageInput = new StorageInput(storageTableName).withReference(storageReference);
|
||||
OutputStream outputStream = storageAction.createOutputStream(storageInput);
|
||||
|
||||
LOG.info("Starting to render a report", logPair("savedReportId", savedReport.getId()), logPair("tableName", savedReport.getTableName()), logPair("storageReference", storageReference));
|
||||
runBackendStepInput.getAsyncJobCallback().updateStatus("Generating Report");
|
||||
@ -120,6 +133,7 @@ public class RenderSavedReportExecuteStep implements BackendStep
|
||||
reportInput.setInputValues(values);
|
||||
|
||||
ReportOutput reportOutput = new GenerateReportAction().execute(reportInput);
|
||||
storageAction.makePublic(storageInput);
|
||||
|
||||
///////////////////////////////////
|
||||
// update record to show success //
|
||||
@ -132,10 +146,28 @@ public class RenderSavedReportExecuteStep implements BackendStep
|
||||
.withValue("rowCount", reportOutput.getTotalRecordCount())
|
||||
));
|
||||
|
||||
runBackendStepOutput.addValue("downloadFileName", downloadFileBaseName + "." + reportFormat.getExtension());
|
||||
String downloadFileName = downloadFileBaseName + "." + reportFormat.getExtension();
|
||||
runBackendStepOutput.addValue("downloadFileName", downloadFileName);
|
||||
runBackendStepOutput.addValue("storageTableName", storageTableName);
|
||||
runBackendStepOutput.addValue("storageReference", storageReference);
|
||||
LOG.info("Completed rendering a report", logPair("savedReportId", savedReport.getId()), logPair("tableName", savedReport.getTableName()), logPair("storageReference", storageReference), logPair("rowCount", reportOutput.getTotalRecordCount()));
|
||||
|
||||
if(sendToEmailAddress != null && CollectionUtils.nullSafeHasContents(QContext.getQInstance().getMessagingProviders()))
|
||||
{
|
||||
String s3Url = "https://bucket-ctlive-reports-dev.s3.us-east-2.amazonaws.com/saved-reports/" + storageReference; // TODO: derp
|
||||
|
||||
new SendMessageAction().execute(new SendMessageInput()
|
||||
.withMessagingProviderName("defaultMessagingProvider") // TODO: derp
|
||||
.withTo(new Party().withAddress(sendToEmailAddress).withRole(EmailPartyRole.TO))
|
||||
.withFrom(new MultiParty()
|
||||
.withParty(new Party().withAddress("reports@coldtrack-dev.com").withRole(EmailPartyRole.FROM)) // TODO: derp
|
||||
.withParty(new Party().withAddress("noreply@coldtrack-dev.com").withRole(EmailPartyRole.REPLY_TO)) // TODO: derp
|
||||
)
|
||||
.withSubject(downloadFileBaseName)
|
||||
.withContent(new Content().withContentRole(EmailContentRole.TEXT).withBody("To download your report, open this URL in your browser: " + s3Url))
|
||||
.withContent(new Content().withContentRole(EmailContentRole.HTML).withBody("Link: <a target=\"_blank\" href=\"" + s3Url + "\">" + downloadFileName + "</a>"))
|
||||
);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
@ -49,6 +49,7 @@ public class RenderSavedReportMetaDataProducer implements MetaDataProducerInterf
|
||||
|
||||
public static final String FIELD_NAME_STORAGE_TABLE_NAME = "storageTableName";
|
||||
public static final String FIELD_NAME_REPORT_FORMAT = "reportFormat";
|
||||
public static final String FIELD_NAME_EMAIL_ADDRESS = "reportDestinationEmailAddress";
|
||||
|
||||
|
||||
|
||||
@ -74,7 +75,8 @@ public class RenderSavedReportMetaDataProducer implements MetaDataProducerInterf
|
||||
.withComponent(new QFrontendComponentMetaData().withType(QComponentType.EDIT_FORM))
|
||||
.withFormField(new QFieldMetaData(FIELD_NAME_REPORT_FORMAT, QFieldType.STRING)
|
||||
.withPossibleValueSourceName(ReportFormatPossibleValueEnum.NAME)
|
||||
.withIsRequired(true)))
|
||||
.withIsRequired(true))
|
||||
.withFormField(new QFieldMetaData(FIELD_NAME_EMAIL_ADDRESS, QFieldType.STRING).withLabel("Send To Email Address")))
|
||||
.addStep(new QBackendStepMetaData()
|
||||
.withName("execute")
|
||||
.withInputData(new QFunctionInputMetaData().withRecordListMetaData(new QRecordListMetaData()
|
||||
|
Reference in New Issue
Block a user