Skip to content

Commit

Permalink
Urgent order option does what it's supposed to now. Implemented admin…
Browse files Browse the repository at this point in the history
… email, only for urgent orders

Still need to do queued admin notifications and improve email quality
  • Loading branch information
arc12012 committed Apr 25, 2017
1 parent 5493da4 commit 1efe749
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 16 deletions.
39 changes: 34 additions & 5 deletions WebContent/html/webpages/redirect/orderFormHandler.jsp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<%@ page import = "database.*,entities.Location" %>
<%@ page import = "entities.User" %>
<%@ page import = "database.*,entities.*,utilities.*" %>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>

Expand Down Expand Up @@ -42,13 +41,13 @@ String phone = request.getParameter("phone");
String email = request.getParameter("email");
String[] options = request.getParameterValues("checkboxes");
int perm = 0;
int urgent = 0;
boolean urgent = false;
if(options != null){
for(int j = 0; j < options.length; j++){
if(options[j].equals("perm"))
perm = 1;
if(options[j].equals("urgent"))
urgent = 1;
urgent = true;
}
}
// read location ID, but only if we haven't already generated it when adding new location to db
Expand All @@ -73,19 +72,49 @@ for(int i=0; i<idStringArray.length; i++)
}
// Now just call generateTicket once for each device (and store ticket IDs)
int[] ticketIDs = new int[devIDs.length];
Ticket[] tickets = new Ticket[ticketIDs.length];
// Yeah, I know, this probably looks kinda silly if you're seeing it for the first time.
for(int i=0; i<devIDs.length; i++)
{
ticketIDs[i] = TicketQueries.generateTicket(Integer.parseInt(navsso), location, devIDs[i], request.getParameter("timeNeeded"), perm);
// We weren't using employee name, location name or device name on this page originally-only the info needed for the above generateTicket query.
tickets[i] = new Ticket(ticketIDs[i],
Integer.parseInt(navsso),
0,
location,
devIDs[i],
"Ready to Ship",
0,
request.getParameter("timeNeeded"),
request.getParameter("name"),
request.getParameter("locname"),
"",//TODO get device name
perm);
// But now that we want to include the extra info in emails, I'm also fetching it and making a Ticket array
// to pass to the relevant notification queues below.
}
// Now that tickets have been generated we will want to notify users.
// ------------------------------------------------- Email notifications -------------------------------------------------
// First clients
boolean emailNotificationEnabled = (self.getNotificationPreferences()%2==1);
// The rightmost, least significant bit of the notificationPreferences integer is used for ticket generation emails.
if(emailNotificationEnabled)
{
new Mail(self).sendTicketConfirmation(ticketIDs); //'self' is the current user, and is defined in navbar.jsp
}
// Now admins.
User[] admins = EmployeeQueries.getAllAdmins();
// If an order is marked urgent this should be easy; just immediately send emails to all admins.
// However because setting up an email takes some time and there are many admins, we will still
// route these emails through a notification queue. Therefore the only difference here between an
// urgent order and a regular order will be the instructions we pass to the queue.
String instructions = (urgent) ? "adminUrgentRequest" : "adminDeviceRequest";
for (int i = admins.length - 1; i >= 0; i--) {
AdminNotificationQueue Q = new AdminNotificationQueue(admins[i],instructions,tickets);
Q.start();
}
%>
window.location.replace("../shoppingCart.jsp");
</script>
Expand Down
30 changes: 19 additions & 11 deletions WebContent/html/webpages/shoppingCart.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@ pageEncoding="ISO-8859-1"%>
</div>
<div class="modal-body">
<form name="orderForm" onsubmit="return submitOrderForm()" action="redirect/orderFormHandler.jsp" method="post">
<input type="text" name="userID" style = "display: none;"/>
<input type="text" name="userID" style = "display: none;"/>
<input type="text" name="orderAll" style = "display: none;"/>
<input type="text" name="deviceIDs" style="display: none;">
<input type="text" name="deviceIDs" style="display: none;">
<input type="text" name="deviceNames" style="display: none;">
<div class="form-group row">
<label for="name">Your name</label><br/>
<input type="text" class="form-control" name="name" placeholder="Name" required>
Expand All @@ -96,10 +97,7 @@ pageEncoding="ISO-8859-1"%>
<select class="form-control" name="location_dropdown" id="dropdown" onchange="forceUpdateLocationMetadata()" style="width:65%; max-height: 80%; text-align: center; vertical-align: center; align-items: center; display: block; position: relative; margin: 0% auto; text-align-last:center; padding:">
</select>
</div>
<div class="form-group-row" style = "display:'none'" name="locnamediv">
<label for="">Location Name</label>
<input type="text" onkeyup="forceDropdownCustomLocation" class="form-control" name="locname" style="width: 50%" placeholder="Give your new location a name!" required/>
</div>

<div class="form-group row" style="display: block; align-items: center;margin: 3% auto;">
<div class="col-md-6" style="width:50%">
<div class="form-group row">
Expand Down Expand Up @@ -173,6 +171,11 @@ pageEncoding="ISO-8859-1"%>
<label for="zip">Zip</label>
<input type="text" onkeyup="forceDropdownCustomLocation" class="form-control" name="zip" placeholder="Zip Code" pattern="[0-9]{5}" title="Input must be 5 digits" style="margin: 0 auto; width:60%" required/>
</div>

</div>
<div class="form-group-row" style = "display:'none'" name="locnamediv">
<label for="">Location Name</label>
<input type="text" onkeyup="forceDropdownCustomLocation" class="form-control" name="locname" style="width: 50%" placeholder="Give your new location a name!" required/>
</div>
</div>
<div class="form-group row">
Expand Down Expand Up @@ -250,6 +253,7 @@ var employee = {
var checked = new Array();
var locations = getLocations();
var cart = getCartItems();
show(); //on load, we want to show everything
Expand All @@ -271,7 +275,7 @@ function setCart(cartArray) {
This function displays a list of devices that a user has currently in their shopping cart.
**/
function show(){
var cart = getCartItems(); //get all the cart items you want to show
cart = getCartItems(); //get all the cart items you want to show
var html = ''; //html string initially empty
var part1 = "nhpup.popup('";
var part2 = "');"
Expand Down Expand Up @@ -347,12 +351,12 @@ function orderAll_showPopup() {
// If true, submitting the form will order everything in the cart. If false it only orders selected devices.
function showPopup(orderAllBool){
if(checked.length==0 && !orderAllBool){
$('#Submit').attr('disabled',true);
$('#Submit').attr('title',"There aren't any devices selected to order!");
$('#Submit').attr('disabled',true);
$('#Submit').attr('title',"There aren't any devices selected to order!");
}
else{
$('#Submit').attr('disabled',false);
$('#Submit').removeAttr('title');
$('#Submit').attr('disabled',false);
$('#Submit').removeAttr('title');
}
orderForm.style.display = "block";
autoFillFields(orderAllBool);
Expand Down Expand Up @@ -474,6 +478,7 @@ function forceUpdateLocationMetadata() {
var selectedDeviceString=JSON.stringify(checked);
document.orderForm.deviceIDs.value=selectedDeviceString;
// Finally remove selected items from the cart
deleteSelected(false);
return true;
Expand Down Expand Up @@ -535,6 +540,9 @@ function deleteAll(){
function getUserID() {
return <%=sso%>;
}
function function_name(argument) {
// body...
}
</script>
</body>
Expand Down
29 changes: 29 additions & 0 deletions src/database/EmployeeQueries.java
Original file line number Diff line number Diff line change
Expand Up @@ -246,4 +246,33 @@ public static void updateNotificationPreferences(int client, int preferences) th
statement.close();
connect.close();
}

public static User[] getAllAdmins() throws SQLException, ClassNotFoundException {
System.getenv("VCAP_SERVICES");
Class.forName("com.mysql.jdbc.Driver");
Connection connect = DriverManager.getConnection(database, user, password);
Statement statement = connect.createStatement();
String query = "select * from employee join admin on employee.Employee_ID=Admin.Admin_ID";
query+=" WHERE Employee_ID = 0;"; //TODO Remove this line when ready for production! It is only here to prevent every single admin from getting all my test emails.
System.out.println("Executing query: "+query);
ResultSet results = statement.executeQuery(query);
results.last();
User[] admins = new User[results.getRow()];
results.beforeFirst();
while(results.next())
{
admins[results.getRow()-1]=new User(
results.getInt("Employee_ID"),
results.getInt("Location_ID"),
results.getString("Name"),
results.getString("Phone_Number"),
results.getString("Email"),
results.getInt("Img_Index"),
results.getInt("Notification_Preference")
);
}
statement.close();
connect.close();
return admins;
}
}
3 changes: 3 additions & 0 deletions src/entities/Ticket.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,7 @@ public long getStatusDatefields(){
public String getDeviceName(){
return devicename;
}
public String getRequestorName() {
return username;
}
}
62 changes: 62 additions & 0 deletions src/utilities/AdminNotificationQueue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package utilities;

import java.util.Set;

import entities.Ticket;
import entities.User;

public class AdminNotificationQueue extends Thread {
/*
This class functions similarly to the regular notification queue.
There are enough differences in admin and client notifications,
however, that it seemed like it deserved a seperate class.
*/
private String instructions="";
private int threadWaitTime;
private User admin;
private Ticket[] tickets;

// The tickets parameter will most likely be relevant only when using this class to
// dispatch emails immediately with threads
public AdminNotificationQueue(User admin, String initialization, Ticket[] tickets)
{
instructions=initialization;
this.admin=admin;
this.tickets=tickets;
}

public void run() {
try {
String threadName = instructions+admin.getID();
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]);
boolean match = false;
System.out.println("Admin Notification Queue: Chacking active threads for match with "+threadName+"...");
for (int i=0; i<threadArray.length; i++) {
if(threadArray[i].getName().equals(threadName)) {
match=true;
}
}
System.out.println(match ? " Match!" : " No match");
if(match){
System.out.println("Redundant Admin Notification Queue thread ("+threadName+") will terminate");
return; //should kill thread
}
else {
Thread.currentThread().setName(threadName);
// Finally do the thing we came for
switch(instructions){
case "adminUrgentRequest":
new Mail(admin).sendUrgentRequest(tickets);
break;
default:
System.out.println("Admin notification queue could not recognize instructions");
}
}
} catch(Exception e) {
e.printStackTrace();
} finally {

}
}
}
57 changes: 57 additions & 0 deletions src/utilities/Mail.java
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,63 @@ protected PasswordAuthentication getPasswordAuthentication(){
}
}

public void sendUrgentRequest(Ticket[] tickets) {

String subject = "{CLIENT} has urgent need of {a/some} device{s}";
// 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>{CLIENT} is very excited about getting a device, and doesn't want to be kept waiting.</h4>"
+ "<p>You'd better drop everything you're doing to take care of them immediately. Who knows what might happen if they don't get their device{s} right freakin' now?</p>"
+ "<p>Here {is/are} the ticket{s} in question:</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
subject=subject.replace("{CLIENT}",""+tickets[0].getRequestorName());
subject=subject.replace("{a/some}",tickets.length==1 ? "a" : "some");
subject=subject.replace("{s}",(tickets.length==1 ? "" : "s"));
msg=msg.replace("{CLIENT}",""+tickets[0].getRequestorName()); //
msg=msg.replace("{s}",(tickets.length==1 ? "" : "s")); //make occurances of 'device' and 'ticket' plural or singular
msg=msg.replace("{was/were}",tickets.length==1 ? "was" : "were"); //use appropriate verbs
msg=msg.replace("{is/are}",tickets.length==1 ? "is" : "are");
msg=msg.replace("{!s}",tickets.length==1 ? "s" : "s"); //verbs again

String tickethtml = "";
for(Ticket ticket : tickets)
{
tickethtml+="<p>Ticket #<a href='"+ticketLink+"'>"+ticket.getId()+"</a></p>";
}
msg=msg.replace("{TICKETS GO HERE}",tickethtml);
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(msg,"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

0 comments on commit 1efe749

Please sign in to comment.