Assignment 4: Bitter

Due: 5pm, Thursday, March 13. Value: 50 pts. You may work with one other student on this assignment if you wish.

In this assignment, you'll develop a Web server for a Twitter knock-off named Bitter, where users post beets complaining about life, and where other users can subscribe to other users' beet feeds. The server will rely upon SQLite to store information about the users and their beets.

Browser-side implementation

A browser-side implementation, developed in HTML, CSS, and JavaScript is already prepared for you in the following files.

main.html the HTML and CSS necessary for the page.
bitter-client.js the JavaScript (using jQuery) that talks to the server.
jquery-1.11.0.min.js the jQuery library that the browser depends upon.

You should not modify any of these files as part of this assignment.

Server-side setup

  1. You probably still have Node.js installed along with the packages downloaded with the npm commands, done as Steps 1 and  2 in Assignment 2; but if not, you will need to do so.

  2. Into the directory where you will do your work for this assignment, download the three files named above that are part of the browser-side implementation as well as two more files:

    bitter-init.sql Contains SQL for configuring an initial SQLite database.
    bitter-server.js Contains skeleton Node.js code for a server.
  3. At the command line in that same directory, execute the command “sqlite3 beets.db < bitter-init.sql” to create the SQLite database, named beets.db

  4. To start the server, execute “node bitter-server.js”, which starts the server on port 8888 on your local computer. In a Web browser, you can load the page by navigating to localhost:8888.

    Whenever you finish editing the bitter-server.js file and are ready to test your modified version, you'll need to stop the server running by typing Ctrl-C (depress the Ctrl key, then type C, then release the Ctrl key). And then you'll restart it again using “node bitter-server.js”.

Database

The database created using the SQL in bitter-init.sql includes three tables.

users(loginpasswd)
beets(beetidloginmessageposttime)
subscriptions(subscriberfeed)

It also creates three users.

Login IDPasswordSubscriptions
bugsbunny elmer, daffy
elmerfudd bugs
daffyduck bugs

AJAX requests

In addition to serving the browser-side files as downloaded, your program should be able to respond to the following AJAX requests that come from the Web browser. All AJAX responses should be in JSON format, with an ok field that is true or false depending on whether the request is successful. Possible causes of unsuccessful responses include problems in SQL as reported by SQLite, or the failure conditions listed below. If ok is false, an additional attribute message provides more details about the problem, formatted to be appropriate for display to the user. If ok is true, some AJAX responses (namely /fetch and /feeds) will include additional data as specified below.

/login [Note: already implemented in handout code]

HTTP request type: POST

HTTP request parameters: login, passwd

Failure condition: Login ID/password combination not found in database.

Action: None. This is just for confirming that login ID/password combination is valid.

/fetch

HTTP request type: POST

HTTP request parameters: login, passwd

Failure condition: Login ID/password combination not found in database

Action: Retrieves all beets in the database that belong to the user's feed or to one of the feeds to which the user has subscribed.

HTTP response data: beets, a list of objects representing beets; each beet includes login, message, and posttime attributes. The beets should be in reverse order by post time, and the list should only contain beets that are either posted by the user or in feeds subscribed to by the user.

/add

HTTP request type: POST

HTTP request parameters: login, passwd, message.

Failure conditions:

  1. Login ID/password combination not found in database.
  2. Message contains more than 100 characters.

Action: Adds a new beet into the user's feed. (Note that you need not specify beetid or posttime; both will default to appropriate values.)

/feeds

HTTP request type: POST

HTTP request parameters: login, passwd.

Failure condition: Login ID/password combination not found in database.

Action: Retrieves a list of all users' login IDs along with an indicator of whether the logged-in user has subscribed to that user's feed.

HTTP response data: feeds, a list of objects representing users; each user object includes login and subscribed attributes. The beets should be in alphabetical order by login ID. The subscribed attribute should be 0 or 1 indicating whether the user has subscribed to that user's feed.

/subscribe

HTTP request type: POST

HTTP request parameters: login, passwd, feed.

Failure conditions:

  1. Login ID/password combination not found in database.
  2. Requested feed does not exist among users.
  3. User is already subscribed to the feed.

Action: Modifies the database to reflect that the user has subscribed to the requested feed.

/unsubscribe

HTTP request type: POST

HTTP request parameters: login, passwd, feed

Failure conditions:

  1. Login ID/password combination not found in database.
  2. Requested feed does not exist among users.
  3. User is already not subscribed to the feed.

Action: Modifies the database to reflect that the user is no longer subscribed to the requested feed.

/register

HTTP request type: POST

HTTP request parameters: login, passwd

Failure conditions:

  1. Login ID or password is more than 10 characters long.
  2. Login ID or password is empty.
  3. Login ID contains characters that are not letters or digits. (To test this, I recommend “if (!/^[a-z0-9]+$/.test(login))”.)
  4. Login ID is already in the database.

Action: Adds a new user into the database.

Pointers

  • Most AJAX requests (all but /register) involve confirming whether the login ID/password combination is valid. The distributed code includes a function confirmLogin that I strongly recommend that you use for this. Its final argument is a function that is called only if the ID/password combination is valid.

  • I suggest breaking this assignment into steps, fully implementing and testing your solution before going on to the next step. Here are the steps I would recommend, ordered by estimated difficulty.

    1. Implement /fetch and /add.

    2. Implement /feeds and /subscribe.

    3. Implement /unsubscribe and /register.

  • Please be sure to test the failure conditions! In some cases, the most straightforward way to test the condition may be to edit the database while the server is running. For example, to test /subscribe's failure condition 3, you may want to load the list of feeds in your browser, then in a terminal window open up SQLite to add a subscription, then try to add the same subscription via the browser to confirm that an error results.