Skip to content
Snippets Groups Projects
Commit e37145d9 authored by ahmada4's avatar ahmada4
Browse files

Merge branch 'uc41' into 'master'

UC 41: Implemented Sending Reminders

See merge request !17
parents 9c652e5e 50f9aa5e
No related branches found
No related tags found
1 merge request!17UC 41: Implemented Sending Reminders
...@@ -31,6 +31,18 @@ ...@@ -31,6 +31,18 @@
</ul> </ul>
</div> </div>
</div> </div>
<div class="panel panel-default">
<div class="panel-heading" anim-type="collapse" anim-target="#messaging-menu">
<h2 class="panel-title">Messaging</h2>
</div>
<div class="panel-body" id="messaging-menu">
<ul class="nav nav-sidebar">
<li><a href="/iTrust/auth/admin/viewReminderOutbox.jsp">Reminder Message Outbox</a></li>
</ul>
</div>
</div>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading" anim-type="collapse" anim-target="#other-menu"> <div class="panel-heading" anim-type="collapse" anim-target="#other-menu">
<h2 class="panel-title">Other</h2> <h2 class="panel-title">Other</h2>
...@@ -44,6 +56,7 @@ ...@@ -44,6 +56,7 @@
<li><a href="/iTrust/auth/admin/sessionTimeout.jsp">Change Global Session Timeout </a></li> <li><a href="/iTrust/auth/admin/sessionTimeout.jsp">Change Global Session Timeout </a></li>
<li><a href="/iTrust/auth/surveyResults.jsp">Satisfaction Survey Results</a></li> <li><a href="/iTrust/auth/surveyResults.jsp">Satisfaction Survey Results</a></li>
<li><a href="/iTrust/auth/admin/activatePatient.jsp">Activate Patient</a></li> <li><a href="/iTrust/auth/admin/activatePatient.jsp">Activate Patient</a></li>
<li><a href="/iTrust/auth/admin/sendAppointmentReminders.jsp">Send Appointment Reminders</a></li>
</ul> </ul>
</div> </div>
</div> </div>
\ No newline at end of file
<%@page errorPage="/auth/exceptionHandler.jsp"%>
<%@page import="edu.ncsu.csc.itrust.action.ViewMyMessagesAction"%>
<%@page import="edu.ncsu.csc.itrust.beans.MessageBean"%>
<%@page import="java.util.List"%>
<%@include file="/global.jsp" %>
<%
pageTitle = "iTrust - View Message";
%>
<%@include file="/header.jsp" %>
<%
ViewMyMessagesAction action = new ViewMyMessagesAction(prodDAO, loggedInMID.longValue());
MessageBean original = null;
loggingAction.logEvent(TransactionType.OUTBOX_VIEW, loggedInMID.longValue(), 0, "");
if (request.getParameter("msg") != null) {
String msgParameter = request.getParameter("msg");
int msgIndex = 0;
try {
msgIndex = Integer.parseInt(msgParameter);
} catch (NumberFormatException nfe) {
response.sendRedirect("viewReminderOutbox.jsp");
}
List<MessageBean> messages = null;
if (session.getAttribute("messages") != null) {
messages = (List<MessageBean>) session.getAttribute("messages");
if(msgIndex > messages.size() || msgIndex < 0) {
msgIndex = 0;
response.sendRedirect("oops.jsp");
}
} else {
response.sendRedirect("viewReminderOutbox.jsp");
}
original = (MessageBean)messages.get(msgIndex);
session.setAttribute("message", original);
}
else {
response.sendRedirect("viewReminderOutbox.jsp");
}
%>
<div>
<table width="99%">
<tr>
<td><b>To:</b> <%= StringEscapeUtils.escapeHtml("" + ( action.getName(original.getTo()) )) %></td>
</tr>
<tr>
<td><b>Subject:</b> <%= StringEscapeUtils.escapeHtml("" + ( original.getSubject() )) %></td>
</tr>
<tr>
<td><b>Date &amp; Time:</b> <%= StringEscapeUtils.escapeHtml("" + ( original.getSentDate() )) %></td>
</tr>
</table>
</div>
<table>
<tr>
<td colspan="2"><b>Message:</b></td>
</tr>
<tr>
<td colspan="2"><%= StringEscapeUtils.escapeHtml("" + ( original.getBody() )).replace("\n","<br/>") %></td>
</tr>
<tr>
<td colspan="2"><a href="viewReminderOutbox.jsp">Back</a></td>
</tr>
</table>
<%@include file="/footer.jsp" %>
\ No newline at end of file
<%@taglib prefix="itrust" uri="/WEB-INF/tags.tld"%>
<%@page errorPage="/auth/exceptionHandler.jsp"%>
<%@page import="edu.ncsu.csc.itrust.action.SendRemindersAction" %>
<%@page import="edu.ncsu.csc.itrust.exception.ITrustException" %>
<%@page import="java.lang.NumberFormatException" %>
<%@include file="/global.jsp" %>
<%
pageTitle = "iTrust - Send Reminder Message";
%>
<%@include file="/header.jsp" %>
<%
String input = request.getParameter("withinDays");
if (input != null && !input.equals("")) {
try {
int days = Integer.valueOf(input);
if (days <= 0) {
%>
<span class="iTrustError"><%=StringEscapeUtils.escapeHtml("Provide a positive number") %></span>
<%
}
else {
SendRemindersAction action = new SendRemindersAction(prodDAO, loggedInMID.longValue());
action.sendReminderForAppointments(days);
%>
<span class="iTrustMessage"><%=StringEscapeUtils.escapeHtml("Reminders were successfully sent") %></span>
<%
}
} catch (NumberFormatException | ITrustException e) {
%>
<span class="iTrustError"><%=StringEscapeUtils.escapeHtml("Reminders failed to send. Please provide a positive number") %></span>
<%
}
}
%>
<div class="page-header"><h1>Send Reminder Message</h1></div>
<form method="post">
<h4> Send reminders to all patients with an appointment within the next n days. Provide n: </h4>
<input type="text" name="withinDays"></td>
<input type="submit" style="font-size: 12pt; font-weight: bold;" value="Send Appointment Reminders">
</form>
<%@include file="/footer.jsp" %>
\ No newline at end of file
<%@page errorPage="/auth/exceptionHandler.jsp"%>
<%@page import="java.util.List"%>
<%@page import="edu.ncsu.csc.itrust.action.ViewMyMessagesAction"%>
<%@page import="edu.ncsu.csc.itrust.beans.MessageBean"%>
<%@page import="edu.ncsu.csc.itrust.dao.DAOFactory"%>
<%@include file="/global.jsp" %>
<%
pageTitle = "iTrust - View My Sent Messages";
%>
<%@include file="/header.jsp" %>
<div align=center>
<h2>Sent Reminders</h2>
<%
loggingAction.logEvent(TransactionType.OUTBOX_VIEW, loggedInMID.longValue(), loggedInMID.longValue(), "");
ViewMyMessagesAction action = new ViewMyMessagesAction(prodDAO, 9000000009L);
List<MessageBean> messages = null;
if(request.getParameter("sortby") != null) {
if(request.getParameter("sortby").equals("name")) {
if(request.getParameter("sorthow").equals("asce")) {
messages = action.getAllMySentMessagesNameAscending();
} else {
messages = action.getAllMySentMessagesNameDescending();
}
} else if(request.getParameter("sortby").equals("time")) {
if(request.getParameter("sorthow").equals("asce")) {
messages = action.getAllMySentMessagesTimeAscending();
} else {
messages = action.getAllMySentMessages();
}
}
}
else {
messages = action.getAllMySentMessages();
}
session.setAttribute("messages", messages);
if (messages.size() > 0) { %>
<br />
<table class="fancyTable">
<tr>
<th>To</th>
<th>Subject</th>
<th>Sent</th>
<th></th>
</tr>
<% int index = 0; %>
<% for(MessageBean message : messages) { %>
<tr <%=(index%2 == 1)?"class=\"alt\"":"" %>>
<td><%= StringEscapeUtils.escapeHtml("" + ( action.getName(message.getTo()) )) %></td>
<td><%= StringEscapeUtils.escapeHtml("" + ( message.getSubject() )) %></td>
<td><%= StringEscapeUtils.escapeHtml("" + ( message.getSentDate() )) %></td>
<td><a href="reminderMessage.jsp?msg=<%= StringEscapeUtils.escapeHtml("" + ( index )) %>">Read</a></td>
</tr>
<% index ++; %>
<% } %>
</table>
<% } else { %>
<div>
<i>No reminders sent</i>
</div>
<% } %>
<br />
</div>
<%@include file="/footer.jsp" %>
\ No newline at end of file
package edu.ncsu.csc.itrust.action;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import edu.ncsu.csc.itrust.beans.ApptBean;
import edu.ncsu.csc.itrust.beans.MessageBean;
import edu.ncsu.csc.itrust.beans.PersonnelBean;
import edu.ncsu.csc.itrust.dao.DAOFactory;
import edu.ncsu.csc.itrust.dao.mysql.ApptDAO;
import edu.ncsu.csc.itrust.dao.mysql.PersonnelDAO;
import edu.ncsu.csc.itrust.exception.DBException;
import edu.ncsu.csc.itrust.exception.FormValidationException;
import edu.ncsu.csc.itrust.exception.ITrustException;
import java.util.*;
public class SendRemindersAction {
public final long systemReminderMID;
private long loggedInMID;
private ApptDAO apptDAO;
private SendMessageAction smAction;
public SendRemindersAction(DAOFactory factory, long loggedInMID) throws DBException {
PersonnelDAO personnelDAO = factory.getPersonnelDAO();
List<PersonnelBean> personnels = personnelDAO.searchForPersonnelWithName("System", "Reminder");
this.systemReminderMID = personnels.get(0).getMID();
this.loggedInMID = loggedInMID;
this.apptDAO = factory.getApptDAO();
this.smAction = new SendMessageAction(factory, systemReminderMID);
}
public void sendReminder(ApptBean aBean) throws ITrustException, SQLException, FormValidationException {
LocalDateTime now = LocalDateTime.now();
LocalDateTime date = aBean.getDate().toLocalDateTime();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm, MMM d");
MessageBean message = new MessageBean();
message.setTo(aBean.getPatient());
message.setFrom(systemReminderMID);
message.setSubject(String.format("Reminder: upcoming appointment in %d day(s)", now.truncatedTo(ChronoUnit.DAYS).until(date.truncatedTo(ChronoUnit.DAYS), ChronoUnit.DAYS)));
message.setBody(String.format("You have an appointment on %s with Dr. %s", date.format(formatter), smAction.getPersonnelName(aBean.getHcp())));
message.setSentDate(Timestamp.valueOf(now));
smAction.sendMessage(message);
}
public int sendReminderForAppointments(int numDays) throws ITrustException {
List<ApptBean> appointments = null;
try {
appointments = apptDAO.getUpcomingAppts(numDays);
for (ApptBean appt : appointments) {
sendReminder(appt);
}
return appointments.size();
} catch (DBException e) {
throw new ITrustException("DB Error in sending reminders.");
} catch (SQLException e) {
throw new ITrustException("SQL Error in sending reminders.");
} catch (FormValidationException e) {
throw new ITrustException("Form Validation Error in sending reminders.");
}
}
}
\ No newline at end of file
...@@ -328,5 +328,35 @@ public class ApptDAO { ...@@ -328,5 +328,35 @@ public class ApptDAO {
} }
}
/**
* Get all upcoming appointments within n days
* @param numDays Number of days after current date within which to find all appointments
* @return ApptBean List of upcoming appointments
*/
public List<ApptBean> getUpcomingAppts(int numDays) throws SQLException, DBException {
Connection conn = null;
PreparedStatement pstring = null;
try {
conn = factory.getConnection();
pstring = conn.prepareStatement(
"SELECT * FROM appointment WHERE " + /*" sched_date.after(?)=TRUE AND sched_date.before(?)=TRUE");*/
"DATE(sched_date)<=DATE_ADD(CURRENT_DATE, INTERVAL ? DAY) AND " + //sched_date day is before or at (numDays) days from now
"sched_date>=CURRENT_DATE"); // sched_date is after today
pstring.setInt(1, numDays);
final ResultSet results = pstring.executeQuery();
final List<ApptBean> abList = this.abloader.loadList(results);
results.close();
pstring.close();
return abList;
} catch (SQLException e) {
throw new DBException(e);
} finally {
DBUtil.closeConnection(conn, pstring);
}
} }
} }
package edu.ncsu.csc.itrust.selenium;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
public class SendRemindersTest extends iTrustSeleniumTest{
protected WebDriver driver;
@Override
protected void setUp() throws Exception {
super.setUp();
gen.clearAllTables();
gen.standardData();
}
// Test sending reminders
public void testSendReminder() throws Exception {
// Login as admin
driver = login("9000000001", "pw");
assertEquals("iTrust - Admin Home", driver.getTitle());
driver.findElement(By.linkText("Send Appointment Reminders")).click();
// Send reminders
driver.findElement(By.name("withinDays")).sendKeys("10");
driver.findElement(By.name("withinDays")).submit();
assertEquals("Reminders were successfully sent",
driver.findElement(By.className("iTrustMessage")).getText());
// Create timestamp
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
Date date = new Date();
String stamp = dateFormat.format(date);
// Check admin reminders outbox
driver.findElement(By.linkText("Reminder Message Outbox")).click();
assertNotNull(driver.findElement(By.className("fancyTable")));
assertTrue(driver.getPageSource().contains(stamp));
// Check a reminder message
driver.findElement(By.linkText("Read")).click();
assertTrue(driver.getPageSource().contains(stamp));
// Logout admin and login as patient
List<WebElement> links = driver.findElements(By.tagName("a"));
int count = 0;
for(int i = 0; i < links.size(); i++) {
if(links.get(i).getAttribute("href").contains("logout"))
{
count = i;
break;
}
}
links.get(count).click();
driver = login("5", "pw");
// Check patient inbox
driver.findElement(By.linkText("Message Inbox")).click();
int index = 1;
WebElement baseTable = driver.findElement(By.cssSelector(".display.fTable"));
List<WebElement> tableRows = baseTable.findElements(By.tagName("tr"));
assertTrue(tableRows.get(index).getText().contains("System Reminder"));
assertTrue(tableRows.get(index).getText().contains("Reminder: upcoming appointment"));
index++;
assertTrue(tableRows.get(index).getText().contains("Reminder: upcoming appointment"));
assertTrue(tableRows.get(index).getText().contains(stamp));
}
// Test invalid number of days input for sending reminders
public void testInvalidSendReminder() throws Exception {
// Login as admin
driver = login("9000000001", "pw");
assertEquals("iTrust - Admin Home", driver.getTitle());
driver.findElement(By.linkText("Send Appointment Reminders")).click();
// Send reminder with negative days
driver.findElement(By.name("withinDays")).sendKeys("-4");
driver.findElement(By.name("withinDays")).submit();
assertEquals("Provide a positive number",
driver.findElement(By.className("iTrustError")).getText());
// Send reminder with non-numberic days
driver.findElement(By.name("withinDays")).sendKeys("Hello");
driver.findElement(By.name("withinDays")).submit();
assertEquals("Reminders failed to send. Please provide a positive number",
driver.findElement(By.className("iTrustError")).getText());
}
}
\ No newline at end of file
package edu.ncsu.csc.itrust.unit.action;
import edu.ncsu.csc.itrust.action.SendRemindersAction;
import edu.ncsu.csc.itrust.beans.ApptBean;
import edu.ncsu.csc.itrust.beans.MessageBean;
import edu.ncsu.csc.itrust.dao.DAOFactory;
import edu.ncsu.csc.itrust.dao.mysql.MessageDAO;
import edu.ncsu.csc.itrust.exception.FormValidationException;
import edu.ncsu.csc.itrust.exception.ITrustException;
import edu.ncsu.csc.itrust.unit.datagenerators.TestDataGenerator;
import edu.ncsu.csc.itrust.unit.testutils.TestDAOFactory;
import junit.framework.TestCase;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.List;
public class SendRemindersActionTest extends TestCase {
private DAOFactory factory;
private MessageDAO messageDAO;
private SendRemindersAction srAction;
private TestDataGenerator gen;
private long patientId;
private long hcpId;
@Override
protected void setUp() throws Exception {
super.setUp();
gen = new TestDataGenerator();
gen.clearAllTables();
gen.standardData();
this.patientId = 2L;
this.hcpId = 9000000000L;
this.factory = TestDAOFactory.getTestInstance();
this.messageDAO = new MessageDAO(this.factory);
this.srAction = new SendRemindersAction(this.factory, this.hcpId);
}
public void testSendRemindersAction() throws ITrustException
{
int numberOfAppts = srAction.sendReminderForAppointments(10);
assertTrue(numberOfAppts >= 5);
}
public void testSendReminders() throws ITrustException, SQLException, FormValidationException {
ApptBean aBean = new ApptBean();
aBean.setApptType("TEST");
aBean.setPatient(patientId);
aBean.setHcp(hcpId);
aBean.setDate(Timestamp.valueOf(LocalDateTime.now().plusDays(4)));
List<MessageBean> mbListBefore = messageDAO.getMessagesFor(patientId);
srAction.sendReminder(aBean);
List<MessageBean> mbList = messageDAO.getMessagesFor(patientId);
assertEquals(mbList.size(), mbListBefore.size() + 1);
MessageBean mBeanDB = mbList.get(0);
assertEquals("Reminder: upcoming appointment in 4 day(s)", mBeanDB.getSubject());
}
}
\ No newline at end of file
...@@ -17,6 +17,8 @@ public class ApptDAOTest extends TestCase { ...@@ -17,6 +17,8 @@ public class ApptDAOTest extends TestCase {
private DAOFactory factory = TestDAOFactory.getTestInstance(); private DAOFactory factory = TestDAOFactory.getTestInstance();
private ApptDAO apptDAO = factory.getApptDAO(); private ApptDAO apptDAO = factory.getApptDAO();
private ApptBean[] appts = null;
private ApptBean a1; private ApptBean a1;
private ApptBean a2; private ApptBean a2;
private ApptBean a3; private ApptBean a3;
...@@ -30,8 +32,6 @@ public class ApptDAOTest extends TestCase { ...@@ -30,8 +32,6 @@ public class ApptDAOTest extends TestCase {
gen.clearAllTables(); gen.clearAllTables();
gen.appointmentType(); gen.appointmentType();
a1 = new ApptBean(); a1 = new ApptBean();
a1.setDate(new Timestamp(new Date().getTime())); a1.setDate(new Timestamp(new Date().getTime()));
a1.setApptType("Ultrasound"); a1.setApptType("Ultrasound");
...@@ -49,6 +49,7 @@ public class ApptDAOTest extends TestCase { ...@@ -49,6 +49,7 @@ public class ApptDAOTest extends TestCase {
a3.setApptType("Ultrasound"); a3.setApptType("Ultrasound");
a3.setHcp(doctorMID); a3.setHcp(doctorMID);
a3.setPatient(patientMID); a3.setPatient(patientMID);
} }
public void testAppointment() throws Exception { public void testAppointment() throws Exception {
...@@ -148,5 +149,20 @@ public class ApptDAOTest extends TestCase { ...@@ -148,5 +149,20 @@ public class ApptDAOTest extends TestCase {
assertEquals(30, type.getDuration()); assertEquals(30, type.getDuration());
assertEquals("Ultrasound", type.getName()); assertEquals("Ultrasound", type.getName());
} }
// Test adding and retreiving upcoming appointments within n days
public void testGetUpcomingAppts() throws Exception {
// Edge case: empty database
List<ApptBean> upcomingAppts = apptDAO.getUpcomingAppts(30);
assertEquals(0, upcomingAppts.size());
// Test returning upcoming appts B
apptDAO.scheduleAppt(a1);
apptDAO.scheduleAppt(a2);
apptDAO.scheduleAppt(a3);
upcomingAppts = apptDAO.getUpcomingAppts(1);
assertEquals(3, upcomingAppts.size());
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment