package com.google.ytd.util;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.BodyPart;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMultipart;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.mail.MailService;
import com.google.appengine.api.mail.MailServiceFactory;
import com.google.appengine.api.mail.MailService.Message;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.ytd.dao.AdminConfigDao;
import com.google.ytd.model.AdminConfig;
import com.google.ytd.model.PhotoEntry;
import com.google.ytd.model.PhotoSubmission;
import com.google.ytd.model.VideoSubmission;
import com.google.ytd.model.VideoSubmission.ModerationStatus;
@Singleton
public class EmailUtil {
private static final Logger log = Logger.getLogger(EmailUtil.class.getName());
@Inject
private AdminConfigDao adminConfigDao;
@Inject
private Util util;
public void sendPhotoEntryToAdmins(PhotoEntry photoEntry) {
log.info(
String.format("Sending photo from PhotoEntry id '%s' to admins...", photoEntry.getId()));
AdminConfig adminConfig = adminConfigDao.getAdminConfig();
MailService mailService = MailServiceFactory.getMailService();
Message message = new Message();
try {
String fromAddress = adminConfig.getFromAddress();
if (util.isNullOrEmpty(fromAddress)) {
throw new IllegalArgumentException("No from address found in configuration.");
}
message.setSubject("Unable to submit photo to Picasa");
message.setSender(fromAddress);
message.setTextBody("YouTube Direct was unable to upload a photo submission to Picasa.\n\n"
+ "There might be a service issue, or your Picasa configuration might be incorrect.\n\n"
+ "The photo in question is attached.");
BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
byte[] photoBytes = blobstoreService.fetchData(
photoEntry.getBlobKey(), 0, photoEntry.getOriginalFileSize() - 1);
MailService.Attachment photoAttachment =
new MailService.Attachment(photoEntry.getOriginalFileName(), photoBytes);
message.setAttachments(photoAttachment);
mailService.sendToAdmins(message);
log.info("Email sent to admins.");
} catch (IOException e) {
log.log(Level.WARNING, "", e);
} catch (IllegalArgumentException e) {
log.log(Level.WARNING, "", e);
}
}
private void sendNewSubmissionEmail(String subject, String body) {
try {
AdminConfig adminConfig = adminConfigDao.getAdminConfig();
String addressCommaSeparated = adminConfig.getNewSubmissionAddress();
if (util.isNullOrEmpty(addressCommaSeparated)) {
throw new IllegalArgumentException(
"No notification email addresses found in configuration.");
}
String[] addresses = addressCommaSeparated.split("\\s*,\\s*");
MailService mailService = MailServiceFactory.getMailService();
Message message = new Message();
// Default to the first (or only) address in the recipient list to use
// as From: header.
message.setSender(addresses[0]);
message.setTo(addresses);
message.setSubject(subject);
message.setTextBody(body);
mailService.send(message);
} catch (IOException e) {
log.log(Level.WARNING, "", e);
} catch (IllegalArgumentException e) {
log.info(e.getMessage());
}
}
public void sendNewSubmissionEmail(VideoSubmission videoSubmission) {
String subject = String.format("New video submission for assignment id %d",
videoSubmission.getAssignmentId());
String body = String.format("Video %s was submitted by YouTube user %s in response to "
+ "assignment id %d.", videoSubmission.getWatchUrl(), videoSubmission.getYouTubeName(),
videoSubmission.getAssignmentId());
sendNewSubmissionEmail(subject, body);
}
public void sendNewSubmissionEmail(PhotoEntry photoEntry, PhotoSubmission photoSubmission) {
String subject = String.format("New photo submission for assignment id %d",
photoSubmission.getAssignmentId());
String body = String.format("The following photo was submitted by %s (%s) in response to "
+ "assignment id %d:\n\n%s", photoSubmission.getAuthor(), photoSubmission.getNotifyEmail(),
photoSubmission.getAssignmentId(), photoEntry.getImageUrl());
sendNewSubmissionEmail(subject, body);
}
private void sendUserModerationEmail(String toAddress, String subject, String body) {
try {
AdminConfig adminConfig = adminConfigDao.getAdminConfig();
MailService mailService = MailServiceFactory.getMailService();
Message message = new Message();
String fromAddress = adminConfig.getFromAddress();
if (util.isNullOrEmpty(fromAddress)) {
throw new IllegalArgumentException("No from address found in configuration.");
}
message.setSender(fromAddress);
message.setTo(toAddress);
message.setSubject(subject);
message.setTextBody(body);
mailService.send(message);
} catch (IOException e) {
log.log(Level.WARNING, "", e);
} catch (IllegalArgumentException e) {
log.log(Level.WARNING, "", e);
}
}
public void sendUserModerationEmail(VideoSubmission entry, ModerationStatus status) {
try {
AdminConfig adminConfig = adminConfigDao.getAdminConfig();
String body;
switch (status) {
case APPROVED:
body = adminConfig.getApprovalEmailText();
break;
case REJECTED:
body = adminConfig.getRejectionEmailText();
break;
default:
throw new IllegalArgumentException(String.format("ModerationStatus %s is not valid.",
status.toString()));
}
if (util.isNullOrEmpty(body)) {
throw new IllegalArgumentException("No email body found in configuration.");
}
body = body.replace("ARTICLE_URL", entry.getArticleUrl());
body = body.replace("YOUTUBE_URL", entry.getWatchUrl());
body = body.replace("MEDIA_URL", entry.getWatchUrl());
String toAddress = entry.getNotifyEmail();
if (util.isNullOrEmpty(toAddress)) {
throw new IllegalArgumentException("No destination email address in VideoSubmission.");
}
sendUserModerationEmail(toAddress, "Your Recent Video Submission", body);
} catch (IllegalArgumentException e) {
log.log(Level.WARNING, "", e);
}
}
public void sendUserModerationEmail(PhotoSubmission photoSubmission, PhotoEntry photoEntry,
com.google.ytd.model.PhotoEntry.ModerationStatus status) {
try {
AdminConfig adminConfig = adminConfigDao.getAdminConfig();
String body;
switch (status) {
case APPROVED:
body = adminConfig.getApprovalEmailText();
break;
case REJECTED:
body = adminConfig.getRejectionEmailText();
break;
case UNREVIEWED:
// Let's not send any email when a photo is marked as UNREVIEWED.
// This differs from the video moderation behavior, but it's arguably
// more correct.
return;
default:
throw new IllegalArgumentException(String.format("ModerationStatus %s is not valid.",
status.toString()));
}
if (util.isNullOrEmpty(body)) {
throw new IllegalArgumentException("No email body found in configuration.");
}
body = body.replace("ARTICLE_URL", photoSubmission.getArticleUrl());
if (status == com.google.ytd.model.PhotoEntry.ModerationStatus.APPROVED) {
body = body.replace("MEDIA_URL", photoEntry.getPicasaUrl());
} else {
body = body.replace("MEDIA_URL", "");
}
String toAddress = photoSubmission.getNotifyEmail();
if (util.isNullOrEmpty(toAddress)) {
throw new IllegalArgumentException("No destination email address in PhotoSubmission.");
}
sendUserModerationEmail(toAddress, "Your Recent Photo Submission", body);
} catch (IllegalArgumentException e) {
log.log(Level.WARNING, "", e);
}
}
public ArrayList<BodyPart> getAllMIMEParts(MimeMultipart mimePart) {
ArrayList<BodyPart> parts = new ArrayList<BodyPart>();
try {
for (int i = 0; i < mimePart.getCount(); i++) {
BodyPart bodyPart = mimePart.getBodyPart(i);
log.info("Subpart's content is: " + bodyPart.getContentType());
if (bodyPart.getContentType().toLowerCase().startsWith("multipart/")) {
parts.addAll(getAllMIMEParts((MimeMultipart) bodyPart.getContent()));
} else {
parts.add(bodyPart);
}
}
} catch (MessagingException e) {
log.log(Level.WARNING, "", e);
} catch (IOException e) {
log.log(Level.WARNING, "", e);
} catch (ClassCastException e) {
// I am not 100% sure that the casts will all work here, so let's catch this just to be safe.
// Worst-case scenario is that we end up missing a part in a funky multi-multi-part message.
log.log(Level.WARNING, "", e);
}
return parts;
}
}