CSc 445 Assignment 3

An Active Calendar

Assigned
Due

Oct 7
95 pts
Oct 24

Update the Assignment 2 Calendar to let it contain appointments. The appointments are saved on the Sandbox server and can be set or queried using AJAX requests transmitting JSON. You will use an existing server script described in more detail below.

The appointments are just arbitrary text associated with a particular day. There is no attempt to display appointments by times of day, and no way to enter recurring events. Each appointment does have a color code, which maps to a display color for the day. (Choose whatever colors you like for each code.)

Each appointment belongs to a calendar. A calendar is just a name you make up to identify groups of appointments. The calendar page displays appointments from one calendar at a time. A calendar must be created, then appointments may be added or removed. Anyone can create a calendar at any time, with any name not yet in use. Anyone can manipulate any calendar; the system has no security at all. (Perhaps assignment 4 will fix that.)

There are several functions you should implement. I will show how I did it, but you are not required to follow my style (which is usually fairly minimal) or interface design. You may start from your version of assignment two or mine (there is a key posted). Or use one and swipe parts from the other.

Required Operations

  1. Add a control to enter a calendar name, to create a calendar by that name, and to load the appointments associated with that calendar. Mine looks like this now:
    The calendar is empty at first. Then, use the box at the top to give a calendar name, and press load to fill in the appointments. Or, use create to create the calendar if it does not exist.

    (There are no doubt prettier ways to do this.)

  2. When using the arrows to move to the previous or next month, automatically load the calendar, if there is a name in the box.
  3. The day boxes are small, so the full appointment text may not fit. You should hide the extra text, but expand boxes when pointed to. Mine expand down and right, except on the right side, when it expands to the left. (There are other arrangements, including perhaps centering the appointment over the calendar. Do what you think looks nice.)
  4. Provide a control to edit the contents of a block. For mine, when the user clicks on an appointment, the page presents an editing control.
    As you see, there is space to edit the text, and buttons to save, clear the text, or cancel the edit. In the upper right is a control to select one of four colors to display the appointment. Of course, cancel discards changes and closes the edit box. Save transmits changes to the server, and closes the edit box.
  5. Provide a control to delete an appointment. Presently, I just delete it unconditionally on a right click. Need to provide something less prone to error (as you should). Either a confirm or an undo. Delete removes it from the the appointment from the calendar display, and from the database on the server using an AJAX request.
  6. Appropriate display of error messaged. I have a status line at the bottom that just updates when something happens. The examples show a message that appointments have been loaded (except the third, that seems to need a fix.) It displays error messages on failures, such as loading a calendar which does not exist.

Server Interface

Access the appointments on the server using AJAX calls, as listed below. Times are given, each way, as Unix time with 1 second resolution (see below). Requests are sent with a few parameters on the URL, and usually a JSON payload. Responses which are HTTP errors (codes 400 or 500) return plain text. Successful responses (code 200) always send JSON. These are arrays, in which the first element is a string, either OK or DBERR, in which case there is one more element which is an error message string.

When the response is an HTTP level error, 400 or 500, the response body is simply a text message describing the error. A 500 code usually means something is wrong with the service; a 400 is something wrong with what you sent, such as a missing URL parameter or a JSON syntax error. These are errors with the networking or transmission of data, rather than the rules of the database.

http://sandbox.mc.edu/~bennet/cs445/support/cal2.php?OP=CREATE&ID=id
Create a calendar named id. On success, the response is simply [ "OK" ].
http://sandbox.mc.edu/~bennet/cs445/support/cal2.php?OP=FETCH&ID=id&MONTH=time
Fetch all the appointments on calendar id in the month of the sent time. Any date within the month works equivalently. A successful response is a JSON array starting with "OK" and followed by a list of appointments which are simple objects having a "date", "color" and "text". The color is simply an integer code, which your app maps to some actual color. Since there may be no appointments, the list may be empty, so your response array consists only of the "OK".
http://sandbox.mc.edu/~bennet/cs445/support/cal2.php?OP=UPDATE&ID=id
Send a list of appointments for the calendar denoted by id to the server. You must use a POST request (rather than a get) to transmit your list, which has the same format as the FETCH response, minus the leading "OK". (Note: Though you can send any number of appointments, my app never uses an array larger than one.) The sent appointments are saved in the database. If an appointment already exists for any of the dates, it is replaced with the new data. A successful response is a two-element array, with the "OK" followed by the number of appointments saved, which should match what you sent.
http://sandbox.mc.edu/~bennet/cs445/support/cal2.php?OP=DELETE&ID=id
Delete appointments on the calendar given by id. This is a post request that takes an array of times. Appointments for those days are deleted. A successful response is a two-element array, with the "OK" followed by the number of appointments deleted, which may be fewer than the number of dates you sent, since it's possible no appointment exists for some of them.

Times

The times transmitted either way are Unix times with one second resolution. Of course, for this application we only care about which day, so the portion of this which gives the time of day is generally ignored.

A Unix time is just a single integer giving the number seconds since the start of 1970 at Greenwich. Seconds since 1970 is also the basis of timekeeping in JavaScript, but it uses millisecond resolution. That is, a JavaScript time is the number of milliseconds since 1970 began. That means, if you have a JavaScript Date object d and you want to make a Unix time to send to the server, just do this:
let u = d.getTime()/1000
The getTime() method just returns the millisecond time value, so just divide by 1000 to get seconds. Going the other way, if you have a Unix time u from the server (an integer value in a variable), you can put it into a JavaScript Date object with
let d = new Date(u*1000);

Some Helpful Local Commands

I have installed a few small shell scripts as local commands on Sandbox which might be useful. You can run these from the command line on Sandbox. (This doesn't mean you have to do all your work there. Just manage to connect so you can run a few commands.) The first is the Unix time converter
bennet@sandbox ~]$ utime.sh Jan 15 unix 1736920800 = js 1736920800000 = Wed Jan 15 12:00:00 AM CST 2025 [bennet@sandbox ~]$ utime.sh Nov 26, 2020 unix 1606370400 = js 1606370400000 = Thu Nov 26 12:00:00 AM CST 2020 [bennet@sandbox ~]$ utime.sh 1774739675113 unix 1774739675 = js 1774739675113 = Sat Mar 28 06:14:35 PM CDT 2026
You can run it with a human date or a number. If a number, it guesses Unix or JS based on it size (cutoff is the year 3000 or something). If you give something that isn't a number, it tries to interpret it as a date. It then prints back what you sent, along with the other two equivalencies. For JS time input, the milliseconds past the last second are just discarded. If you type a human time, the code that reads it is pretty reasonable. If it doesn't like it, it will tell you.

The others make HTTP requests to the server using the above protocol. They print out both the request and the response, and are are useful to see how this works, and to add test data to a calendar while you are working on your project.

  1. mkcal.sh takes a name and a name and creates a calendar.
    bennet@sandbox support]$ mkcal.sh alice GET http://sandbox.mc.edu/~bennet/cs445/support/cal2.php?OP=CREATE&ID=alice [ "OK" ] [bennet@sandbox support]$ mkcal.sh alice GET http://sandbox.mc.edu/~bennet/cs445/support/cal2.php?OP=CREATE&ID=alice ["DBERR","Calendar alice already exists."]
  2. addapt.sh adds a single appointment (so it's not fully general). It takes an id (calendar name), date, color (just an integer number) and some text. The date is a human date, and anything with spaces must be quoted.
    [bennet@sandbox support]$ addappt.sh alice "Oct 10" 3 "Sleep in, then watch TV." POST http://sandbox.mc.edu/~bennet/cs445/support/cal2.php?OP=UPDATE&ID=alice [ { "date": 1760072400, "color": 3, "text": "Sleep in, then watch TV." } ] ["OK",1] [bennet@sandbox support]$ addappt.sh alphonse "Oct 11" 3 "Sleep in, then watch TV." POST http://sandbox.mc.edu/~bennet/cs445/support/cal2.php?OP=UPDATE&ID=alphonse [ { "date": 1760158800, "color": 3, "text": "Sleep in, then watch TV." } ] ["DBERR","No such calendar alphonse"]
  3. delappt.sh deletes a single appointment (also not fully general). It takes a name and a date.
    bennet@sandbox support]$ delappt.sh alice "Oct 10" POST http://sandbox.mc.edu/~bennet/cs445/support/cal2.php?OP=DELETE&ID=alice [ 1760072400 ] ["OK",1] [bennet@sandbox support]$ delappt.sh alice "Oct 20" POST http://sandbox.mc.edu/~bennet/cs445/support/cal2.php?OP=DELETE&ID=alice [ 1760936400 ] ["OK",0] [bennet@sandbox support]$ delappt.sh alphonse "Oct 20" POST http://sandbox.mc.edu/~bennet/cs445/support/cal2.php?OP=DELETE&ID=alphonse [ 1760936400 ] ["DBERR","No such calendar alphonse"]
  4. calfetch.sh gets the appointments for the indicated month. Takes the calendar and a time which can be anywhere within the month.
    [bennet@sandbox support]$ calfetch.sh alice "Oct 18" GET http://sandbox.mc.edu/~bennet/cs445/support/cal2.php?OP=FETCH&ID=alice&MONTH=1760763600 [ "OK" ] [bennet@sandbox support]$ calfetch.sh bennet "Oct 18" GET http://sandbox.mc.edu/~bennet/cs445/support/cal2.php?OP=FETCH&ID=bennet&MONTH=1760763600 [ "OK", { "date": 1759770000, "color": 0, "text": "Monday, Monday, can't trust that day. Monday, Monday, somehow it just turns out that way." }, { "date": 1760029200, "color": 3, "text": "No lab today." }, { "date": 1760979600, "color": 1, "text": "Wash the car." }, { "date": 1761066000, "color": 1, "text": "Probably get it dirty again." }, { "date": 1761238800, "color": 2, "text": "Pick up the newspaper and cry." }, { "date": 1761930000, "color": 3, "text": "Dress up as a tax man, so I can get stuff from people and scare them." } ]
    This one also runs the result through a tool which formats the returned JSON. The string as actually returned is more compact.

The chat example contains two examples of AJAX calls. The ones for the project will follow a similar pattern. When you need to send a JSON, you will need to use a POST request instead of a GET. This page has an example (third code block).

When you're ready, post your solution (all three files) on Sandbox, then paste in the URL for the .html file (from which the other two are linked) and send it.