Skip to content

Commit

Permalink
SAK-31174
Browse files Browse the repository at this point in the history
Attachments sent to email archive from Email tool arent accessible
  • Loading branch information
buckett authored and Miguel Carro Pellicer committed May 10, 2016
1 parent 1a27a90 commit 97792e8
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,16 @@ List<String> sendEmail(ConfigEntry config, String fromEmail, String fromName,
/**
* Append email to Email Archive
*
* @param config
* @param channelRef
* @param sender
* @param subject
* @param body
* @param config The config used by the user, can be <code>null</code>.
* @param channelRef The Email Archive channel reference to add the email to.
* @param sender The email sender (eg John Smith &lt;[email protected]&gt;)
* @param subject The Subject of the email.
* @param body The body of the email message.
* @param attachments A list of attachments, can be <code>null</code>.
* @return true if success
*/
boolean addToArchive(ConfigEntry config, String channelRef, String sender, String subject,
String body);
String body, List<Attachment> attachments);

/**
* @return the current location id of the current user
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,8 @@

import static org.sakaiproject.mailsender.logic.impl.MailConstants.PROTOCOL_SMTP;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.io.InputStream;
import java.util.*;
import java.util.Map.Entry;

import javax.mail.MessagingException;
Expand All @@ -33,6 +30,8 @@
import org.sakaiproject.authz.api.FunctionManager;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.content.api.ContentHostingService;
import org.sakaiproject.content.api.ContentResource;
import org.sakaiproject.email.api.AddressValidationException;
import org.sakaiproject.email.api.Attachment;
import org.sakaiproject.email.api.ContentType;
Expand All @@ -41,6 +40,10 @@
import org.sakaiproject.email.api.EmailMessage;
import org.sakaiproject.email.api.EmailService;
import org.sakaiproject.email.api.NoRecipientsException;
import org.sakaiproject.entity.api.EntityManager;
import org.sakaiproject.entity.api.Reference;
import org.sakaiproject.entity.api.ResourceProperties;
import org.sakaiproject.entity.api.ResourcePropertiesEdit;
import org.sakaiproject.event.api.Event;
import org.sakaiproject.event.api.EventTrackingService;
import org.sakaiproject.event.api.NotificationService;
Expand All @@ -61,6 +64,7 @@
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.user.api.UserNotDefinedException;
import org.sakaiproject.util.Validator;

/**
* This is the implementation for logic which is external to our app logic
Expand All @@ -81,6 +85,8 @@ public class ExternalLogicImpl implements ExternalLogic
private EmailService emailService;
private ServerConfigurationService configService;
private EventTrackingService eventService;
private ContentHostingService contentHostingService;
private EntityManager entityManager;

/**
* Place any code that should run when this class is initialized by spring here
Expand Down Expand Up @@ -261,13 +267,18 @@ public boolean isEmailArchiveAddedToSite()
}

public boolean addToArchive(ConfigEntry config, String channelRef, String sender,
String subject, String body)
String subject, String body, List<Attachment> attachments)
{
if (config == null)
{
config = ConfigEntry.DEFAULT_CONFIG;
}

if (attachments == null)
{
attachments = Collections.EMPTY_LIST;
}

boolean retval = true;
MailArchiveChannel channel = null;
try
Expand Down Expand Up @@ -316,6 +327,15 @@ public boolean addToArchive(ConfigEntry config, String channelRef, String sender
header.setFromAddress(sender);
header.setDateSent(timeService.newTime());
header.setMailHeaders(mailHeaders);
// List of references needed.
List<Reference> refs = new ArrayList<Reference>();
for(Attachment attachment : attachments) {
ContentResource resource = createAttachment(channel.getContext(), attachment.getContentTypeHeader(),
attachment.getFilename(), attachment.getDataSource().getInputStream(), edit.getId());
if (resource != null) {
header.addAttachment(entityManager.newReference(resource.getReference()));
}
}
channel.commitMessage(edit, NotificationService.NOTI_NONE);
}
catch (Exception e)
Expand All @@ -326,6 +346,34 @@ public boolean addToArchive(ConfigEntry config, String channelRef, String sender
return retval;
}

protected ContentResource createAttachment(String siteId, String type, String fileName, InputStream in, String id) {
// we just want the file name part - strip off any drive and path stuff
// This shouldn't be necessary as it's already been processed.
String resourceName = Validator.escapeResourceName(fileName);

// make a set of properties to add for the new resource
ResourcePropertiesEdit props = contentHostingService.newResourceProperties();
props.addProperty(ResourceProperties.PROP_DISPLAY_NAME, fileName);
props.addProperty(ResourceProperties.PROP_DESCRIPTION, fileName);

// make an attachment resource for this URL
try {
ContentResource attachment;
if (siteId == null) {
attachment = contentHostingService.addAttachmentResource(resourceName, type, in, props);
} else {
attachment = contentHostingService.addAttachmentResource(resourceName, siteId, null, type, in, props);
}

log.debug(id + " : attachment: " + attachment.getReference() + " size: " + attachment.getContentLength());

return attachment;
} catch (Exception any) {
log.warn(id + " : exception adding attachment resource: " + fileName + " : " + any.toString());
return null;
}
}

public List<String> sendEmail(ConfigEntry config, String fromEmail, String fromName,
Map<String, String> to, String subject, String content,
List<Attachment> attachments) throws MailsenderException, AttachmentException
Expand Down Expand Up @@ -525,4 +573,12 @@ public void setServerConfigurationService(ServerConfigurationService configServi
public void setEventTrackingService(EventTrackingService eventService) {
this.eventService = eventService;
}

public void setContentHostingService(ContentHostingService contentHostingService) {
this.contentHostingService = contentHostingService;
}

public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;

Expand All @@ -41,7 +42,14 @@
import org.sakaiproject.authz.api.FunctionManager;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.content.api.ContentHostingService;
import org.sakaiproject.content.api.ContentResource;
import org.sakaiproject.email.api.Attachment;
import org.sakaiproject.email.api.EmailService;
import org.sakaiproject.entity.api.EntityManager;
import org.sakaiproject.entity.api.Reference;
import org.sakaiproject.entity.api.ResourceProperties;
import org.sakaiproject.entity.api.ResourcePropertiesEdit;
import org.sakaiproject.event.api.EventTrackingService;
import org.sakaiproject.event.api.NotificationService;
import org.sakaiproject.exception.IdUnusedException;
Expand All @@ -61,6 +69,8 @@
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.user.api.UserNotDefinedException;

import javax.activation.DataSource;

/**
* @author chall
*
Expand Down Expand Up @@ -95,6 +105,10 @@ public class ExternalLogicImplTest {
ServerConfigurationService configService;
@Mock
EventTrackingService eventService;
@Mock
EntityManager entityManager;
@Mock
ContentHostingService contentHostingService;

static final String LOCATION_ID = "locationId";
static final String LOCATION_TITLE = "Location Title";
Expand Down Expand Up @@ -128,6 +142,8 @@ public void setUp() throws Exception {
impl.setUserDirectoryService(userDirectoryService);
impl.setServerConfigurationService(configService);
impl.setEventTrackingService(eventService);
impl.setEntityManager(entityManager);
impl.setContentHostingService(contentHostingService);

impl.init();
}
Expand Down Expand Up @@ -309,16 +325,57 @@ public void emailArchiveIsNotAddedToSite() throws Exception {

// #1
assertFalse("Permission exception from getMailArchiveChannel() should return false",
impl.addToArchive(null, "channel", null, null, null));
impl.addToArchive(null, "channel", null, null, null, null));
// #2
assertFalse("Need a non-null channel",
impl.addToArchive(null, "channel", null, null, null));
impl.addToArchive(null, "channel", null, null, null, null));
// #3
assertFalse("Permission exception from addMessage() should return false",
impl.addToArchive(null, "channel", null, null, null));
impl.addToArchive(null, "channel", null, null, null, null));
// #4
assertTrue(impl.addToArchive(null, "channel", null, null, null));
assertTrue(impl.addToArchive(null, "channel", null, null, null, null));

verify(channel).commitMessage(eq(msg), eq(NotificationService.NOTI_NONE));
}

@Test
public void sendEmailToArchiveWithAttachments() throws Exception {
// Simple test of adding email to archive.
MailArchiveChannel channel = mock(MailArchiveChannel.class);
MailArchiveMessageEdit message = mock(MailArchiveMessageEdit.class);
MailArchiveMessageHeaderEdit headers = mock(MailArchiveMessageHeaderEdit.class);

when(channel.addMessage()).thenReturn(message);
when(message.getMailArchiveHeaderEdit()).thenReturn(headers);
when(message.getId()).thenReturn("messageId");

when(channel.getContext()).thenReturn("siteId");

ContentResource resource = mock(ContentResource.class);
ResourcePropertiesEdit attachmentProperties = mock(ResourcePropertiesEdit.class);

when(contentHostingService.newResourceProperties()).thenReturn(attachmentProperties);
when(contentHostingService.addAttachmentResource(
anyString(), anyString(), anyString(), anyString(), any(InputStream.class), any(ResourceProperties.class)
)).thenReturn(resource);
when(resource.getReference()).thenReturn("attachmentReference");

Reference ref = mock(Reference.class);
when(entityManager.newReference("attachmentReference")).thenReturn(ref);

when(mailArchiveService.getMailArchiveChannel("channel")).thenReturn(channel);

DataSource dataSource = mock(DataSource.class);
when(dataSource.getInputStream()).thenReturn(new ByteArrayInputStream("Hello World".getBytes("UTF-8")));
Attachment attachment = mock(Attachment.class);
when(attachment.getContentTypeHeader()).thenReturn("text/plain");
when(attachment.getFilename()).thenReturn("test.txt");
when(attachment.getDataSource()).thenReturn(dataSource);

impl.addToArchive(null, "channel", "[email protected]", "Subject", "Body Message",
Collections.singletonList(attachment));

verify(channel).commitMessage(message, NotificationService.NOTI_NONE);
verify(headers).addAttachment(ref);
}
}
2 changes: 2 additions & 0 deletions mailsender/pack/src/webapp/WEB-INF/components.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
<property name="emailService" ref="org.sakaiproject.email.api.EmailService" />
<property name="serverConfigurationService" ref="org.sakaiproject.component.api.ServerConfigurationService" />
<property name="eventTrackingService" ref="org.sakaiproject.event.api.EventTrackingService" />
<property name="contentHostingService" ref="org.sakaiproject.content.api.ContentHostingService"/>
<property name="entityManager" ref="org.sakaiproject.entity.api.EntityManager"/>
</bean>

<bean id="org.sakaiproject.mailsender.logic.ComposeLogic"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ public String sendEmail()
if (multipartMap != null && !multipartMap.isEmpty()) {
for (Entry<String, MultipartFile> entry : multipartMap.entrySet()) {
MultipartFile mf = entry.getValue();
// Although JavaDoc says it may contain path, Commons implementation always just
// returns the filename without the path.
String filename = mf.getOriginalFilename();
try
{
Expand All @@ -228,12 +230,12 @@ public String sendEmail()
// send the message
invalids = externalLogic.sendEmail(config, fromEmail, fromDisplay,
emailusers, subject, content, attachments);
}
// append to the email archive
String siteId = externalLogic.getSiteID();
String fromString = fromDisplay + " <" + fromEmail + ">";
addToArchive(config, fromString, subject, siteId, attachments);

// append to the email archive
String siteId = externalLogic.getSiteID();
String fromString = fromDisplay + " <" + fromEmail + ">";
addToArchive(config, fromString, subject, siteId);
}

// build output message for results screen
for (Entry<String, String> entry : emailusers.entrySet())
Expand Down Expand Up @@ -304,7 +306,7 @@ public String sendEmail()
return EMAIL_SENT;
}

private void addToArchive(ConfigEntry config, String fromString, String subject, String siteId)
private void addToArchive(ConfigEntry config, String fromString, String subject, String siteId, List<Attachment> attachments)
{
if (emailEntry.getConfig().isAddToArchive())
{
Expand All @@ -322,7 +324,7 @@ private void addToArchive(ConfigEntry config, String fromString, String subject,
}
String emailarchive = "/mailarchive/channel/" + siteId + "/main";
String content = Web.cleanHtml(emailEntry.getContent()) + attachment_info.toString();
externalLogic.addToArchive(config, emailarchive, fromString, subject, content);
externalLogic.addToArchive(config, emailarchive, fromString, subject, content, attachments);
}
}

Expand Down

0 comments on commit 97792e8

Please sign in to comment.