Skip to content

Commit

Permalink
Ticket rejection emails have been implemented. Client email notificat…
Browse files Browse the repository at this point in the history
…ion system finished?

Could definitely use polishing, but the functionality is there. Now for admin emails...
  • Loading branch information
arc12012 committed Apr 20, 2017
1 parent 64ae85a commit 5e8ed1e
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 45 deletions.
10 changes: 8 additions & 2 deletions WebContent/html/webpages/redirect/ticketAdminRedirect.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,10 @@ int locationid = Integer.parseInt(locationidstr);
//approve form was submitted
if(request.getParameter("approve") != null){
//TODO include in time of action so that the status fields can be updated in the ticket
TicketQueries.acceptTicket(ticketid,deviceid,locationid,Integer.parseInt(navsso));
User client = EmployeeQueries.getEmployeeByID(TicketQueries.getUserID(ticketid));
boolean notificationPreferences = (Math.floor(client.getNotificationPreferences()/2)%2==1);
//The second least significant bit of notificationPreferences - the 4's place - is used for ticket approval notifications.
//The second least significant bit of notificationPreferences - the 2's place - is used for ticket approval notifications.
if(notificationPreferences){
NotificationQueue q = new NotificationQueue(client,"ticketConfirmations");
q.start();
Expand All @@ -50,6 +49,13 @@ if(request.getParameter("approve") != null){
//reject form was submitted
if(request.getParameter("reject") != null){
TicketQueries.rejectTicket(ticketid);
User client = EmployeeQueries.getEmployeeByID(TicketQueries.getUserID(ticketid));
boolean notificationPreferences = (Math.floor(client.getNotificationPreferences()/4)%2==1);
//The third least significantbit of notificationPreferences - te 4's place - is used for ticket rejection notifications.
if(notificationPreferences){
NotificationQueue q = new NotificationQueue(client, "ticketRejections");
q.start();
}
}
%>
<script>
Expand Down
11 changes: 7 additions & 4 deletions src/database/TicketQueries.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ public static void rejectTicket(int id) throws SQLException, ClassNotFoundExcept
Class.forName("com.mysql.jdbc.Driver");
Connection connect = DriverManager.getConnection(database, user, password);
Statement stmt = connect.createStatement();
stmt.executeUpdate("UPDATE ticket SET Status = \"Rejected\" WHERE Ticket_ID = " + id);
long milliseconds = new Date().getTime();
String query="UPDATE ticket SET Status = \"Rejected\", Status_Date_Fields = "+milliseconds+" WHERE Ticket_ID = " + id;
System.out.println("Executing query "+query);
stmt.executeUpdate(query);
stmt.close();
connect.close();
}
Expand All @@ -116,8 +119,8 @@ public static long getLatestTicketActivity(User employee, String status) throws
connect.close();
return results.getLong("MAX(Status_Date_Fields)");
}
// Returns all tickets approved since 'millieconds' and associated with 'employee'
public static Ticket[] getRecentApprovedTickets(int userID, long milliseconds) throws SQLException, ClassNotFoundException {
// Returns all tickets changed to 'status' since 'millieconds' and associated with 'employee'
public static Ticket[] getRecentlyChangedTickets(int userID, String status, long milliseconds) throws SQLException, ClassNotFoundException {
System.getenv("VCAP_SERVICES");
Class.forName("com.mysql.jdbc.Driver");
Connection connect = DriverManager.getConnection(database, user, password);
Expand All @@ -126,7 +129,7 @@ public static Ticket[] getRecentApprovedTickets(int userID, long milliseconds) t
+"FROM ticket INNER JOIN employee ON ticket.Requestor = employee.Employee_ID "
+"INNER JOIN devices ON ticket.Device_ID = devices.Device_ID "
+"INNER JOIN location ON ticket.Location = location.Location_ID "
+"WHERE ticket.Status = 'Approved' AND Requestor = " + userID
+"WHERE ticket.Status = '"+status+"' AND Requestor = " + userID
+" AND Status_Date_Fields >= " + milliseconds;
System.out.println("Executing query '"+query+"'");
ResultSet results = stmt.executeQuery(query);
Expand Down
95 changes: 72 additions & 23 deletions src/utilities/Mail.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public class Mail {
private String sender = "Senior.design.synchrony.test@gmail.com";
private String password = "synchrony123";
private User client;
private String profileLink = "https://seniordesign.cfapps.io/html/webpages/profileSettings.jsp";
private String ticketLink = "";

public Mail(User client){
this.client=client;
}
Expand All @@ -29,16 +32,16 @@ public void sendTicketConfirmation(int[] ticketIDs) throws IOException, Interrup
String subject = "Your test device order";
// I really want to read this from a seperate file, but even when it's in the same directory eclipse insists on moving everything around :(
String msg = "<!DOCTYPE html>"
+ "<html>"
+ "<body>"
+ "<h4>We've received your order! We'll let you know when your device{s} ship{!s}.</h4>"
+ "<p>The following ticket{s} {was/were} generated:</p>"
+ "<div name = 'tickets' style='text-indent: 20px'>"
+ "{TICKETS GO HERE}"
+ "</div>"
+ "</body>"
+ "<footer style='text-align: center;'><font size='1'>To change notification settings, please visit your <a href='../WebContent/html/webpages/profileSettings.jsp'>profile settings page</a></font></footer>"
+ "</html>";
+ "<html>"
+ "<body>"
+ "<h4>We've received your order! We'll let you know when your device{s} ship{!s}.</h4>"
+ "<p>The following ticket{s} {was/were} generated:</p>"
+ "<div name = 'tickets' style='text-indent: 20px'>"
+ "{TICKETS GO HERE}"
+ "</div>"
+ "</body>"
+ "<footer style='text-align: center;'><font size='1'>To change notification settings, please visit your <a href='"+profileLink+"'>profile settings page</a></font></footer>"
+ "</html>";

// The messege needs to be tailored to make sense
msg=msg.replace("{s}",(ticketIDs.length==1 ? "" : "s")); //make occurances of 'device' and 'ticket' plural or singular
Expand All @@ -47,7 +50,7 @@ public void sendTicketConfirmation(int[] ticketIDs) throws IOException, Interrup
String tickethtml = "";
for(int tickID : ticketIDs)
{
tickethtml+="<p>Ticket #<a href='../WebContent/html/webpages/'>"+tickID+"</a></p>";
tickethtml+="<p>Ticket #<a href='"+ticketLink+"'>"+tickID+"</a></p>";
}
msg=msg.replace("{TICKETS GO HERE}",tickethtml);
Properties properties = System.getProperties();
Expand Down Expand Up @@ -78,17 +81,17 @@ protected PasswordAuthentication getPasswordAuthentication(){
public void sendTicketApproval(Ticket[] tickets) throws IOException, InterruptedException {
String subject = "{DEVICE(S)} {is/are(3)} on the way!";
String messege = "<!DOCTYPE html>"
+ "<html>"
+ "<body>"
+ "<h4>Your ticket{s} {have/has} been approved!</h4>"
+ "<p>I hope you're exicted, because the device{s} you ordered {is/are} about to ship. Happy testing!</p>"
+ "{list_header}"
+ "<div name = 'tickets' style='text-indent: 20px'>"
+ "{TICKETS GO HERE}"
+ "</div>"
+ "</body>"
+ "<footer style='text-align: center;'><font size='1'>To change notification settings, please visit your <a href='../WebContent/html/webpages/profileSettings.jsp'>profile settings page</a></font></footer>"
+ "</html>";
+ "<html>"
+ "<body>"
+ "<h4>Your ticket{s} {have/has} been approved!</h4>"
+ "<p>I hope you're exicted, because the device{s} you ordered {is/are} about to ship. Happy testing!</p>"
+ "{list_header}"
+ "<div name = 'tickets' style='text-indent: 20px'>"
+ "{TICKETS GO HERE}"
+ "</div>"
+ "</body>"
+ "<footer style='text-align: center;'><font size='1'>To change notification settings, please visit your <a href='"+profileLink+"'>profile settings page</a></font></footer>"
+ "</html>";

subject=subject.replace("{DEVICE(S)}", tickets[0].getDeviceName() + (tickets.length>1 ? " and "+(tickets.length-1)+" more" : ""));
subject=subject.replace("{is/are(3)}",tickets.length>2 ? "are" : "is");
Expand All @@ -100,7 +103,7 @@ public void sendTicketApproval(Ticket[] tickets) throws IOException, Interrupted
if(tickets.length>1)
{
for (Ticket tic : tickets) {
ticketList+="<p>Ticket #<a href='../WebContent/html/webpages/'>"+tic.getId()+"</a> - "+tic.getDeviceName()+"</p>";
ticketList+="<p>Ticket #<a href='"+ticketLink+"'>"+tic.getId()+"</a> - "+tic.getDeviceName()+"</p>";
}
}
messege=messege.replace("{TICKETS GO HERE}",ticketList);
Expand All @@ -127,6 +130,52 @@ protected PasswordAuthentication getPasswordAuthentication(){
mex.printStackTrace();
}
}

public void sendTicketRejection(Ticket[] tickets) throws IOException, InterruptedException{
String subject = "Bad news, we've had to reject your order.";
String messege = "<!DOCTYPE html>"
+ "<html>"
+ "<body>"
+ "<h4>Unfortunately, we couldn't deliver on your recent order. The following ticket{s} {have/has} been rejected:</h4>"
+ "<div name = 'tickets' style='text-indent: 20px'>"
+ "{TICKETS GO HERE}"
+ "</div>"
+ "<p>There may have been an availablilty conflict. You can try submitting a new order for{ a} similar device{s},"
+ " or for more information you can contact an administrator.</p>"
+ "</body>"
+ "<footer style='text-align: center;'><font size='1'>To change notification settings, please visit your <a href='"+profileLink+"'>profile settings page</a></font></footer>"
+ "</html>";
messege=messege.replace("{s}",tickets.length>1 ? "s" : "");
messege=messege.replace("{have/has}",tickets.length>1 ? "have" : "has");
messege=messege.replace("{ a}",tickets.length>1 ? "" : " a");
String ticketText = "";
for (Ticket t : tickets) {
ticketText+="<p>Ticket #<a href='"+ticketLink+"'>"+t.getId()+"</a> - "+t.getDeviceName()+"</p>";
}
messege=messege.replace("{TICKETS GO HERE}",ticketText);
Properties properties = System.getProperties();
properties = setProp(sender, client.getEmail());
Session session = Session.getInstance(properties, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication(){
return new PasswordAuthentication(sender, password);
}
});

try {
Address address = new InternetAddress(client.getEmail());
MimeMessage message = new MimeMessage(session);
message.setFrom(address);
message.addRecipient(Message.RecipientType.TO, address);
message.setSubject(subject);
message.setText(messege,"utf-8","html");
message.saveChanges();
Transport.send(message);
System.out.println("Sent message successfully....");

} catch (Exception mex) {
mex.printStackTrace();
}
}
private Properties setProp(String email, String targetEmail) {
Properties props = null;
try {
Expand Down
57 changes: 41 additions & 16 deletions src/utilities/NotificationQueue.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public class NotificationQueue extends Thread{
private String instructions="";
// this determines what information the notification queue will collect when it is finished waiting.
// >'ticketConfirmations' will cause it to query approved tickets since initialization associated with 'employee'
private int threadWaitTime = 3*60000; //3 minutes seeeeems reasonable
// This is how long a thread will stay idle before consolidating notification activity.
// The number only applies to client emails; administators may configure their own wait time.
private User employee;
public NotificationQueue(User employee, String initialize){
instructions=initialize;
Expand All @@ -41,7 +44,7 @@ public void run(){
}
System.out.println(match ? " Match!" : " No match");
if(match){
System.out.println("Redundant NotificationQueue thread will terminate");
System.out.println("Redundant NotificationQueue thread ("+threadName+") will terminate");
return; //should kill thread
}
else{
Expand All @@ -53,18 +56,32 @@ public void run(){
// Finally do the thing we came for
switch(instructions){
case "ticketConfirmations":
try {
startTicketApproveQueue(employee);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
startTicketApproveQueue(employee);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case "ticketRejections":
try{
startTicketRejectQueue(employee);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
default:
System.out.println("NotificationQueue: Did not recognize instruction string");
Expand All @@ -80,10 +97,18 @@ private void startTicketApproveQueue(User employee) throws InterruptedException,
// Database connections are becoming a serious problem, so I'm just going to estimate that 5 seconds is more than enough
// to account for the time it took to get from the ticket generation to here.
long milliseconds = new Date().getTime()-5000;
Thread.sleep(30000);
System.out.println("NotificationQueue: sending summary email from thread "+Thread.currentThread().getName());
Ticket[] tickets = TicketQueries.getRecentApprovedTickets(employee.getID(),milliseconds);
Thread.sleep(threadWaitTime);
System.out.println("NotificationQueue: sending summary approval email from thread "+Thread.currentThread().getName());
Ticket[] tickets = TicketQueries.getRecentlyChangedTickets(employee.getID(), "Shipped", milliseconds);
Mail mail = new Mail(employee);
mail.sendTicketApproval(tickets);
}
private void startTicketRejectQueue(User employee) throws InterruptedException, ClassNotFoundException, SQLException, IOException{
long milliseconds = new Date().getTime()-5000;
Thread.sleep(threadWaitTime);
System.out.println("NotificationQueue: sending summary rejection email from thread "+Thread.currentThread().getName());
Ticket[] tickets = TicketQueries.getRecentlyChangedTickets(employee.getID(), "Rejected", milliseconds);
Mail mail = new Mail(employee);
mail.sendTicketRejection(tickets);
}
}
13 changes: 13 additions & 0 deletions src/utilities/ticketConfirmation.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- I would love to organize these templates better, but I have no idea where eclipse is putting everything when it builds the project -->
<!DOCTYPE html>
<html>
<body>
<h4>We've received your order! We'll let you know when your device{s} will ship.</h2>
<p>The following ticket{s} {was/were} generated:</p>
<div name = 'tickets' style='text-indent: 20px'>
<p>Ticket #<a href='../WebContent/html/webpages/'>12321312</a></p>
<p>Ticket #<a href='../WebContent/html/webpages/'>12321312</a></p>
</div>
</body>
<footer style='text-align: center;'><font size='2'>To change notification settings, please visit your <a href='../WebContent/html/webpages/profileSettings.jsp'>profile settings page</a></font></footer>
</html>

0 comments on commit 5e8ed1e

Please sign in to comment.