Assignment 2A: PizzaTron4000

Due: Friday February 15th 2019 @ 11:59pm

Introduction

pizzatron3000

Pizza is a type of food that penguins commonly eat in Club Penguin. The Pizza Parlor, with its Pizzatron 3000, pumps out thousands of pizzas every day for hungry penguins across the island. Some notable flavors include Licorice Pizza, Flamethrower Fish Pizza, and of course, Seaweed Pizza. Gary the Gadget Guy wants to upgrade the Pizzatron 3000 into the Pizzatron 4000 by taking inspiration from what's trending on Twitter! He needs you to design a gadget that will let him view a feed of all pizza-related tweets.

We have provided a web server that will fetch the 26 most recent Tweets about Pizza every time you ask for them. You will build a website that takes those Tweets and presents them to the user in some kind of a streaming list.

You will be responsible for periodically querying the server for new Tweets, and using the DOM to append them to a new part of the page. You will also be responsible for filtering out duplicates, as some Tweets may overlap with the last time you requested them.

Important Note: this project involves making requests that violates the same-origin policy, and as such, it requires a web browser that supports XMLHttpRequest 2 and CORS. This means you must be using a semi-recent web browser: Firefox 4+, Chrome 7+, Safari 5+, or IE 10+.

Setup

If you are using a department machine, run cs132_install assignment2A to get started.

The script will create a assignment2A directory in /gpfs/data/course/cs1320/your_cs_login/

If you are using your own computer, download the zip of the stencil here to get started

You should implement all of your HTML in index.html, CSS in index.css, and all of your JavaScript in index.js.

Before starting this assignment, it is helpful to first complete the JavaScript prelab & lab. JavaScript is one of the core technologies of the web, and will be used extensively in this and future assignments.

Also since you are fetching tweets for this assignment, you are allowed to reuse your code from Assignment 1 Part 2, though you are not required to.

Overview

The TwitterFeed Server

You will be interacting with a server we’ve provided that will give you Pizza-related Tweets.

On a department machine, if your path is fixed, you can run the server by entering cs132_twitterfeed (your path is fixed if you can run cs132_install). If your path isn't fixed, you can either start the server by typing the full path /course/cs1320/bin/twitterfeed/cs132_twitterfeed or by fixing your path first following instructions in assignment0.

If you are working locally, assuming you have python3 installed, you can run the server by first CDing into your assignment directory and then entering python3 cs132_twitterfeed.py

Just for fun, you may also specify an additional argument to tell the server to look for tweets with a specific topic: cs132_twitterfeed [topic] (department machine) or python3 cs132_twitterfeed.py [topic] (local machine). But for grading, we will be testing your handin on pizza (pizza is the default topic when no argument is passed).

The server has been started once you see something like [OK] Server is listening to http://localhost:8081/feed/start. It might take some time for the script to setup first time running. And you can visit, in a browser on the same machine, the bolded address http://localhost:8081/feed/start to see the server's response in action!

Note: if you are using ssh, you need to ssh into the same department machine to receive server response. When you have sshed in any department machine, you can run ssh "department machine name" to access another department machine, the department machine name is the first thing in terminal's prompt (e.g. cslab3d ~ $)

Make a GET request to this endpoint to obtain a new block of 26 Tweets. The response will be returned as a JSON array. Take note that some of these Tweets may be duplicates of Tweets that you’ve already seen, and it is your responsibility to filter those out. Every Tweet has a unique id field that you can use for this purpose.

For testing with duplicate tweets, you can pass in a flag cs132_twitterfeed -r [topic] (department machine) or python3 cs132_twitterfeed.py -r [topic] (local machine) to request more repetitive tweets.

The Search API's example response describes what a success response from server looks like.

The available properties for each tweet (represented by an object in "statuses") are those returned by the Twitter API for Tweets. Note that Tweet entities are supported, so you should consider using them to create a more engaging user experience.

Importing jQuery

If you choose to use jQuery in your assignment, the first thing you have to do is import the library from the web. There are a couple of ways to do so, but we're going to show you how to include the jQuery CDN in your code. A CDN, or content delivery network, is a distributed network that 'delivers content' to users based on geographical location; since there is a high probability that a user visiting the site (you in this case) has already visited a site that requires jQuery, the library has already been cached, and no file serving latency is experienced!

To request the library via the CDN, add the following the header of an HTML file:

<script
  src="https://code.jquery.com/jquery-3.1.1.min.js"
  integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
  crossorigin="anonymous">
</script>

Getting data from an API endpoint

Since the idea of the TwitterFeed is that it’s a live stream of Tweets, having the page refresh every second with new content would be a bit annoying. There are multiple ways to do this, but we will introduce you to 2 methods, AJAX and Fetch.

Ajax, which historically stands for Asynchronous JavaScript and XML, is jQuery's method for fetching data.

The standard template for an Ajax request looks something like this:

//specify a url, in this case our web server
$.get('http://localhost:8081/feed/start', function(data, status) {
  //do something with data
}

Fetch is a bit different in that it is from your browser's native API. This means that you don't have to import anything to use fetch!

The standard template for a fetch request looks something like this:

// specify a url, in this case our web server
fetch('http://localhost:8081/feed/start')
.then(res => res.json())
.then(data => {
  //do something with data
})
.catch(err => {
  //error catching
  console.log(err)
})

You might want to encapsulate this into a simple function to make your life easier

Combine the above template with something like setInterval(...) (see the Mozilla Developer Network’s documentation) to periodically load new Tweets. Note that the timeout value passed to setInterval(...) is in milliseconds, and we ask that you don’t use a value smaller than 3000 (3 seconds) so as not to overload our server.

If you want to learn more, there’s a good tutorial on Using XMLHttpRequest on the Mozilla Developer Network.

Aside: the Same-Origin Policy

In order to prevent a particularly malicious class of attacks known as cross-site request forgery, web browsers enforce a policy known as the same-origin policy. Essentially, the same-origin policy places restrictions on what can be done with content that originates from a different origin than that of the page you’re currently on (an origin being a combination of a domain name, port, and protocol – HTTP or HTTPS).

By default, requests to websites on different origins are forbidden by web browsers. The reason for this is that I could, for instance, make an request from my website at evilsite.com to facebook.com, and the browser would send along all of your saved cookies for Facebook, meaning I would have unrestricted access to your (fully logged in!) Facebook session. I could somewhat trivially construct a website that, just by virtue of visiting it, would “like” my company’s page on Facebook (or something much more malicious). Thus, the same-origin policy is a “Good Thing”.

However, there are times when the same-origin policy makes it very inconvenient to do legitimate things – like on this project. To that end, a new standard called CORS has evolved. By adding a few headers to our responses from the TwitterFeed server:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, Content-Length, X-Requested-With

… we are able to inform the browser that “yes, this website will allow other websites to make requests to it.” In particular, Access-Control-Allow-Origin: * says that our server will respond to requests from any origin. In practice, you would want to place a list of domain names here that your website is explicitly allowing requests from (for example, Facebook might not want to allow evilsite.com to make request to it, but it might allow instagram.com to do it).

Appending the Tweets

You’ll want to come up with some way to insert new Tweets into the page.

Using jQuery

// we have an unordered list of Tweets
let ul = $('#tweets')
// create a new li element for the Tweet, and append it
let li = $('<li></li>')
li.html('<strong>${data[0].user.name}</strong> ${data[0].text}')
ul.append(li)

Using plain javascript

// we have an unordered list of Tweets
let ul = document.getElementById('tweets')
// create a new li element for the Tweet, and append it
let li = document.createElement("li")
li.innerHTML('<strong>${data[0].user.name}</strong> ${data[0].text}')
ul.append(li)

Note that you could use element.prepend(...) instead of element.append(...) if you wanted to alter Tweet chronology (newest on top vs. newest on bottom). For this assignment you are required to have the feed display the newest Tweets on top. The Mozilla Developer Network documentation for HTML elements includes a large number of DOM methods you could use to make your life easier.

Additional Features

Two additional features are required to have a complete TwitterFeed:

Requirements

A complete TwitterFeed will be a website that:

Handing In

Before handing in your project, make sure you’ve checked to make sure you’ve filled in your README.md file. You can use any format you like for your README, but Markdown is highly recommended. We provide markdown resources under the Docs page. Make sure to document any known bugs and important design decisions.

If you used a department machine, run the handin script cs132_handin assignment2A to submit your code.

If you used your own computer, transfer your files to a department machine and submit there. Refer to our remote setup instructions under the Docs page.