Problem Set 8: HoosHungry.com
- There is a special automatic adjudicator for PS8. It applies to Questions 2, 4, 5 and 6. Each partner must submit separately.
- Bring in to class a stapled turn-in containing your written answers and screenshots for Questions 1, 3 and 7. Each partner must separately submit a writeup. Your writeup must include your UVA ID (e.g., mst3k) in big block letters at the top. If you have a partner, your writeup must also include your partner's ID in big block letters.
Collaboration Policy - Read Carefully
For this assignment, you make work either alone or with a partner of your choice.You may consult any outside resources, including books, papers, web sites and people, you wish except for materials from previous CS1120 courses. You may consult an outside person (e.g., another friend who is a CS major but is not in this class, or a CS prof, etc.) who is not a member of the course staff, but that person cannot type anything in for you and all work must remain your own. That is, you can ask general questions such as "can you explain recursion to me?" or "how do lists work in Python?", but outside sources should never tell you what to type. If you use resources other than the class materials, lectures and course staff, explain what you used in your turn-in.
You are strongly encouraged to take advantage of the scheduled help hours and office hours for this course.
Purpose
The primary goal of this assignment is to give you some experience with a dynamic web application before you build your own web application for Problem Set 9. In addition, this assignment should help you:
- Understand how a web application is designed and implemented.
- Gain confidence that you can learn new languages on your own.
- Gain experience with some useful languages (Python, SQL, HTML, and JavaScript) for making web applications.
- Build your own web community.
- Satisfy late night cravings with yummy Python Burgers and Lambda Cakes.
Background
In 1990, Tim Berners-Lee, wrote a program called WorlDwidEweb for editing hypertext (text with embedded links to other documents) and developed the HyperText Transfer Protocol (HTTP) for allowing clients (browsers) and servers to talk to each other, Universal Resource Locators (URLs) for naming objects, and the HyperText Markup Language (HTML) for describing hypertext documents. With these pieces in place, anyone could set up a web server and start publishing their own hypertext documents. The web grew exponentially throughout the 1990s, with the number of web sites increasing from a few hundred in 1991 to 215.6 million sites in February 2009 and many fortunes were won and lost.For this assignment you will understand and complete the implementation of a web application that aims to provide a restaurant guide for hungry Hoos. When you are done, you will have produced a dynamic web application that integrates with a map and a database.
To build this, we used several languages:
- HTML (Hypertext Markup Language) — the language used to describe web pages. See the Schemer's Guide to HTML.
- Python — a universal programming language that can be incorporated into web pages and is evaluated by the web server when a page is requested. See the PS7, the Course Book Chapters on Interpreters and the Web, and the Schemer's Guide to Python.
- SQL (Structured Query Language) — a language for manipulating and extracting information from a database similar to the procedures you used in PS5. See the Schemer's Guide to SQL.
- JavaScript — a client-side programming language that is incorporated into generated web pages and evaluated by the web browser. We use JavaScript to interface with the Google Maps client application. (There is no guide provided to JavaScript, since you are not expected to modify any of the JavaScript code.)
Getting Started
Some amount of setup work will be required before your website is up and running. It will be extremely convenient for you if you work on the lab machines for this assignment.To get a feel for the web application that you will be working on, open a web browser to https://church.cs.virginia.edu/cs1120/hooshungry/. Click on Register New User to create an account for yourself. You should receive an email message with your password. Once you have logged in, you will see an additional option to Add Restaurant. Also try clicking on the markers on the map, and the links that pop-up after you click on a marker. Try adding a restaurant, reviewing a restaurant, and looking at the restaurant reviews.
You will be making a website similar to HoosHungry. We will storing your files on a special department webserver, named socrates, so that users can access them with a normal web browser. (We have already made you an account there.)
This special departmental server that will hold your files is sometimes called a network drive. You will have to map the network drive on to your lab computer before you can access the files. (Mac and Linux users: read all the instructions — specific info for you is at the end.)
- If you are working from on grounds, skip this step. If you want
to work from off grounds, you will have to install and run
the virtual private network
(VPN) client to access these UVA resources securely from outside.
If relevant, be sure to click "make always available online" when you're
using the VPN.
- We've had reports that many Mac users struggle to get the VPN setup working correctly on their computers. (Reminder: we only officially support the lab computers for exactly this reason!) Anyway, some such students have reported success using the UVA Hive VMware client for Macs instead.
- Right click on the My Computer icon and select Map Network
Drive from the dropdown menu, as shown in this screenshot:
- Normal files on your hard drive live on C:. We will use
Z: for these networked files for PS8 and PS9. Make sure that
Z: is selected next to the Drive: prompt. Then, at the
Folder: line, write in \\socrates\mst3k where
mst3k is your UVA ID. It should look like this screenshot:
- If just socrates doesn't work, try \\socrates.cs.virginia.edu\mst3k.
- Use the same password you use in the OLS 001 Labs.
- You must have logged on to the OLS 001 Lab computers at least once before you can authenticate here.
- If you are working on an OLS 001 Lab Computer, you will be
authenticated automatically. If not, use CSLAB\mst3k as your
username, where mst3k is your UVA ID. You may have to
click on Connect as a difference user for this.
Note the CSLAB\ prefix in the username. This is essential; without it, you will not be able to authenticate.
- A set of screenshots showing the process for Windows XP is also available.
- Explore the network drive Z: and click through the
public_html and cgi-bin folders until you reach
Z:\public_html\cgi-bin.
- Note that only the Windows machines in the lab are officially supported.
- Do you have a directory hooshungry inside your
cgi-bin directory? And does hooshungry have have
index.py and other files inside of it?
- If so, do nothing for this step! We've already installed ps8.zip for you.
- If you do not already have a full hooshungry
directory inside your cgi-bin directory, then do this:
- Create a directory hooshungry inside your cgi-bin directory. Using lowercase letters matters! If you're at the lab machines in OLS 001, you will be creating Z:\public_html\cgi-bin\hooshungry, but the drive letter may be different on different machines.
- Download ps8.zip and unzip it into your public_html\cgi-bin\hooshungry\ directory.
-
The webserver that will be responsible for making your files available
to the outside world is called plato.
Point your web browser at
http://plato.cs.virginia.edu/cgi-bin/cgiwrap/wrw6y/hooshungry/index.py
but replace wrw6y with your UVA ID. You should see something like
the HoosHungry website.
You will not be able to try out your website fully until you have set up
the database, however.
If you mistakenly extracted your the ps8.zip files to another location, such as public_html\cgi-bin\HoosHungry\ps8\, then you'll need to point your web browser at the appropriate location (e.g., http://plato.cs.virginia.edu/cgi-bin/cgiwrap/wrw6y/HoosHungry/ps8/index.py). Uppercase and lowercase matter!
Database
Because HTTP is a stateless protocol, all information that needs to persist between web requests must be stored somewhere. We use a database to store everything (except for user login information with is stored in a cookie, see below). The Schemer's Guide to Structured Query Language gives a brief introduction to the SQL language we will use to manipulate the database.The University of Virginia will provide you with your own personal MySQL database, hosted on dbm2.itc.virginia.edu. You will have to sign up and activate your database, and then create and manage the appropriate tables on it.
First, you need to create a MySQL account. Follow the directions in the SQL Guide to create your own MySQL account, being sure to select the new password security style (it's the default, so that's easy to do):
After creating your database, edit the db.py file. You can find it in hooshungry\db.py. Change the values assigned to userName, password, server and dbName to match those for the database you created. Notably, it should look something like this:
server = "dbm2.itc.virginia.edu" username = "mst3k" password = "XYZ123" dbName = "mst3k_cs1120"Yes, you really have to change the server line from dbm1 to dmb2. At this point your HoosHungry page will not work, because your new database does not have the right tables! Let's fix that up now.
Users
Since we want to only allow legitimate users to add restaurants and post reviews, we need a table for managing users.You will create a table in your database named users with fields for storing the name, email address, last name, first names (all names except the last name), encrypted password and cookiecounter for each user (managing cookies and passwords is tricky and error prone). In later lectures we will explain more about why the way it does things is semi-secure.
You can create the users table by issuing this SQL command:
To enter SQL commands using phpMyAdmin, first choose your database in the left panel. We could use their handy table creation interface, but we'll do it with raw SQL instead. So click on the SQL tab in the top center: To enter SQL commands using phpMyAdmin, first click on the Databases link near the center of the page.CREATE TABLE users ( id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, user VARCHAR(80) UNIQUE, email VARCHAR(255) UNIQUE NOT NULL, lastname VARCHAR(255) NOT NULL, firstnames VARCHAR(255), password CHAR(80), cookiecounter INT )
Now copy and paste the query above into the text box, and click Go:
Note that each field has a name and a type. The id field is a unique identifier for each user. Since it is labeled AUTO_INCREMENT, the database will give it a value automatically that is one more than the previous entry. The user and email fields have type VARCHAR(num) which means they are a string of up to num characters. They use the UNIQUE and NOT NULL modifiers to indicate that all table entries must have different user names and emails, and that every entry must have a value for these fields.
Now that you have created a table, insert an entry for yourself in the table. For example, I would do this by running the SQL query,
(Don't forget the quote (') marks.) If you do it correctly, it will look something like this, but with your name instead of "Wes Weimer":INSERT INTO users (user, email, lastname, firstnames) VALUES ('weimer', 'weimer@cs.virginia.edu', 'Weimer', 'Wes')
At this point, your users table should contain one entry corresponding to yourself. If you click on users in the left panel, you should see something like this:
Restaurants
We also need a database table to keep track of the restaurants. We will use the restaurants table for this, and create it using this SQL command.You absolutely must have switched over to your own database by now. If you are still using the default wrw6y database in db.py, you should return to Step 5.
You should issue this SQL command for your database in phpMyAdmin:
CREATE TABLE restaurants ( id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, user VARCHAR(80), name VARCHAR(80), cuisine VARCHAR(40), lat DECIMAL(54, 30) NOT NULL, lng DECIMAL(54, 30) NOT NULL, notes TEXT )
Reviews
We want to be able to collect reviews for the restaurants. This requires a new table, reviews, which will store the restaurant reviews. We want to be able to associate reviews with the restaurant they are describing, so we include a field in the reviews table that is a restaurant identifier. It is the number of the id field of the corresponding restaurant in the restaurants table.
You absolutely must have switched over to your own database by now. If you are still using the default wrw6y database in db.py, you should return to Step 5.
Create your reviews table by issuing this SQL command in phpMyAdmin:
CREATE TABLE reviews ( restaurantid INT NOT NULL, user VARCHAR(80), stars INT, comments TEXT )
Google Maps
Our web application uses the Google Maps API to display maps. An "API" is an Application Program Interface, a set of definitions that allow programs to interact with each other. In this case, the Google Maps API is a set of procedures you can use to interact with the Google Maps application that Google provides for displaying and manipulating maps. It provides procedures for controlling the map, putting flags and lines on the map, and obtaining user clicks on the map.To use the Google Maps API, you need to obtain a Google Maps API key. We have already obtained a Google Maps API key for you. There is nothing for you to do in this step.
(If you expect to get more than about 1,000 page views per day for your PS8, you need to contact Google to get separate permission. Follow the directions here: http://www.google.com/apis/maps/signup.html. This will probably not be a problem for you unless you add some extra features to your site!)
At this point, you should be able to see the web application by opening a web browser to http://plato.cs.virginia.edu/cgi-bin/cgiwrap/your_uva_id/hooshungry/index.py You should see a welcome page including links to Register New User and Display Restaurants, plus a map of Charlottesville. If you don't, you may have made a mistake while setting up your database and tables. Also make sure that your db.py file is correct.
Managing Passwords
When you created your user entry in the table, you did not provide a value for the password field. This is because we don't want to store actual passwords in the database. This would be dangerous since anyone who breaks into the database (or just steals the disk it is stored on and starts looking at bits on the disk) would be able to learn everyone's password. Even though you would be foolish to put anything highly confidential on this site, people often use the same password for security-critical and non-security critical websites, so it is important to never store passwords in cleartext.Instead of storing actual passwords in the database we will store encrypted passwords. There are some tricky issues in how to do this that we will discuss in a later lecture, but the basic idea is to store Encrypt(password) in the database, and then when a user logs in check that the value calculated by encrypting the entered password matches the stored password.
To activate your account, you will need to reset the password.
Reload your main page ( http://plato.cs.virginia.edu/cgi-bin/cgiwrap/your_uva_id/hooshungry/index.py ) and click on the Reset Password link.
Understanding SQL
- Insert a user into your users table with user name alyssa, email aph@cs.virginia.edu, last name Hacker and firstnames Alyssa P..
- Insert a user into your users table with user name ben, email bb@cs.virginia.edu, last name Bitdiddle and firstnames Ben.
- Select the lastname of all users in your table. The
response should be a table like this (of course, your result will be
different because you put yourself in the table instead of me):
lastname Weimer Hacker Bitdiddle - Select the lastname and firstnames of all users
in your table in alphabetical order by firstnames. The
response should be a table like:
firstnames lastname Alyssa P. Hacker Ben Bitdiddle Westley Weimer - Select the email address of all users in your table with
lastname matching Hacker. The response should be the
table:
email aph@cs.virginia.edu - Delete all entries from your table whose id does not equal the id for your entry. Note that the MySQL interface will give you a confirmation on DELETE commands, since a mistake could remove all the records you want from the table. It is a good idea with DELETE commands to use a LIMIT n as part of the query to make sure only the right number of entries are deleted. For example, for this question you would do DELETE FROM users ... LIMIT 2 to ensure that no more than 2 entries are deleted.
Turn in: Write down (or print out) and turn in the correct SQL commands.
Debugging Web Applications
Debugging a Python web application is slightly trickier than debugging a normal Python application because your Python code is actually being run on the server, plato, not on on your desktop machine. We will practice debugging together.Anyway, change index.py so that you add the text
if true: then falseto the second line. Note that the line you were just told to add is invalid Python syntax. It represents a mistake.
Direct your browser to http://plato.cs.virginia.edu/cgi-bin/cgiwrap/your_uva_id/hooshungry/index.py . You should see the words Internal Server Error, which are not very helpful.
Now direct your browser to this new URL, which is just like the old one but with a d added after cgiwrap ("d" for "debug"):
http://plato.cs.virginia.edu/cgi-bin/cgiwrapd/your_uva_id/hooshungry/index.py
- If you are mistakenly using Internet Explorer (IE) it may try to download the debugging results as a file instead of displaying them to you. Use Firefox or Chrome, which both work fine.
Scroll down to the absolute bottom of the page. You should find an error message explaining the error on Line 2. Copy-and-paste that error message and submit it via automatic adjudication.
Now go back and fix up index.py by removing the erroneous line!
Whenever you receive a "blank page" or an Internal Server Error message, use the cgiwrapd power to help you debug the problem.
Turn in: A copy of the error message via automatic adjudication.
Simple Web Applications
We have included two simple web forms with the HoosHungry distribution. One is Simple.java and the other is simple-python.py.Notice that when you submit the web form, control is transfered to either simple-python2.py or simple-java2.cgi.
Read all four of Simple.java, Simple2.java, simple-python.py and simple-python2.py carefully. You do not need to understand how simple-java.cgi and simple-java2.cgi work. Choose either Java or Python. Edit the corresponding file and add a form field requesting the year of the user's birth. Edit the corresponding second file and print out the user's year of birth on the other side.
Do not go too quickly through this step — take some time to understand these files, because this is PS9 (the Final Project) in a nutshell.
Take a screenshot of your input form webpage showing the near "year" question. Then take a second screenshot of the second webpage showing the chosen "year" being displayed.
Turn in: The two screenshots demonstrating your working modified simple web application.
Restaurant and Review Information
If would be nice if you could add some reviews and see them on the restaurant pages. The index page has a link to Display Reviews which links to the show-reviews.py file. This file is not complete in your implementation. Before we get started, why don't you add some restaurants to your site. Make sure you add more than just one.If you click on a marker on the map, and then click on the restaurant name, it would be nice to see a page with more information on the restaurant. With the provided implementation, however, you instead get an error since the code for lookup in restaurants.py is not complete.
Turn in: Use the automatic adjudicator. The deliverables are:
- The URL for the restaurant information screen (this must be your website and not church.cs.virginia.edu). For full credit, you must have at least two separate reviews by two different reviewers for the given restaurant.
- Copy and paste the new c.execute("") line from restaurants.py into the adjudicator.
You absolutely must have switched over to your own database by now. If you are still using the default wrw6y database in db.py, you should return to Step 5.
When displaying the reviews, do your best to follow the format provided in the sample website. On the sample website, you can right click on the screen and view page source to see how the html is structured. Try your best to do something similar to this. Additionally, ensure that the ratings are represented using stars (* * * * *) and not numbers (5).
Turn in: Use the automatic adjudicator. The deliverables are:
- The URL for your Display Reviews page. For full credit, you must show at least two separate restaurants, each of which must have at least two separate reviews. That is, you must have added the restaurants and reviews to your database — either via phpMyAdmin or via your HoosHungry website.
- Copy and paste your updated c.execute("SELECT * FROM reviews") line from reviews.py.