Skip to content

Commit d9bc636

Browse files
authored
Merge pull request #10 from objectcomputing/makeemails
this is blasphemy...but we need to keep progress for now. :-)
2 parents d0a843f + 6fa22af commit d9bc636

11 files changed

Lines changed: 402 additions & 28 deletions

File tree

send-surveys/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ dependencies {
5555

5656
compile 'io.micronaut.data:micronaut-data-jdbc:1.0.0.M5'
5757
compile 'com.github.spullara.mustache.java:compiler:0.9.6'
58+
compile "com.sun.mail:javax.mail:1.6.2"
59+
compile "com.google.api-client:google-api-client:1.28.0"
60+
compile "com.google.oauth-client:google-oauth-client-jetty:1.28.0"
61+
compile "com.google.apis:google-api-services-drive:v3-rev20190501-1.28.0"
62+
compile "com.google.apis:google-api-services-gmail:v1-rev20190422-1.28.0"
5863
runtime group: 'org.postgresql', name: 'postgresql', version: '42.2.9'
5964
compile 'joda-time:joda-time:2.10.5'
6065
compile("org.postgresql:postgresql:9.4.1207")
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package com.objectcomputing.pulsesurvey.email.manager;
2+
3+
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
4+
import com.google.api.client.http.HttpTransport;
5+
import com.google.api.client.json.JsonFactory;
6+
import com.google.api.client.json.jackson2.JacksonFactory;
7+
import com.google.api.client.util.Base64;
8+
import com.google.api.services.gmail.Gmail;
9+
import com.google.api.services.gmail.model.Message;
10+
import io.micronaut.context.annotation.Property;
11+
import org.slf4j.Logger;
12+
import org.slf4j.LoggerFactory;
13+
14+
import javax.inject.Inject;
15+
import javax.inject.Singleton;
16+
import javax.mail.MessagingException;
17+
import javax.mail.Session;
18+
import javax.mail.internet.InternetAddress;
19+
import javax.mail.internet.MimeMessage;
20+
import java.io.ByteArrayOutputStream;
21+
import java.io.IOException;
22+
import java.net.Authenticator;
23+
import java.net.PasswordAuthentication;
24+
import java.security.GeneralSecurityException;
25+
import java.util.Map;
26+
import java.util.Properties;
27+
28+
@Singleton
29+
public class GmailSender {
30+
31+
private final HttpTransport httpTransport;
32+
private final JsonFactory jsonFactory;
33+
private final GoogleAuthenticator authenticator;
34+
private final String applicationName;
35+
private static final Logger LOG = LoggerFactory.getLogger(GmailSender.class);
36+
37+
@Inject
38+
GmailSender(
39+
@Property(name = "oci-google-drive.application.name") String applicationName,
40+
GoogleAuthenticator authenticator) throws GeneralSecurityException, IOException {
41+
this.applicationName = applicationName;
42+
this.authenticator = authenticator;
43+
this.httpTransport = GoogleNetHttpTransport.newTrustedTransport();
44+
this.jsonFactory = JacksonFactory.getDefaultInstance();
45+
}
46+
47+
Gmail getService() throws IOException {
48+
return new Gmail.Builder(httpTransport, jsonFactory, authenticator.setupCredentials())
49+
.setApplicationName(applicationName)
50+
.build();
51+
}
52+
53+
public void sendEmail(String subject, String emailAddress, String emailMessage) {
54+
try {
55+
Gmail emailService = getService();
56+
LOG.info("Email Address: " + emailAddress);
57+
LOG.info("Email body: " + emailMessage);
58+
59+
Properties props = new Properties();
60+
Session session = Session.getDefaultInstance(props, null);
61+
MimeMessage emailContent = new MimeMessage(session);
62+
emailContent.setFrom("kimberlinm@objectcomputing.com");
63+
emailContent.addRecipient(javax.mail.Message.RecipientType.TO,
64+
new InternetAddress("williamsh@objectcomputing.com"));
65+
emailContent.setSubject(subject);
66+
emailContent.setText(emailMessage);
67+
/*.setContent(html code) will have to be constructed from template */
68+
Message message = createMessageWithEmail(emailContent);
69+
message = emailService.users().messages().send("kimberlinm@objectcomputing.com", message).execute();
70+
71+
LOG.info("Message id: " + message.getId());
72+
LOG.info(message.toPrettyString());
73+
LOG.info("Email Sent: " + subject + " to " + emailAddress + "\n");
74+
} catch (IOException e) {
75+
LOG.error("IOException: " + e.getMessage());
76+
e.printStackTrace();
77+
} catch (MessagingException e) {
78+
LOG.error("MessagingException: " + e.getMessage());
79+
e.printStackTrace();
80+
}
81+
82+
}
83+
84+
/**
85+
* Create a message from an email. Converts Mime to gmail format
86+
*
87+
* @param emailContent Email to be set to raw of message
88+
* @return a message containing a base64url encoded email
89+
* @throws IOException
90+
* @throws MessagingException
91+
*/
92+
public static Message createMessageWithEmail(MimeMessage emailContent)
93+
throws MessagingException, IOException {
94+
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
95+
emailContent.writeTo(buffer);
96+
byte[] bytes = buffer.toByteArray();
97+
String encodedEmail = Base64.encodeBase64URLSafeString(bytes);
98+
Message message = new Message();
99+
message.setRaw(encodedEmail);
100+
return message;
101+
}
102+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.objectcomputing.pulsesurvey.email.manager;
2+
3+
4+
import com.google.api.client.auth.oauth2.Credential;
5+
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
6+
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
7+
import com.google.api.client.http.javanet.NetHttpTransport;
8+
import com.google.api.client.json.JsonFactory;
9+
import com.google.api.client.json.jackson2.JacksonFactory;
10+
import io.micronaut.context.annotation.Property;
11+
12+
import javax.inject.Singleton;
13+
import java.io.FileNotFoundException;
14+
import java.io.IOException;
15+
import java.io.InputStream;
16+
import java.security.GeneralSecurityException;
17+
import java.util.Collection;
18+
19+
@Singleton
20+
public class GoogleAuthenticator {
21+
private static final String CREDENTIALS_FILE_PATH = "/secrets/credentials.json";
22+
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
23+
24+
private final NetHttpTransport httpTransport;
25+
26+
private final Collection<String> scopes;
27+
28+
/**
29+
* Creates a google drive utility for quick access
30+
*
31+
* @param scopes, the scope(s) of access to request for this application
32+
*/
33+
public GoogleAuthenticator(@Property(name = "oci-google-drive.application.scopes") Collection<String> scopes)
34+
throws GeneralSecurityException, IOException {
35+
this.httpTransport = GoogleNetHttpTransport.newTrustedTransport();
36+
this.scopes = scopes;
37+
}
38+
39+
/**
40+
* Creates an authorized Credential object.
41+
*
42+
* @return An authorized Credential object.
43+
* @throws IOException If the credentials.json file cannot be found.
44+
*/
45+
Credential setupCredentials() throws IOException {
46+
InputStream in = GoogleDriveAccessor.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
47+
if (in == null) {
48+
throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
49+
}
50+
51+
return GoogleCredential.fromStream(in, httpTransport, JSON_FACTORY).createDelegated("kimberlinm@objectcomputing.com ").createScoped(scopes);
52+
53+
}
54+
55+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.objectcomputing.pulsesurvey.email.manager;
2+
3+
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
4+
import com.google.api.client.http.javanet.NetHttpTransport;
5+
import com.google.api.client.json.JsonFactory;
6+
import com.google.api.client.json.jackson2.JacksonFactory;
7+
import com.google.api.services.drive.Drive;
8+
import io.micronaut.context.annotation.Property;
9+
10+
import javax.inject.Inject;
11+
import javax.inject.Singleton;
12+
import java.io.IOException;
13+
import java.security.GeneralSecurityException;
14+
15+
@Singleton
16+
public class GoogleDriveAccessor {
17+
18+
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
19+
20+
private final NetHttpTransport httpTransport;
21+
22+
private final String applicationName;
23+
24+
/**
25+
* Creates a google drive utility for quick access
26+
*
27+
* @param applicationName the name of this application
28+
*/
29+
public GoogleDriveAccessor(@Property(name = "oci-google-drive.application.name") String applicationName)
30+
throws GeneralSecurityException, IOException {
31+
this.httpTransport = GoogleNetHttpTransport.newTrustedTransport();
32+
this.applicationName = applicationName;
33+
}
34+
35+
@Inject
36+
private GoogleAuthenticator authenticator;
37+
38+
/**
39+
* Create and return the google drive access object
40+
*
41+
* @return a google drive access object
42+
* @throws IOException
43+
*/
44+
public Drive accessGoogleDrive() throws IOException {
45+
return new Drive
46+
.Builder(httpTransport, JSON_FACTORY, authenticator.setupCredentials())
47+
.setApplicationName(applicationName)
48+
.build();
49+
}
50+
51+
}

send-surveys/src/main/java/com/objectcomputing/pulsesurvey/model/ResponseKey.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import javax.persistence.Column;
1313

1414
@Entity
15-
@Table(name = "keys")
15+
@Table(name = "responsekeys")
1616
public class ResponseKey {
1717

1818
@Id

send-surveys/src/main/java/com/objectcomputing/pulsesurvey/send/surveys/SurveysController.java

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package com.objectcomputing.pulsesurvey.send.surveys;
22

3+
import com.objectcomputing.pulsesurvey.email.manager.GmailSender;
34
import com.objectcomputing.pulsesurvey.model.SendSurveysCommand;
45
import com.objectcomputing.pulsesurvey.model.ResponseKey;
56
import com.objectcomputing.pulsesurvey.repositories.ResponseKeyRepository;
7+
import com.objectcomputing.pulsesurvey.template.manager.SurveyTemplateManager;
68

79
import javax.inject.*;
10+
import java.io.IOException;
811
import java.util.List;
912
import java.util.ArrayList;
1013
import java.util.Map;
@@ -24,6 +27,12 @@ public class SurveysController {
2427
@Inject
2528
private ResponseKeyRepository responseKeyRepo;
2629

30+
@Inject
31+
private SurveyTemplateManager templateManager;
32+
33+
@Inject
34+
private GmailSender gmailSender;
35+
2736
class GmailApi {
2837
public List<String> getEmails() {
2938
List<String> emailAddresses = new ArrayList<>();
@@ -42,6 +51,18 @@ public void setGmailApi(GmailApi api) {
4251
this.gmail = api;
4352
}
4453

54+
public void setResponseKeyRepo(ResponseKeyRepository responseKeyRepository) {
55+
this.responseKeyRepo = responseKeyRepository;
56+
}
57+
58+
public void setTemplateManager(SurveyTemplateManager surveyTemplateManager) {
59+
this.templateManager = surveyTemplateManager;
60+
}
61+
62+
public void setGmailSender(GmailSender gmailSender) {
63+
this.gmailSender = gmailSender;
64+
}
65+
4566
/* call GetRandomEmails(what percentage of current employees) ->
4667
GetEmail(Google) -> SelectRandom -> GenerateKeys -> Map<String Email, String KeyUUID>
4768
Map gets returned */
@@ -61,14 +82,23 @@ public SendSurveys sendEmails(@Body SendSurveysCommand sendSurveysCommand) {
6182
LOG.info("Grabbing email addresses.");
6283
List<String> emailAddresses = getRandomEmailAddresses(percentOfEmailsToGet);
6384
LOG.info("Generating keys.");
64-
List<ResponseKey> keys = generateKeys(emailAddresses.size());
85+
List<ResponseKey> keys = generateAndSaveKeys(emailAddresses.size());
6586
LOG.info("Mapping emails to keys.");
6687
Map<String, String> emailKeyMap = new HashMap<String, String>();
6788
emailKeyMap = mapEmailsToKeys(emailAddresses, keys);
6889
LOG.info("And Finally - emailKeyMap: " + emailKeyMap);
6990

91+
Map<String, String> emailBodies = null;
92+
// populate the emails
93+
try {
94+
emailBodies = templateManager.populateEmails(sendSurveysCommand.getTemplateName(),
95+
emailKeyMap);
96+
} catch (IOException e) {
97+
LOG.error(e.getMessage());
98+
e.printStackTrace();
99+
}
70100
// send some emails
71-
sendTheEmails(emailKeyMap);
101+
sendTheEmails(emailBodies);
72102

73103
return new SendSurveys("Sent surveys: " + emailKeyMap.size() +
74104
" for " + sendSurveysCommand.getPercentOfEmails() +
@@ -95,7 +125,7 @@ List<String> getRandomEmailAddresses(int percentOfEmailsNeeded) {
95125
return randomSubsetEmailAddresses;
96126
}
97127

98-
List<ResponseKey> generateKeys(int howManyKeys) {
128+
List<ResponseKey> generateAndSaveKeys(int howManyKeys) {
99129

100130
List<ResponseKey> keys = new ArrayList<ResponseKey>();
101131

@@ -125,12 +155,15 @@ Map<String, String> mapEmailsToKeys(List<String> emails, List<ResponseKey> keys)
125155
return map;
126156
}
127157

128-
void sendTheEmails(Map<String, String> emailKeyMap) {
158+
void sendTheEmails(Map<String, String> emailAddressToBodiesMap) {
129159

130160
// call some google api with the list of emails to send them with a key for each
131161

132162
LOG.info("I'm sending the emails now");
133163

164+
emailAddressToBodiesMap.forEach((address, body) ->
165+
gmailSender.sendEmail("Feelings, Whoa, Whoa, Whoa, Feelings", address, body)
166+
);
134167

135168
}
136169

send-surveys/src/main/java/com/objectcomputing/pulsesurvey/template/manager/SurveyTemplateManager.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import javax.inject.Singleton;
88
import java.io.IOException;
99
import java.io.StringWriter;
10+
import java.util.HashMap;
1011
import java.util.Map;
1112

1213
@Singleton
@@ -24,6 +25,23 @@ public Mustache getMustache(String mustacheFileName) {
2425
return factory.compile(mustacheFileName + ".mustache");
2526
}
2627

28+
public Map<String, String> populateEmails(String templateFileName,
29+
Map<String, String> emailKeyMap)
30+
throws IOException {
31+
32+
Map<String, String> emailBodies = new HashMap<>();
33+
34+
int numberOfEmails = emailKeyMap.size();
35+
36+
for (Map.Entry<String, String> entry : emailKeyMap.entrySet()) {
37+
Map<String, Object> templateVariableValueMap = new HashMap<>();
38+
templateVariableValueMap.put("surveyKey", entry.getValue());
39+
emailBodies.put(entry.getKey(), populateTemplate(templateFileName, templateVariableValueMap));
40+
}
41+
42+
return emailBodies; //email addresses to html with keys
43+
}
44+
2745
public String populateTemplate(String templateFileName, Object data)
2846
throws IOException {
2947

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
micronaut:
2-
function:
2+
application:
33
name: send-surveys
44
root: src/main/resources
55

66
---
77
datasources:
88
default:
9-
url: jdbc:postgresql://pulsesurveydb.ca4gwn3eiebi.us-east-1.rds.amazonaws.com:5432/pulsesurveydb
9+
url: ${JDBC_URL:`jdbc:postgresql://localhost:5432/pulsesurveydb`}
1010
driverClassName: org.postgresql.Driver
11-
username: pulsesurvey
12-
password: 'surveyadmin321'
13-
dialect: POSTGRES
11+
username: postgres
12+
password: 'postgres'
13+
dialect: POSTGRES
14+
15+
oci-google-drive:
16+
application:
17+
dir-key: "benefits"
18+
name: "OCI Surveys"
19+
scopes:
20+
- "https://www.googleapis.com/auth/drive.file"
21+
- "https://www.googleapis.com/auth/gmail.send"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*

0 commit comments

Comments
 (0)