/**
*
* 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.application.defaults;
import static org.qi4j.api.usecase.UsecaseBuilder.newUsecase;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import org.qi4j.api.configuration.Configuration;
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.mixin.Mixins;
import org.qi4j.api.query.Query;
import org.qi4j.api.service.Activatable;
import org.qi4j.api.service.ServiceComposite;
import org.qi4j.api.structure.Module;
import org.qi4j.api.unitofwork.UnitOfWork;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import se.streamsource.dci.api.RoleMap;
import se.streamsource.streamflow.api.workspace.cases.caselog.CaseLogEntryTypes;
import se.streamsource.streamflow.api.workspace.cases.conversation.MessageType;
import se.streamsource.streamflow.util.Translator;
import se.streamsource.streamflow.web.application.mail.EmailValue;
import se.streamsource.streamflow.web.domain.entity.caze.CaseEntity;
import se.streamsource.streamflow.web.domain.entity.gtd.Drafts;
import se.streamsource.streamflow.web.domain.entity.organization.OrganizationalUnitsQueries;
import se.streamsource.streamflow.web.domain.entity.organization.OrganizationsEntity;
import se.streamsource.streamflow.web.domain.entity.project.ProjectEntity;
import se.streamsource.streamflow.web.domain.entity.user.UserEntity;
import se.streamsource.streamflow.web.domain.entity.user.UsersEntity;
import se.streamsource.streamflow.web.domain.structure.attachment.AttachedFileValue;
import se.streamsource.streamflow.web.domain.structure.attachment.Attachment;
import se.streamsource.streamflow.web.domain.structure.casetype.CaseType;
import se.streamsource.streamflow.web.domain.structure.conversation.Conversation;
import se.streamsource.streamflow.web.domain.structure.conversation.ConversationParticipant;
import se.streamsource.streamflow.web.domain.structure.created.Creator;
import se.streamsource.streamflow.web.domain.structure.organization.Organization;
import se.streamsource.streamflow.web.domain.structure.organization.OrganizationalUnit;
import se.streamsource.streamflow.web.domain.structure.organization.Organizations;
import se.streamsource.streamflow.web.domain.structure.project.Project;
import se.streamsource.streamflow.web.domain.structure.user.Contactable;
import se.streamsource.streamflow.web.domain.structure.user.Users;
import se.streamsource.streamflow.web.infrastructure.caching.Caches;
import se.streamsource.streamflow.web.infrastructure.caching.Caching;
import se.streamsource.streamflow.web.infrastructure.caching.CachingService;
/**
* A service holding system default configuration properties.
*/
@Mixins(SystemDefaultsService.Mixin.class)
public interface SystemDefaultsService
extends ServiceComposite, Configuration, Activatable
{
public Configuration<SystemDefaultsConfiguration> config();
public void createCaseOnEmailFailure( EmailValue email );
public void createCaseOnSendMailFailure( EmailValue email, Throwable originalException );
public Drafts getUser( EmailValue email );
abstract class Mixin
implements SystemDefaultsService, Activatable
{
@Structure
Module module;
@Service
CachingService cache;
Caching caching;
@This
Configuration<SystemDefaultsConfiguration> config;
private Logger logger;
public Configuration<SystemDefaultsConfiguration> config()
{
return config;
}
public void activate() throws Exception
{
// Read arbitrary property just to activate config-handler
config().configuration().enabled();
caching = new Caching(cache, Caches.CASECOUNTS);
logger = LoggerFactory.getLogger(SystemDefaultsService.class);
}
public void createCaseOnEmailFailure( EmailValue email )
{
UnitOfWork uow = module.unitOfWorkFactory().newUnitOfWork( newUsecase( "Create case on email failure" ) );
RoleMap.newCurrentRoleMap();
try
{
Organizations.Data organizations = uow.get( Organizations.Data.class, OrganizationsEntity.ORGANIZATIONS_ID );
Organization organization = organizations.organization().get();
OrganizationalUnit ou = ((OrganizationalUnitsQueries) organization).getOrganizationalUnitByName( config.configuration().supportOrganizationName().get() );
Project project = ou.getProjectByName( config.configuration().supportProjectName().get() );
CaseType caseType = project.getCaseTypeByName( config.configuration().supportCaseTypeForIncomingEmailName().get() );
Drafts user = getUser( email );
ConversationParticipant participant = (ConversationParticipant) user;
RoleMap.current().set( organization );
RoleMap.current().set( project );
RoleMap.current().set( user );
CaseEntity caze = user.createDraft();
caze.changeCaseType( caseType );
caze.changeOwner( project );
RoleMap.current().set( caze );
caze.caselog().get().addTypedEntry( "{receivererror,description=Could not parse email.}", CaseLogEntryTypes.system );
caze.changeDescription( email.subject().get() );
// Create conversation
Conversation conversation = caze.createConversation( email.subject().get(), (Creator) user );
if( Translator.HTML.equalsIgnoreCase( email.contentType().get() ))
{
caze.addNote( email.contentHtml().get() == null ? email.content().get() : email.contentHtml().get(), Translator.HTML );
conversation.createMessage( email.content().get(), MessageType.HTML, participant );
} else
{
caze.addNote( email.content().get(), Translator.PLAIN );
conversation.createMessage( email.content().get(), MessageType.PLAIN, participant );
}
// Create attachments
for (AttachedFileValue attachedFileValue : email.attachments().get())
{
Attachment attachment = caze.createAttachment( attachedFileValue.uri().get() );
attachment.changeName( attachedFileValue.name().get() );
attachment.changeMimeType( attachedFileValue.mimeType().get() );
attachment.changeModificationDate( attachedFileValue.modificationDate().get() );
attachment.changeSize( attachedFileValue.size().get() );
attachment.changeUri( attachedFileValue.uri().get() );
}
// Add contact info
caze.updateContact(0, ((Contactable.Data)user).contact().get());
// open the case
caze.open();
caching.addToCaseCountCache( ((ProjectEntity)project).identity().get(), 1 );
uow.complete();
} catch (Exception e)
{
e.printStackTrace();
uow.discard();
} finally
{
RoleMap.clearCurrentRoleMap();
}
}
public Drafts getUser(EmailValue email)
{
// Try to find real user first
Query<Drafts> finduserwithemail = module.queryBuilderFactory().newNamedQuery(Drafts.class, module.unitOfWorkFactory().currentUnitOfWork(), "esquery");
finduserwithemail.setVariable("query", "{\"filtered\":{\"query\":{\"match_all\":{}},\"filter\":{\"and\":{\"filters\":[{\"term\":{\"_types\":\"se.streamsource.streamflow.web.domain.entity.gtd.Drafts\"}},{\"term\":{\"contact.emailAddresses.emailAddress\":\"" + email.from().get() + "\"}}]}}}}");
Drafts user = finduserwithemail.find();
// Create email user
if (user == null)
{
user = module.unitOfWorkFactory().currentUnitOfWork().get(Users.class, UsersEntity.USERS_ID).createEmailUser(email);
}
return user;
}
public void createCaseOnSendMailFailure( EmailValue email, Throwable originalException )
{
UnitOfWork uow = module.unitOfWorkFactory().newUnitOfWork( newUsecase( "Create case on email failure" ) );
RoleMap.newCurrentRoleMap();
try
{
Organizations.Data organizations = uow.get( Organizations.Data.class, OrganizationsEntity.ORGANIZATIONS_ID );
Organization organization = organizations.organization().get();
OrganizationalUnit ou = ((OrganizationalUnitsQueries) organization).getOrganizationalUnitByName( config.configuration().supportOrganizationName().get() );
Project project = ou.getProjectByName( config.configuration().supportProjectName().get() );
CaseType caseType = project.getCaseTypeByName( config.configuration().supportCaseTypeForOutgoingEmailName().get() );
UserEntity supportUser = uow.get( UserEntity.class, UserEntity.ADMINISTRATOR_USERNAME );
ConversationParticipant participant = (ConversationParticipant) supportUser;
RoleMap.current().set( organization );
RoleMap.current().set( project );
RoleMap.current().set( supportUser );
CaseEntity caze = supportUser.createDraft();
caze.changeCaseType( caseType );
caze.changeOwner( project );
RoleMap.current().set( caze );
caze.caselog().get().addTypedEntry( "{sendmailerror,description=Could not send email.}", CaseLogEntryTypes.system );
caze.changeDescription( email.subject().get() );
if( Translator.HTML.equalsIgnoreCase( email.contentType().get() ))
{
String htmlNote = getHtmlNote(email, originalException);
caze.addNote( htmlNote, Translator.HTML );
}
else
{
String plainNote = getPlainNote(email, originalException);
caze.addNote( plainNote , Translator.PLAIN );
}
// open the case
caze.open();
caching.addToCaseCountCache( ((ProjectEntity)project).identity().get(), 1 );
uow.complete();
}
catch (Exception e) {
logger.warn("Failed createCaseOnSendMailFailure", e);
uow.discard();
}
finally {
RoleMap.clearCurrentRoleMap();
}
}
private static String getPlainNote(EmailValue email, Throwable originalException) {
StringBuilder result = new StringBuilder();
result.append(getExceptionString(originalException));
result.append("\n\n-------------------------\n");
result.append(email.content().get());
return result.toString();
}
private static String getExceptionString(Throwable t) {
StringBuilder result = new StringBuilder();
result.append(t.getMessage());
result.append("\n\n");
ByteArrayOutputStream stackTraceStream = new ByteArrayOutputStream();
t.printStackTrace(new PrintStream(stackTraceStream));
result.append(stackTraceStream.toString());
return result.toString();
}
private static String getHtmlNote(EmailValue email, Throwable originalException) {
StringBuilder result = new StringBuilder();
result.append("<pre>");
result.append(getExceptionString(originalException));
result.append("</pre><br/><br/>-------------------------<br/>");
result.append( email.contentHtml().get() == null ? email.content().get() : email.contentHtml().get());
return result.toString();
}
}
}