diff --git a/src/java/com/jdbernard/nurseryschedule/NurseryScheduleServlet.groovy b/src/java/com/jdbernard/nurseryschedule/NurseryScheduleServlet.groovy new file mode 100644 index 0000000..9f14f3a --- /dev/null +++ b/src/java/com/jdbernard/nurseryschedule/NurseryScheduleServlet.groovy @@ -0,0 +1,132 @@ +package com.jdbernard.nurseryschedule + +import com.jdbernard.util.SmartConfig +import groovy.json.JsonBuilder +import groovy.json.JsonException +import groovy.json.JsonSlurper +import groovy.text.SimpleTemplateEngine +import java.util.Calendar +import java.util.regex.Matcher +import javax.servlet.ServletConfig +import javax.servlet.ServletException +import javax.servlet.http.HttpServlet +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse +import javax.servlet.http.HttpSession + +import static java.util.Calendar.* +import static javax.servlet.http.HttpServletResponse.* + +public class NurseryScheduleServlet extends HttpServlet { + + /// This service currently only supports one user. + private String username + private String password + private String outputDirectory + + private static SimpleDateFormat dataDateFormat = + new SimpleDateFormat("yyyy-MM-dd") + private static SimpleDateFormat displayDateFormat = + new SimpleDateFormat("MMM dd") + + void init(ServletConfig config) { + this.username = config.getInitParameter("username") + this.password = config.getInitParameter("password") + this.outputDirectory = config.getInitParameter("outputDirectory") } + + void doPost(HttpServletRequest request, HttpServletResponse response) { + + HttpSession session = request.getSession(true); + + /// If the user is posting to `/login` then let's try to authenticate + /// them. We don't care about the state of the existing session. + if (request.servletPath == '/login') { + + /// Parse the username/password from the request. + def requestBody + try { requestBody = new JsonSlurper().parse(request.reader) } + catch (JsonException jsone) { + response.status = SC_BAD_REQUEST + return } + + /// If no username or password are configured we cannot + /// authenticate the user. + if (!password || !username) { + response.status = SC_UNAUTHORIZED + return } + + /// If the username or password do not match, deny the request. + if (username != requestBody.username || + password != requestBody.password) { + response.status = SC_UNAUTHORIZED + return } + + response.status = SC_OK + session.setAttribute('authenticated', 'true') + session.setAttribute('username', requestBody.username) + writeJSON([status: "ok"], response) + return } + + /// The other endpoints require the user to be authenticated. + if (!((boolean)session.getAttribute('authenticated'))) { + response.status = SC_UNAUTHORIZED + return } + + switch (request.servletPath) { + case ~ '/make-schedule': + + /// Parse the request body. + def data + try { data = new JsonSlurper().parse(request.reader) } + catch (JsonException jsone) { + response.status = SC_BAD_REQUEST + return } + + /// Calculate dates and modify the schedule data to include + /// them. + def cal = Calendar.getInstance() + cal.time = dataDateFormat.parse(data.date) + int month = cal.get(MONTH) + cal.set(HOUR_OF_DAY, 0) + cal.set(MINUTE, 0) + cal.set(SECOND, 0) + cal.set(MILLISECOND, 0) + + ['first', 'second', 'third', 'fourth', 'fifth'].eachWithIndex + { dayNum, idx -> + /// Set the sunday + cal.set(DAY_OF_WEEK, SUNDAY) + cal.set(DAY_OF_WEEK_IN_MONTH, idx + 1) + if (cal.get(MONTH) == month) + data.sundays[dayNum].date = displayDateFormat.format(cal.time) + + /// Set the wednesday. Note that we have to reformat the + /// input data from {"first": ["PersonA", "PersonB"]} to + /// {"date": "Oct. 6", "volunteers": ["PersonA", PersonB"]} + def volunteers = data.wednesdays[dayNum] + data.wednesdays[dayNum] = [:] + data.wednesdays[dayNum].volunteers = volunteers + + if (cal.get(MONTH) == month) + data.wednesdays[dayNum].date = + displayDateFormat.format(cal.time) } + + cal.set(DAY_OF_WEEK_IN_MONTH, 2) + data.sundays['second'].date = displayDateFormat.format(cal.time) + + /// Build the resulting page. + def engine = new SimpleTemplateEngine() + def scheduleTemplate = engine.createTemplate( + this.getClass().getResource('schedule.template')) + def output = scheduleTemplate.make(data) + + /// Write the results to file. + new File(outputDirectory, data.date + ".html").text = output + response.status = SC_OK + + default: + response.status = SC_NOT_FOUND + return + } + } +} diff --git a/src/test/make_template.groovy b/src/test/make_template.groovy new file mode 100644 index 0000000..59bea9b --- /dev/null +++ b/src/test/make_template.groovy @@ -0,0 +1,34 @@ +import com.jdbernard.util.LightOptionParser +import groovy.json.JsonSlurper +import groovy.text.SimpleTemplateEngine + +def cli = [ + 't': [longName: 'template', arguments: 1], + 'd': [longName: 'data', arguments: 1], + 'o': [longName: 'output', arguments: 1]] + +def opts = LightOptionParser.parseOptions(cli, args as List) + +def templateFile, dataFile, outputFile + +if (opts.t) templateFile = new File(opts.t) +if (opts.d) dataFile = new File(opts.d) +if (opts.o) outputFile = new File(opts.o) + +if (!templateFile || !templateFile.exists() || !templateFile.isFile()) { + println "Template file is not specified or does not exist." + return -1 } + +if (!dataFile || !dataFile.exists() || !dataFile.isFile()) { + println "Data file is not specified or does not exist." + return -1 } + +if (!outputFile) { + println "Output file is not specified." + return -1 } + +def engine = new SimpleTemplateEngine() +def binding = new JsonSlurper().parseText(dataFile.text) +def template = engine.createTemplate(templateFile.text).make(binding) + +outputFile.text = template.toString() diff --git a/src/test/nursery-schedule-2013-10-01.txt b/src/test/nursery-schedule-2013-10-01.txt new file mode 100644 index 0000000..ec5ba84 --- /dev/null +++ b/src/test/nursery-schedule-2013-10-01.txt @@ -0,0 +1,42 @@ +{"date":"2013-10-01", + "sundays":{ + "first":{ + "date": "Oct. 6th", + "toddlers":["Sara Bernard","Priscilla Reid","Becca Torres"], + "infants":["Latonya Kirton","Susan Vacca","Brandie Kristoff"], + "pm":["Susan Miller","Pamala Green"]}, + "second":{ + "date": "Oct. 13th", + "toddlers":["Sara Bernard","Priscilla Reid","Maria Almazan"], + "infants":["Latonya Kirton","Susan Vacca","Rebecca Dombroski"], + "pm":["Zoe Torres","Hannah Torres"]}, + "third":{ + "date": "Oct. 20th", + "toddlers":["Sara Bernard","Priscilla Reid","Delia Borrego"], + "infants":["Latonya Kirton","Susan Vacca","Deborah McDonald"], + "pm":["Jeanie Nelson","Alayna Robert"]}, + "fourth":{ + "date": "Oct. 27th", + "toddlers":["Sara Bernard","Priscilla Reid","Maria Almazan"], + "infants":["Latonya Kirton","Susan Vacca","Crystal Johnson"], + "pm":["Deidra Dawson","Shekinah Dawson"]}, + "fifth":{ + "toddlers":["Sara Bernard","Priscilla Reid","Julie Froese"], + "infants":["Latonya Kirton","Susan Vacca"], + "pm":[]}}, + "wednesdays":{ + "first": { + "date": "Oct. 3rd", + "volunteers": ["Courtney or Bryan Bootka","Gabby Galvez"]}, + "second": { + "date": "Oct. 10th", + "volunteers": ["Reeta or Lionel Aguilar","Stephanie Langley"]}, + "third": { + "date": "Oct. 17th", + "volunteers": ["Christina Grooms","Lanell Hanson"]}, + "fourth": { + "date": "Oct. 24th", + "volunteers": ["Cassie Hernandez"]}, + "fifth": { + "date": "Oct. 31st", + "volunteers": ["Regina Noble","Vita Sharpe"]}}} diff --git a/src/test/test.html b/src/test/test.html new file mode 100644 index 0000000..7d4071d --- /dev/null +++ b/src/test/test.html @@ -0,0 +1,165 @@ + + +
+ + + +