diff --git a/src/java/com/jdbernard/nurseryschedule/NurseryScheduleServlet.groovy b/src/java/com/jdbernard/nurseryschedule/NurseryScheduleServlet.groovy deleted file mode 100644 index 9f14f3a..0000000 --- a/src/java/com/jdbernard/nurseryschedule/NurseryScheduleServlet.groovy +++ /dev/null @@ -1,132 +0,0 @@ -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/www/css/schedule-maker.scss b/src/www/css/schedule-maker.scss index 186f854..7e3a324 100644 --- a/src/www/css/schedule-maker.scss +++ b/src/www/css/schedule-maker.scss @@ -16,65 +16,123 @@ article,aside,details,figcaption,figure, footer,header,hgroup,menu,nav,section { display:block; } +// Fonts +@import url(http://fonts.googleapis.com/css?family=Abel); + +html { font-size: 90%; } + body { - line-height: normal; + font-family: "Abel"; + line-height: 1.1em; margin: 2rem; } -.header { position: relative; } +.inactive { opacity: 0.5; } -.load-dialog { - background: rgba(0, 0, 0, 0.5); - bottom: 0; - display: none; - position: absolute; - top: 0; - left: 0; - right: 0; - z-index: 10; - - div { - text-align: center; - margin-top: 4rem; - - span { - background: whitesmoke; - border-radius: 3px; - padding: 1em; - - #fileLoad { width: 30rem; } } } } - -.tools { - - position: absolute; - top: 0; - right: 0; - - input[type="date"] { - border: solid thin gray; - border-radius: 3px; } - - ul { - list-style: none; +@media screen { + body { line-height: normal; } - li { - padding-right: 0.5rem; - display: inline-block; } } - - .publish { text-decoration: line-through; } } + .print-only { display: none; } -.sundays { border-right: solid thin lightgray; } -.wednesdays { padding-left: 2rem; } + .load-dialog { + background: rgba(0, 0, 0, 0.5); + bottom: 0; + display: none; + position: absolute; + top: 0; + left: 0; + right: 0; + z-index: 10; + + div { + text-align: center; + margin-top: 4rem; + + span { + background: whitesmoke; + border-radius: 3px; + padding: 1em; + + #fileLoad { width: 30rem; } } } } + + + .sundays { + border-right: solid thin lightgray; + .remove { left: 7.5rem; } + .clone { left: 6.5rem; } } + + .wednesdays { + padding-left: 2rem; + .remove { left: 11.5rem; } + .clone { left: 10.5rem; } } + + .sundays, .wednesdays { width: 49%; } + + .teacher-needed { + color: #A00; + font-style: italic; } + + header { position: relative; } + + .tools { + + position: absolute; + top: 0; + right: 0; + + input[type="date"] { + border: solid thin gray; + border-radius: 3px; } + + ul { + list-style: none; + + li { + padding-right: 0.5rem; + display: inline-block; } } + + .publish { text-decoration: line-through; } } + +} + +@media print { + body { + line-height: 1.1em; } + + .load-dialog, .tools, .teacher-needed, .screen-only { display: none; } + + .sundays, .wednesdays { width: 100%; } + + .sundays { border-bottom: solid thin lightgray; } +} + +h5 { + font-size: small; + font-weight: normal; + text-decoration: underline; } + +.first, .second, .third, .fourth, .fifth { + display: inline-block; + margin-bottom: 2rem; + vertical-align: top; + width: 19em; } + +.date { } + +ul { list-style: none; } + +.toddlers, .infants { + display: inline-block; + vertical-align: top; + width: 9rem; } + +div.am, div.pm, .wednesdays ul { + margin-top: 0.5rem; } .sundays, .wednesdays { display: inline-block; line-height: 1.1rem; margin-top: 2rem; vertical-align: top; - width: 49%; - - .teacher-needed { - color: #A00; - font-style: italic; } li { position: relative; @@ -98,11 +156,3 @@ body { &.editing:hover { .clone, .remove { display: none; } } } } - -.sundays { - .remove { left: 7.5rem; } - .clone { left: 6.5rem; } } - -.wednesdays { - .remove { left: 11.5rem; } - .clone { left: 10.5rem; } } diff --git a/src/www/index.html b/src/www/index.html index b6392e4..9574ad9 100644 --- a/src/www/index.html +++ b/src/www/index.html @@ -1,122 +1,116 @@
- + + + + + + + + + + + + +