/**
*
* Copyright
* 2009-2015 Jayway Products AB
* 2016-2017 Föreningen Sambruk
*
* Licensed under AGPL, Version 3.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/agpl.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package se.streamsource.streamflow.web.context.surface.tasks;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdfwriter.COSWriter;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.qi4j.api.common.Optional;
import org.qi4j.api.injection.scope.Service;
import org.qi4j.api.injection.scope.Structure;
import org.qi4j.api.injection.scope.This;
import org.qi4j.api.injection.scope.Uses;
import org.qi4j.api.mixin.Mixins;
import org.qi4j.api.query.Query;
import org.qi4j.api.structure.Module;
import org.qi4j.api.value.ValueBuilder;
import org.qi4j.api.value.ValueBuilderFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import se.streamsource.dci.api.Context;
import se.streamsource.dci.api.IndexContext;
import se.streamsource.dci.api.RoleMap;
import se.streamsource.dci.value.StringValue;
import se.streamsource.streamflow.api.administration.form.AttachmentFieldValue;
import se.streamsource.streamflow.api.administration.form.RequiredSignatureValue;
import se.streamsource.streamflow.api.administration.form.RequiredSignaturesValue;
import se.streamsource.streamflow.api.workspace.cases.CaseOutputConfigDTO;
import se.streamsource.streamflow.api.workspace.cases.contact.ContactBuilder;
import se.streamsource.streamflow.api.workspace.cases.form.AttachmentFieldSubmission;
import se.streamsource.streamflow.api.workspace.cases.general.FormDraftDTO;
import se.streamsource.streamflow.api.workspace.cases.general.FormSignatureDTO;
import se.streamsource.streamflow.util.Strings;
import se.streamsource.streamflow.util.Translator;
import se.streamsource.streamflow.util.Visitor;
import se.streamsource.streamflow.web.application.defaults.SystemDefaultsService;
import se.streamsource.streamflow.web.application.mail.EmailValue;
import se.streamsource.streamflow.web.application.mail.HtmlMailGenerator;
import se.streamsource.streamflow.web.application.mail.MailSender;
import se.streamsource.streamflow.web.application.pdf.PdfGeneratorService;
import se.streamsource.streamflow.web.context.services.ApplyFilterContext;
import se.streamsource.streamflow.web.domain.entity.attachment.AttachmentEntity;
import se.streamsource.streamflow.web.domain.entity.caze.CaseEntity;
import se.streamsource.streamflow.web.domain.entity.customer.CustomerEntity;
import se.streamsource.streamflow.web.domain.entity.customer.CustomersEntity;
import se.streamsource.streamflow.web.domain.interaction.gtd.CaseId;
import se.streamsource.streamflow.web.domain.interaction.gtd.Owner;
import se.streamsource.streamflow.web.domain.structure.SubmittedFieldValue;
import se.streamsource.streamflow.web.domain.structure.attachment.AttachedFile;
import se.streamsource.streamflow.web.domain.structure.attachment.AttachedFileValue;
import se.streamsource.streamflow.web.domain.structure.attachment.DefaultPdfTemplate;
import se.streamsource.streamflow.web.domain.structure.attachment.FormPdfTemplate;
import se.streamsource.streamflow.web.domain.structure.caze.Case;
import se.streamsource.streamflow.web.domain.structure.customer.Customer;
import se.streamsource.streamflow.web.domain.structure.customer.Customers;
import se.streamsource.streamflow.web.domain.structure.form.FieldValueDefinition;
import se.streamsource.streamflow.web.domain.structure.form.FormDraft;
import se.streamsource.streamflow.web.domain.structure.form.MailSelectionMessage;
import se.streamsource.streamflow.web.domain.structure.form.RequiredSignatures;
import se.streamsource.streamflow.web.domain.structure.form.SubmittedFormValue;
import se.streamsource.streamflow.web.domain.structure.form.SubmittedForms;
import se.streamsource.streamflow.web.domain.structure.organization.AccessPoint;
import se.streamsource.streamflow.web.domain.structure.project.filter.Filters;
import se.streamsource.streamflow.web.domain.structure.user.ProxyUser;
import se.streamsource.streamflow.web.infrastructure.attachment.AttachmentStore;
import se.streamsource.streamflow.web.infrastructure.attachment.OutputstreamInput;
import se.streamsource.streamflow.web.rest.service.mail.MailSenderService;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import static se.streamsource.dci.api.RoleMap.*;
/**
* JAVADOC
*/
@Mixins(TaskFormDraftSummaryContext.Mixin.class)
public interface TaskFormDraftSummaryContext extends Context, MailSender, IndexContext<FormDraftDTO>
{
void submitandsend();
RequiredSignaturesValue signatures();
StringValue mailselectionmessage();
void enablemailmessage();
void disablemailmessage();
void changeemailstobenotified(StringValue message);
abstract class Mixin implements TaskFormDraftSummaryContext
{
protected ApplyFilterContext applyFilterContext;
private HtmlMailGenerator htmlGenerator;
public Mixin(@Structure Module module, @This MailSender mailSender, @Service AttachmentStore attachmentStore, @Service SystemDefaultsService systemDefaults
)
{
applyFilterContext = new ApplyFilterContext(module, mailSender, attachmentStore, systemDefaults);
htmlGenerator = module.objectBuilderFactory().newObject( HtmlMailGenerator.class );
}
@Structure
Module module;
@Service
PdfGeneratorService pdfGenerator;
@Uses
Locale locale;
@Optional
@Service
MailSenderService mailSender;
@Structure
ValueBuilderFactory vbf;
@Service
AttachmentStore attachmentStore;
final Logger logger = LoggerFactory.getLogger( SubmittedForms.class.getName() );
public FormDraftDTO index()
{
return RoleMap.role( FormDraftDTO.class );
}
public void submitandsend()
{
FormDraft formSubmission = RoleMap.role( FormDraft.class );
Case aCase = RoleMap.role( Case.class );
// Get the signature
FormSignatureDTO signature = formSubmission.getFormDraftValue().signatures().get().get( 0 );
StringBuilder queryBuilder = new StringBuilder();
queryBuilder.append( " type:se.streamsource.streamflow.web.domain.entity.customer.CustomerEntity" );
queryBuilder.append( " contactId:" + signature.signerId().get() );
Query<Customer> query = module.queryBuilderFactory()
.newNamedQuery( Customer.class, module.unitOfWorkFactory().currentUnitOfWork(), "solrquery" )
.setVariable( "query", queryBuilder.toString() );
Customer customer = null;
if (query.iterator().hasNext())
{
customer = query.iterator().next();
} else
{
Customers customers = module.unitOfWorkFactory().currentUnitOfWork().get( Customers.class, CustomersEntity.CUSTOMERS_ID );
customer = customers.createCustomerById( signature.signerId().get(), signature.name().get());
}
RoleMap.current().set( customer , CustomerEntity.class );
// Add contact info for signatories
ContactBuilder builder = new ContactBuilder( module.valueBuilderFactory() );
builder.name( signature.signerName().get() ).contactId( signature.signerId().get() );
aCase.addContact( builder.newInstance() );
aCase.submitForm( formSubmission, customer );
FormDraftDTO form = role( FormDraftDTO.class );
if (form.mailSelectionEnablement().get() != null && form.mailSelectionEnablement().get())
{
try
{
SubmittedForms.Data data = RoleMap.role( SubmittedForms.Data.class );
SubmittedFormValue submittedFormValue = null;
for (SubmittedFormValue value : data.submittedForms().get())
{
if (value.form().get().identity().equals( form.form().get().identity() ))
{
submittedFormValue = value;
}
}
if (submittedFormValue != null)
{
// find all form attachments and attach them to the email as
// well
List<AttachedFileValue> formAttachments = new ArrayList<AttachedFileValue>();
for (SubmittedFieldValue value : submittedFormValue.fields())
{
FieldValueDefinition.Data field = module.unitOfWorkFactory().currentUnitOfWork()
.get( FieldValueDefinition.Data.class, value.field().get().identity() );
if (field.fieldValue().get() instanceof AttachmentFieldValue)
{
if (!Strings.empty( value.value().get() ))
{
AttachmentFieldSubmission currentFormDraftAttachmentField = module.valueBuilderFactory()
.newValueFromJSON( AttachmentFieldSubmission.class, value.value().get() );
AttachmentEntity attachment = module
.unitOfWorkFactory()
.currentUnitOfWork()
.get( AttachmentEntity.class,
currentFormDraftAttachmentField.attachment().get().identity() );
ValueBuilder<AttachedFileValue> formAttachment = module.valueBuilderFactory()
.newValueBuilder( AttachedFileValue.class );
formAttachment
.prototype()
.mimeType()
.set( URLConnection.guessContentTypeFromName( currentFormDraftAttachmentField.name()
.get() ) );
formAttachment.prototype().uri().set( attachment.uri().get() );
formAttachment.prototype().modificationDate().set( attachment.modificationDate().get() );
formAttachment.prototype().name().set( currentFormDraftAttachmentField.name().get() );
formAttachment.prototype().size()
.set( attachmentStore.getAttachmentSize( attachment.uri().get() ) );
formAttachments.add( formAttachment.newInstance() );
}
}
}
notifyByMail( submittedFormValue, form.enteredEmails().get(), formAttachments );
}
} catch (Throwable throwable)
{
logger.error( "Could not send mail", throwable );
}
}
// Apply filter if they exist.
Owner owner = ((CaseEntity)aCase).owner().get();
if (owner instanceof Filters.Data)
{
applyFilterContext.rebind((Filters.Data) owner, (CaseEntity)aCase).applyFilters();
}
}
public RequiredSignaturesValue signatures()
{
RequiredSignatures.Data data = role( RequiredSignatures.Data.class );
ValueBuilder<RequiredSignaturesValue> valueBuilder = module.valueBuilderFactory().newValueBuilder(
RequiredSignaturesValue.class );
valueBuilder.prototype().signatures().get()
.add( data.requiredSignatures().get().get( 1 ).<RequiredSignatureValue> buildWith().newInstance() );
return valueBuilder.newInstance();
}
public StringValue mailselectionmessage()
{
String message = RoleMap.current().get( MailSelectionMessage.Data.class ).mailSelectionMessage().get();
ValueBuilder<StringValue> builder = module.valueBuilderFactory().newValueBuilder( StringValue.class );
if (message == null)
{
message = "";
}
builder.prototype().string().set( message );
return builder.newInstance();
}
public void enablemailmessage()
{
FormDraft formDraft = role( FormDraft.class );
formDraft.enableEmailMessage();
}
public void disablemailmessage()
{
FormDraft formDraft = role( FormDraft.class );
formDraft.disableEmailMessage();
}
public void changeemailstobenotified(StringValue message)
{
FormDraft formDraft = role( FormDraft.class );
formDraft.changeEmailsToBeNotified( message );
}
private PDDocument generatePdf(SubmittedFormValue submittedFormValue) throws Throwable
{
FormDraftDTO form = role( FormDraftDTO.class );
FormPdfTemplate.Data selectedTemplate = role( FormPdfTemplate.Data.class );
AttachedFile.Data template = (AttachedFile.Data) selectedTemplate.formPdfTemplate().get();
if (template == null)
{
ProxyUser proxyUser = role( ProxyUser.class );
template = (AttachedFile.Data) ((FormPdfTemplate.Data) proxyUser.organization().get()).formPdfTemplate()
.get();
if (template == null)
{
template = (AttachedFile.Data) ((DefaultPdfTemplate.Data) proxyUser.organization().get())
.defaultPdfTemplate().get();
}
}
String uri = null;
if (template != null)
{
uri = template.uri().get();
}
CaseId.Data idData = role( CaseId.Data.class );
return pdfGenerator.generateSubmittedFormPdf( submittedFormValue, idData, uri, locale );
}
private void notifyByMail(SubmittedFormValue form, String emails, List<AttachedFileValue> formAttachments)
throws Throwable
{
String[] mails = emails.split( "," );
PDDocument document = generatePdf( form );
// TODO handle case attachments: also attach them to the mail
AccessPoint role = role( AccessPoint.class );
Date submittedOn = form.submissionDate().get();
mailFormPDF( role.getDescription(), submittedOn, document, formAttachments, mails );
}
private void mailFormPDF(String accessPointName, Date submittedOn, PDDocument document,
List<AttachedFileValue> formAttachments, String... recipients)
{
ResourceBundle bundle = ResourceBundle.getBundle( TaskFormDraftSummaryContext.class.getName(), locale );
try
{
String id = addToAttachmentStore( document );
for (String recipient : recipients)
{
ValueBuilder<EmailValue> builder = vbf.newValueBuilder( EmailValue.class );
// leave from address and fromName empty to allow mail sender to
// pick up
// default values from mail sender configuration
builder.prototype().subject().set( accessPointName );
builder.prototype().content().set( htmlGenerator.createMailContent( bundle.getString( "mail_notification_body" ), "" ) );
builder.prototype().contentType().set( Translator.HTML );
builder.prototype().to().set( recipient );
List<AttachedFileValue> attachments = builder.prototype().attachments().get();
ValueBuilder<AttachedFileValue> attachment = vbf.newValueBuilder( AttachedFileValue.class );
attachment.prototype().mimeType().set( "application/pdf" );
attachment.prototype().uri().set( "store:" + id );
attachment.prototype().modificationDate().set( submittedOn );
attachment.prototype().name().set( accessPointName + ".pdf" );
attachment.prototype().size().set( attachmentStore.getAttachmentSize( id ) );
attachments.add( attachment.newInstance() );
if (formAttachments.size() > 0)
{
for (AttachedFileValue formAttachment : formAttachments)
{
attachments.add( formAttachment );
}
}
mailSender.sentEmail( builder.newInstance() );
}
} catch (Throwable throwable)
{
logger.error( "Could not send mail", throwable );
}
}
private String addToAttachmentStore(final PDDocument pdf) throws Throwable
{
// Store case as PDF for attachment purposes
ValueBuilder<CaseOutputConfigDTO> config = vbf.newValueBuilder( CaseOutputConfigDTO.class );
config.prototype().attachments().set( true );
config.prototype().contacts().set( true );
config.prototype().conversations().set( true );
config.prototype().submittedForms().set( true );
config.prototype().caselog().set( true );
RoleMap.current().set( new Locale( "SV", "se" ) );
String id = attachmentStore.storeAttachment( new OutputstreamInput( new Visitor<OutputStream, IOException>()
{
public boolean visit(OutputStream out) throws IOException
{
COSWriter writer = new COSWriter( out );
try
{
writer.write( pdf );
} catch (COSVisitorException e)
{
throw new IOException( e );
} finally
{
writer.close();
}
return true;
}
}, 4096 ) );
pdf.close();
return id;
}
}
}