diff --git a/assignments/Project/README.txt b/assignments/Project/README.txt new file mode 100644 index 00000000..6bc643d2 --- /dev/null +++ b/assignments/Project/README.txt @@ -0,0 +1,32 @@ +Application URL: http://block647068-f9b.blueboxgrid.com:6543 + +Github URL: https://github.com/yenlinsu/training.python_web/tree/master/assignments/Project + + +Project Description: Network Deployment Automation System + +Front End: +- Automation Process initiation: + - Form: input site specific information (location, network, etc) - complete + - Submitted data validation - complete + - store submitted data into ZODB - not complete yet +- Query site specific data stored in ZODB: + - Form: input site selection - complete + - Submitted data validation - complete + - Display the contents of the objects in a nicely formatted table, based on different query set - not complete yet +- user login/out (not complete yet) + +Backend: (out of scope for this project due to the time required to develop this portion) +- IP subnetting (user input an IP supernet and the system generate a list of subnets based on a pre-defined IP subnetting scheme) - not complete yet + - based on the subnetting result, create a set of objects needed for generating the network device configs + - take those objects and generate the configs, save them to txt files + +Extras down the road: (out of scope for this project) +- learn APIs of other network management system so my deployment system can automate populating data into those network management systems + +Note: the "not complete yet" part will be the focus of the spring term class project. + + + +Instructions on how to run my project locally on your laptop: +- packages needed: pyramid_zodbconn, pyramid_tm, deform diff --git a/assignments/Project/deploy_auto/__init__.py b/assignments/Project/deploy_auto/__init__.py new file mode 100644 index 00000000..ae7dca8d --- /dev/null +++ b/assignments/Project/deploy_auto/__init__.py @@ -0,0 +1,18 @@ +from pyramid.config import Configurator +from pyramid_zodbconn import get_connection +from .models import appmaker + + +def root_factory(request): + conn = get_connection(request) + return appmaker(conn.root()) + + +def main(global_config, **settings): + """ This function returns a Pyramid WSGI application. + """ + config = Configurator(root_factory=root_factory, settings=settings) + config.add_static_view('static', 'static', cache_max_age=3600) + config.add_static_view('deform_static', 'deform:static') + config.scan() + return config.make_wsgi_app() diff --git a/assignments/Project/deploy_auto/models.py b/assignments/Project/deploy_auto/models.py new file mode 100644 index 00000000..79dfb418 --- /dev/null +++ b/assignments/Project/deploy_auto/models.py @@ -0,0 +1,14 @@ +from persistent.mapping import PersistentMapping +from persistent import Persistent + +class Deploy_Auto(PersistentMapping): + __name__ = None + __parent__ = None + +def appmaker(zodb_root): + if not 'app_root' in zodb_root: + app_root = Deploy_Auto() + zodb_root['app_root'] = app_root + import transaction + transaction.commit() + return zodb_root['app_root'] diff --git a/assignments/Project/deploy_auto/static/favicon.ico b/assignments/Project/deploy_auto/static/favicon.ico new file mode 100644 index 00000000..71f837c9 Binary files /dev/null and b/assignments/Project/deploy_auto/static/favicon.ico differ diff --git a/assignments/Project/deploy_auto/static/footerbg.png b/assignments/Project/deploy_auto/static/footerbg.png new file mode 100644 index 00000000..1fbc873d Binary files /dev/null and b/assignments/Project/deploy_auto/static/footerbg.png differ diff --git a/assignments/Project/deploy_auto/static/headerbg.png b/assignments/Project/deploy_auto/static/headerbg.png new file mode 100644 index 00000000..0596f202 Binary files /dev/null and b/assignments/Project/deploy_auto/static/headerbg.png differ diff --git a/assignments/Project/deploy_auto/static/ie6.css b/assignments/Project/deploy_auto/static/ie6.css new file mode 100644 index 00000000..b7c8493d --- /dev/null +++ b/assignments/Project/deploy_auto/static/ie6.css @@ -0,0 +1,8 @@ +* html img, +* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none", +this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')", +this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("http://github.com/','').replace('")',''), +this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')", +this.runtimeStyle.backgroundImage = "none")),this.pngSet=true) +);} +#wrap{display:table;height:100%} diff --git a/assignments/Project/deploy_auto/static/middlebg.png b/assignments/Project/deploy_auto/static/middlebg.png new file mode 100644 index 00000000..2369cfb7 Binary files /dev/null and b/assignments/Project/deploy_auto/static/middlebg.png differ diff --git a/assignments/Project/deploy_auto/static/pylons.css b/assignments/Project/deploy_auto/static/pylons.css new file mode 100644 index 00000000..aa31385d --- /dev/null +++ b/assignments/Project/deploy_auto/static/pylons.css @@ -0,0 +1,372 @@ +html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td +{ + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-size: 100%; /* 16px */ + vertical-align: baseline; + background: transparent; +} + +body +{ + line-height: 1; +} + +ol, ul +{ + list-style: none; +} + +blockquote, q +{ + quotes: none; +} + +blockquote:before, blockquote:after, q:before, q:after +{ + content: ''; + content: none; +} + +:focus +{ + outline: 0; +} + +ins +{ + text-decoration: none; +} + +del +{ + text-decoration: line-through; +} + +table +{ + border-collapse: collapse; + border-spacing: 0; +} + +sub +{ + vertical-align: sub; + font-size: smaller; + line-height: normal; +} + +sup +{ + vertical-align: super; + font-size: smaller; + line-height: normal; +} + +ul, menu, dir +{ + display: block; + list-style-type: disc; + margin: 1em 0; + padding-left: 40px; +} + +ol +{ + display: block; + list-style-type: decimal-leading-zero; + margin: 1em 0; + padding-left: 40px; +} + +li +{ + display: list-item; +} + +ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl +{ + margin-top: 0; + margin-bottom: 0; +} + +ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir +{ + list-style-type: circle; +} + +ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir +{ + list-style-type: square; +} + +.hidden +{ + display: none; +} + +p +{ + line-height: 1.5em; +} + +h1 +{ + font-size: 1.75em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +h2 +{ + font-size: 1.5em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +h3 +{ + font-size: 1.25em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +h4 +{ + font-size: 1em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +html, body +{ + width: 100%; + height: 100%; +} + +body +{ + margin: 0; + padding: 0; + background-color: #fff; + position: relative; + font: 16px/24px NobileRegular, "Lucida Grande", Lucida, Verdana, sans-serif; +} + +a +{ + color: #1b61d6; + text-decoration: none; +} + +a:hover +{ + color: #e88f00; + text-decoration: underline; +} + +body h1, body h2, body h3, body h4, body h5, body h6 +{ + font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif; + font-weight: 400; + color: #373839; + font-style: normal; +} + +#wrap +{ + min-height: 100%; +} + +#header, #footer +{ + width: 100%; + color: #fff; + height: 40px; + position: absolute; + text-align: center; + line-height: 40px; + overflow: hidden; + font-size: 12px; + vertical-align: middle; +} + +#header +{ + background: #000; + top: 0; + font-size: 14px; +} + +#footer +{ + bottom: 0; + background: #000 url(http://github.com/footerbg.png) repeat-x 0 top; + position: relative; + margin-top: -40px; + clear: both; +} + +.header, .footer +{ + width: 750px; + margin-right: auto; + margin-left: auto; +} + +.wrapper +{ + width: 100%; +} + +#top, #top-small, #bottom +{ + width: 100%; +} + +#top +{ + color: #000; + height: 230px; + background: #fff url(http://github.com/headerbg.png) repeat-x 0 top; + position: relative; +} + +#top-small +{ + color: #000; + height: 60px; + background: #fff url(http://github.com/headerbg.png) repeat-x 0 top; + position: relative; +} + +#bottom +{ + color: #222; + background-color: #fff; +} + +.top, .top-small, .middle, .bottom +{ + width: 750px; + margin-right: auto; + margin-left: auto; +} + +.top +{ + padding-top: 40px; +} + +.top-small +{ + padding-top: 10px; +} + +#middle +{ + width: 100%; + height: 170px; + background: url(http://github.com/middlebg.png) repeat-x; + border-top: 2px solid #fff; + border-bottom: 2px solid #b2b2b2; +} + +.app-welcome +{ + margin-top: 25px; +} + +.app-name +{ + color: #000; + font-weight: 700; +} + +.bottom +{ + padding-top: 50px; +} + +#left +{ + width: 350px; + float: left; + padding-right: 25px; +} + +#right +{ + width: 350px; + float: right; + padding-left: 25px; +} + +.align-left +{ + text-align: left; +} + +.align-right +{ + text-align: right; +} + +.align-center +{ + text-align: center; +} + +ul.links +{ + margin: 0; + padding: 0; +} + +ul.links li +{ + list-style-type: none; + font-size: 14px; +} + +form +{ + border-style: none; +} + +fieldset +{ + border-style: none; +} + +input +{ + color: #222; + border: 1px solid #ccc; + font-family: sans-serif; + font-size: 12px; + line-height: 16px; +} + +input[type=text], input[type=password] +{ + width: 205px; +} + +input[type=submit] +{ + background-color: #ddd; + font-weight: 700; +} + +/*Opera Fix*/ +body:before +{ + content: ""; + height: 100%; + float: left; + width: 0; + margin-top: -32767px; +} diff --git a/assignments/Project/deploy_auto/static/pyramid-small.png b/assignments/Project/deploy_auto/static/pyramid-small.png new file mode 100644 index 00000000..a5bc0ade Binary files /dev/null and b/assignments/Project/deploy_auto/static/pyramid-small.png differ diff --git a/assignments/Project/deploy_auto/static/pyramid.png b/assignments/Project/deploy_auto/static/pyramid.png new file mode 100644 index 00000000..347e0554 Binary files /dev/null and b/assignments/Project/deploy_auto/static/pyramid.png differ diff --git a/assignments/Project/deploy_auto/static/transparent.gif b/assignments/Project/deploy_auto/static/transparent.gif new file mode 100644 index 00000000..0341802e Binary files /dev/null and b/assignments/Project/deploy_auto/static/transparent.gif differ diff --git a/assignments/Project/deploy_auto/templates/base.pt b/assignments/Project/deploy_auto/templates/base.pt new file mode 100644 index 00000000..386a33a7 --- /dev/null +++ b/assignments/Project/deploy_auto/templates/base.pt @@ -0,0 +1,74 @@ + + + + ${project} + + + + + + + + + + + +
+
+
+
+ pyramid +
+
+
+
+
+

+ Welcome to the ${project} +

+
+
+
+ +
+
+
+
+ +
+ +
+ +
+ +
+
+
+ + + diff --git a/assignments/Project/deploy_auto/templates/deploy.pt b/assignments/Project/deploy_auto/templates/deploy.pt new file mode 100644 index 00000000..8ff59526 --- /dev/null +++ b/assignments/Project/deploy_auto/templates/deploy.pt @@ -0,0 +1,9 @@ + + +

Please input store specific info

+
+ +
form
+
Data successfully submitted!
+
+
diff --git a/assignments/Project/deploy_auto/templates/query.pt b/assignments/Project/deploy_auto/templates/query.pt new file mode 100644 index 00000000..63b86128 --- /dev/null +++ b/assignments/Project/deploy_auto/templates/query.pt @@ -0,0 +1,9 @@ + + +

Please input store number

+
+ +
form
+

Data successfully submitted!

+
+
diff --git a/assignments/Project/deploy_auto/views.py b/assignments/Project/deploy_auto/views.py new file mode 100644 index 00000000..b26a87de --- /dev/null +++ b/assignments/Project/deploy_auto/views.py @@ -0,0 +1,96 @@ +from pyramid.view import view_config +from .models import Deploy_Auto +from pyramid_zodbconn import get_connection +from deform import Form, ValidationFailure + +import colander + +@view_config(context=Deploy_Auto, renderer='templates/base.pt') +def my_view(request): + conn = get_connection(request) + root = conn.root() + return {'project': 'Network Deployment Automation System', 'page': root['app_root']} + +class Store(colander.MappingSchema): + store_number = colander.SchemaNode(colander.Integer()) + city = colander.SchemaNode(colander.String()) + state = colander.SchemaNode(colander.String()) + country = colander.SchemaNode(colander.String()) + region = colander.SchemaNode(colander.String()) + network = colander.SchemaNode(colander.String()) + +class Store_Number(colander.MappingSchema): + store_number = colander.SchemaNode(colander.Integer()) + +@view_config(context=Deploy_Auto, name='deploy', renderer='templates/deploy.pt') +def view_deploy(request): + conn = get_connection(request) + root = conn.root() + schema = Store() + myform = Form(schema, buttons=('submit',)) + if 'submit' in request.POST: + controls = request.POST.items() + try: + appstruct = myform.validate(controls) + except ValidationFailure, e: + return { + 'project': 'Network Deployment Automation System', + 'page': root['app_root'], + 'form': e.render(), + 'values': False, + } + values = { + 'store_number': appstruct['store_number'], + 'city': appstruct['city'], + 'state': appstruct['state'], + 'country': appstruct['country'], + 'region': appstruct['region'], + 'network': appstruct['network'] + } + return { + 'project': 'Network Deployment Automation System', + 'page': root['app_root'], + 'form': myform.render(), + 'values': values + } + + return { + 'project': 'Network Deployment Automation System', + 'page': root['app_root'], + 'form': myform.render(), + 'values': None + } + +@view_config(context=Deploy_Auto, name='query', renderer='templates/query.pt') +def view_query(request): + conn = get_connection(request) + root = conn.root() + schema = Store_Number() + myform = Form(schema, buttons=('submit',)) + if 'submit' in request.POST: + controls = request.POST.items() + try: + appstruct = myform.validate(controls) + except ValidationFailure, e: + return { + 'project': 'Network Deployment Automation System', + 'page': root['app_root'], + 'form': e.render(), + 'values': False, + } + values = { + 'store_number': appstruct['store_number'], + } + return { + 'project': 'Network Deployment Automation System', + 'page': root['app_root'], + 'form': myform.render(), + 'values': values + } + + return { + 'project': 'Network Deployment Automation System', + 'page': root['app_root'], + 'form': myform.render(), + 'values': None + } diff --git a/assignments/teachers/week02/answers/http_serve7.py b/assignments/teachers/week02/answers/http_serve7.py index ae889efc..ed2aaf60 100644 --- a/assignments/teachers/week02/answers/http_serve7.py +++ b/assignments/teachers/week02/answers/http_serve7.py @@ -1,170 +1,179 @@ -#!/usr/bin/env python - -import socket -import os - -import httpdate - -host = '' # listen on all connections (WiFi, etc) -port = 50000 -backlog = 5 # how many connections can we stack up -size = 1024 # number of bytes to receive at once - -root_dir = 'web' # must be run from code dir... - -print "point your browser to http://localhost:%i"%port - -## create the socket -s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -# set an option to tell the OS to re-use the socket -s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - -# the bind makes it a server -s.bind( (host,port) ) -s.listen(backlog) - -html = open("tiny_html.html").read() - -mime_types={} -mime_types['html'] = "text/html" -mime_types['htm'] = "text/html" -mime_types['txt'] = "text/plain" -mime_types['png'] = "image/png" -mime_types['jpeg'] = "image/jpg" -mime_types['jpg'] = "image/jpg" - -def OK_response(entity, extension='html'): - """ - returns an HTTP response: header and entity in a string - """ - resp = [] - resp.append('HTTP/1.1 200 OK') - resp.append(httpdate.httpdate_now()) - type = mime_types.get(extension, 'text/plain') - resp.append( 'Content-Type: %s'%type ) - resp.append('Content-Length: %i'%len(entity)) - resp.append('') - resp.append(entity) - - return "\r\n".join(resp) - -def Error_response(URI): - """ - returns an HTTP 404 Not Found Error response: - - URI is the name of the entity not found - """ - resp = [] - resp.append('HTTP/1.1 404 Not Found') - resp.append(httpdate.httpdate_now()) - resp.append('Content-Type: text/plain') - - msg = "404 Error:\n %s \n not found"%( URI ) - - resp.append('Content-Length: %i'%( len(msg) ) ) - resp.append('') - resp.append(msg) - - return "\r\n".join(resp) - - -def parse_request(request): - """ - parse an HTTP request - - returns the URI asked for - - note: minimal parsing -- only supprt GET - - example: - GET / HTTP/1.1 - Host: localhost:50000 - User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0 - Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 - Accept-Language: en-us,en;q=0.5 - Accept-Encoding: gzip, deflate - Connection: keep-alive - Cache-Control: max-age=0 - """ - # first line should be the method line: - lines = request.split("\r\n") - - method, URI, protocol = lines[0].split() - - # a bit of checking: - if method.strip() != "GET": - raise ValueError("I can only process a GET request") - if protocol.split('/')[0] != "HTTP": - raise ValueError("I can only process an HTTP request") - - return URI - -def format_dir_list(URI): - """ - format the contests of dir as HTML with links - """ - dir = os.path.join(root_dir, URI) - names = os.listdir(dir) - - dirs = [d for d in names if os.path.isdir(os.path.join(dir,d))] - files = [d for d in names if os.path.isfile(os.path.join(dir,d))] - - html =[] - html.append(" ") - html.append("

%s

"%URI) - print "URI:", URI - if URI: # don't need the parent dir at the root - html.append('Parent' ) - html.append("

Directories:

") - html.append(" ") - html.append("

Files:

") - html.append(" ") - html.append("
") - return "\n".join(html) - -def get_time_page(): - """ - returns and html page with the current time in it - """ - time = httpdate.httpdate_now() - html = "

%s

"%time - return html - -def get_file(URI): - - URI = URI.strip('/') #weird-- os.path.join does not like a leading slash - # check if this is the time server option - if URI.lower() == "get_time": - return get_time_page(), 'html' - else: - filename = os.path.join( root_dir, URI) - if os.path.isfile(filename): - contents = open(filename, 'rb').read() - ext = os.path.splitext(filename)[1].strip('.') - return contents, ext - elif os.path.isdir(filename): - return format_dir_list(URI), 'htm' - else: - raise ValueError("there is nothing by that name") - - -while True: # keep looking for new connections forever - client, address = s.accept() # look for a connection - request = client.recv(size) - if request: # if the connection was closed there would be no data - print "received:", request - URI = parse_request(request) - try: - file_data, ext = get_file(URI) - response = OK_response(file_data, ext) - except ValueError: - response = Error_response(URI) - client.send(response) - client.close() - +#!/usr/bin/env python + +import socket +import os +import email.utils +import time +#import httpdate + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +root_dir = 'web' # must be run from code dir... + +print "point your browser to http://localhost:%i"%port + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +#html = open("tiny_html.html").read() + +mime_types={} +mime_types['html'] = "text/html" +mime_types['htm'] = "text/html" +mime_types['txt'] = "text/plain" +mime_types['png'] = "image/png" +mime_types['jpeg'] = "image/jpg" +mime_types['jpg'] = "image/jpg" + +def httpdate(): + """Returns a date/time value in RFC1123 format""" + now = time.gmtime() + stamp = time.mktime(now) + return email.utils.formatdate(stamp, False, True) + +def OK_response(entity, extension='html'): + """ + returns an HTTP response: header and entity in a string + """ + resp = [] + resp.append('HTTP/1.1 200 OK') + resp.append(httpdate()) + type = mime_types.get(extension, 'text/plain') + resp.append( 'Content-Type: %s'%type ) + resp.append('Content-Length: %i'%len(entity)) + resp.append('') + resp.append(entity) + + return "\r\n".join(resp) + +def Error_response(URI): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + resp = [] + resp.append('HTTP/1.1 404 Not Found') + resp.append(httpdate()) + resp.append('Content-Type: text/plain') + + msg = "404 Error:\n %s \n not found"%( URI ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + + +def parse_request(request): + """ + parse an HTTP request + + returns the URI asked for + + note: minimal parsing -- only supprt GET + + example: + GET / HTTP/1.1 + Host: localhost:50000 + User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0 + Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Language: en-us,en;q=0.5 + Accept-Encoding: gzip, deflate + Connection: keep-alive + Cache-Control: max-age=0 + """ + # first line should be the method line: + lines = request.split("\r\n") + + method, URI, protocol = lines[0].split() + + # a bit of checking: + if method.strip() != "GET": + raise ValueError("I can only process a GET request") + if protocol.split('/')[0] != "HTTP": + raise ValueError("I can only process an HTTP request") + + return URI + +def format_dir_list(URI): + """ + format the contests of dir as HTML with links + """ + dir = os.path.join(root_dir, URI) + names = os.listdir(dir) + + dirs = [d for d in names if os.path.isdir(os.path.join(dir,d))] + files = [d for d in names if os.path.isfile(os.path.join(dir,d))] + + html =[] + html.append(" ") + html.append("

%s

"%URI) + print "URI:", URI + if URI: # don't need the parent dir at the root + html.append('Parent' ) + html.append("

Directories:

") + html.append(" ") + html.append("

Files:

") + html.append(" ") + html.append("
") + return "\n".join(html) + +def get_time_page(): + """ + returns and html page with the current time in it + """ + time = httpdate() + html = "

%s

"%time + return html + +def get_file(URI): + + print 'URI = ', URI + URI = URI.strip('/') #weird-- os.path.join does not like a leading slash + # check if this is the time server option + if URI.lower() == "get_time": + return get_time_page(), 'html' + else: + filename = os.path.join( root_dir, URI) + if os.path.isfile(filename): + contents = open(filename, 'rb').read() + ext = os.path.splitext(filename)[1].strip('.') + return contents, ext + elif os.path.isdir(filename): + return format_dir_list(URI), 'htm' + else: + raise ValueError("there is nothing by that name") + + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received:", request + URI = parse_request(request) + try: + file_data, ext = get_file(URI) + response = OK_response(file_data, ext) + except ValueError: + response = Error_response(URI) + print response + client.send(response) + client.close() + diff --git a/assignments/teachers/week02/answers/web/a_web_page.html b/assignments/teachers/week02/answers/web/a_web_page.html new file mode 100644 index 00000000..e7c3c777 --- /dev/null +++ b/assignments/teachers/week02/answers/web/a_web_page.html @@ -0,0 +1,11 @@ + + + + +

My First Heading

+ +

My first paragraph.

+ + + + diff --git a/assignments/teachers/week02/answers/web/images/JPEG_example.jpg b/assignments/teachers/week02/answers/web/images/JPEG_example.jpg new file mode 100644 index 00000000..13506f01 Binary files /dev/null and b/assignments/teachers/week02/answers/web/images/JPEG_example.jpg differ diff --git a/assignments/teachers/week02/answers/web/images/Sample_Scene_Balls.jpg b/assignments/teachers/week02/answers/web/images/Sample_Scene_Balls.jpg new file mode 100644 index 00000000..1c0ccade Binary files /dev/null and b/assignments/teachers/week02/answers/web/images/Sample_Scene_Balls.jpg differ diff --git a/assignments/teachers/week02/answers/web/images/sample_1.png b/assignments/teachers/week02/answers/web/images/sample_1.png new file mode 100644 index 00000000..5b2f52df Binary files /dev/null and b/assignments/teachers/week02/answers/web/images/sample_1.png differ diff --git a/assignments/teachers/week02/answers/web/make_time.py b/assignments/teachers/week02/answers/web/make_time.py new file mode 100644 index 00000000..80166cee --- /dev/null +++ b/assignments/teachers/week02/answers/web/make_time.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +""" +make_time.py + +simple script that returns and HTML page with the current time +""" + +import datetime + +time_str = datetime.datetime.now().isoformat() + +html = """ + + +

The time is:

+

%s

+ + +"""% time_str + +print html + + + diff --git a/assignments/teachers/week02/answers/web/sample.txt b/assignments/teachers/week02/answers/web/sample.txt new file mode 100644 index 00000000..1e318a76 --- /dev/null +++ b/assignments/teachers/week02/answers/web/sample.txt @@ -0,0 +1,3 @@ +This is a very simple text file. +Just to show that we can server it up. +It is three lines long. diff --git a/assignments/week01/athome/add_client.py b/assignments/week01/athome/add_client.py new file mode 100644 index 00000000..ea3bf247 --- /dev/null +++ b/assignments/week01/athome/add_client.py @@ -0,0 +1,33 @@ +#------------------------------------------------------------------------------- +# Name: add_client.py +# Purpose: +# +# Author: Allen Su +# +# Created: 10/01/2013 +# Copyright: (c) allsu 2013 +# Licence: +#------------------------------------------------------------------------------- + +import socket +import sys + +client = socket.socket() # Create a TCP/IP socket + +# Connect the socket to the port where the server is listening +server_address = ('localhost', 50000) +client.connect(server_address) + +try: + # Send data + num1 = raw_input('Please input the 1st integer number: ') + num2 = raw_input('Please input the 2nd integer number: ') + message = '%s,%s' % (num1, num2) + client.sendall(message) + + # print the response + print('%s + %s = %s') % (num1, num2, client.recv(4096)) + +finally: + # close the socket to clean up + client.close() diff --git a/assignments/week01/athome/add_server.py b/assignments/week01/athome/add_server.py new file mode 100644 index 00000000..d14117c8 --- /dev/null +++ b/assignments/week01/athome/add_server.py @@ -0,0 +1,44 @@ +#------------------------------------------------------------------------------- +# Name: add_server.py +# Purpose: +# +# Author: Allen Su +# +# Created: 10/01/2013 +# Copyright: (c) allsu 2013 +# Licence: +#------------------------------------------------------------------------------- + +import socket +import sys + +# Create a TCP/IP socket +server = socket.socket() + +# Bind the socket to the port +server_address = ('localhost', 50000) +server.bind(server_address) + +# Listen for incoming connections +server.listen(100) + +try: + + while True: + # Wait for a connection + con, addr = server.accept() + try: + # Receive the data and send it back + message = con.recv(4096) + delimiter = ',' + num = message.split(delimiter) + total = int(num[0]) + int(num[1]) + con.sendall(str(total)) + + finally: + # Clean up the connection + con.close() + +except KeyboardInterrupt: + server.close() + sys.exit() diff --git a/assignments/week01/lab/echo_client.py b/assignments/week01/lab/echo_client.py index b8898436..70707625 100644 --- a/assignments/week01/lab/echo_client.py +++ b/assignments/week01/lab/echo_client.py @@ -1,16 +1,20 @@ -import socket -import sys - -# Create a TCP/IP socket - -# Connect the socket to the port where the server is listening -server_address = ('localhost', 50000) - -try: - # Send data - message = 'This is the message. It will be repeated.' - - # print the response - -finally: - # close the socket to clean up +import socket +import sys + +client = socket.socket() # Create a TCP/IP socket + +# Connect the socket to the port where the server is listening +server_address = ('localhost', 50000) +client.connect(server_address) + +try: + # Send data + message = 'This is the message. It will be repeated.' + client.sendall(message) + + # print the response + print(client.recv(4096)) + +finally: + # close the socket to clean up + client.close() diff --git a/assignments/week01/lab/echo_server.py b/assignments/week01/lab/echo_server.py index e2c52fc6..198da36b 100644 --- a/assignments/week01/lab/echo_server.py +++ b/assignments/week01/lab/echo_server.py @@ -1,19 +1,24 @@ -import socket -import sys - -# Create a TCP/IP socket - -# Bind the socket to the port -server_address = ('localhost', 50000) - -# Listen for incoming connections - -while True: - # Wait for a connection - - try: - # Receive the data and send it back - - - finally: - # Clean up the connection +import socket +import sys + +# Create a TCP/IP socket +server = socket.socket() + +# Bind the socket to the port +server_address = ('localhost', 50000) +server.bind(server_address) + +# Listen for incoming connections +server.listen(100) + +while True: + # Wait for a connection + con, addr = server.accept() + try: + # Receive the data and send it back + message = con.recv(4096) + con.sendall(message) + + finally: + # Clean up the connection + con.close() diff --git a/assignments/week02/athome/Assignment - Allen Su.txt b/assignments/week02/athome/Assignment - Allen Su.txt new file mode 100644 index 00000000..3e4fc3a2 --- /dev/null +++ b/assignments/week02/athome/Assignment - Allen Su.txt @@ -0,0 +1,12 @@ +hi Chris, sorry for the late submission. I stunbled across several challenges that took me a long time to resolve. + +I was able to finish the labs and the assignment up to the "dynamic time-page" point, without the bonus (running it on the VM). + +However, in I ran into an issue that I can't figure out. I added another directory (web/images/test), and a file inside that directory (web/images/test/test.txt). + +the URI works fine until the test.txt file. For some reason, when I click the link on that file, the URI being passed with the request becomes /images/images/test/test.txt, +which then resulted a 404 error. + +Thanks, + +Allen Su \ No newline at end of file diff --git a/assignments/week02/athome/http_server.py b/assignments/week02/athome/http_server.py new file mode 100644 index 00000000..db7a498b --- /dev/null +++ b/assignments/week02/athome/http_server.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +import socket + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +html = open('tiny_html.html', 'r').read() + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received: " + print request + client.send(html) + client.close() diff --git a/assignments/week02/athome/http_server2.py b/assignments/week02/athome/http_server2.py new file mode 100644 index 00000000..3f23d695 --- /dev/null +++ b/assignments/week02/athome/http_server2.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python + +import socket +import email.utils +import time + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +def httpdate(): + """Returns a date/time value in RFC1123 format""" + now = time.gmtime() + stamp = time.mktime(now) + return email.utils.formatdate(stamp, False, True) + +def ok_response(data): + r = [] + r.append('HTTP/1.1 200 OK') + r.append(httpdate()) + r.append('Content Type: text/html') + r.append('Content Length: %i' % len(data)) + r.append('') + r.append(data) + + return '\r\n'.join(r) + +html = open('tiny_html.html', 'r').read() + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + response = ok_response(html) + if request: # if the connection was closed there would be no data + print "received: " + print request + print 'sending: ' + print response + client.send(response) + client.close() diff --git a/assignments/week02/athome/http_server3.py b/assignments/week02/athome/http_server3.py new file mode 100644 index 00000000..9fe6e52e --- /dev/null +++ b/assignments/week02/athome/http_server3.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python + +import socket +import email.utils +import time + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +def httpdate(): + """Returns a date/time value in RFC1123 format""" + now = time.gmtime() + stamp = time.mktime(now) + return email.utils.formatdate(stamp, False, True) + +def ok_response(data): + r = [] + r.append('HTTP/1.1 200 OK') + r.append(httpdate()) + r.append('Content Type: text/html') + r.append('Content Length: %i' % len(data)) + r.append('') + r.append(data) + + return '\r\n'.join(r) + +def client_error_response(method, protocol): + msg = '400 Error: Bad Request. Either %s or %s is not a supported request' % (method, protocol.split('/')[0]) + r = [] + r.append('HTTP/1.1 400 Bad Request') + r.append(httpdate()) + r.append('Content Type: text/html') + r.append('Content Length: %i' % len(msg)) + r.append('') + r.append(msg) + + return '\r\n'.join(r) + +def parse_request(r, h): + """Parse a request and returns a URL""" + lines = r.split('\r\n') + + method, URI, protocol = lines[0].split() + + print('URI requested is: %s') % URI + + if method != 'GET': + response = client_error_response(method, protocol) + print 'sending: ' + print response + client.send(response) + client.close() + raise ValueError('This server currently can only process GET request') + elif protocol.split('/')[0] != 'HTTP': + response = client_error_response(method, protocol) + print 'sending: ' + print response + client.send(response) + client.close() + raise ValueError('This server can only process HTTP request') + else: + return ok_response(h) + +html = open('tiny_html.html', 'r').read() + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received: " + print request + response = parse_request(request, html) + print 'sending: ' + print response + client.send(response) + client.close() diff --git a/assignments/week02/athome/http_server4.py b/assignments/week02/athome/http_server4.py new file mode 100644 index 00000000..6c9ee91c --- /dev/null +++ b/assignments/week02/athome/http_server4.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python + +import socket +import email.utils +import time +import os + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +mime_types = {} +mime_types['html'] = 'text/html' +mime_types['htm'] = 'text/html' +mime_types['txt'] = 'text/plain' +mime_types['py'] = 'text/plain' +mime_types['jpg'] = 'image/jpg' +mime_types['jpeg'] = 'image/jpg' +mime_types['png'] = 'image/png' + +def httpdate(): + """Returns a date/time value in RFC1123 format""" + now = time.gmtime() + stamp = time.mktime(now) + return email.utils.formatdate(stamp, False, True) + +def ok_response(data, extension = 'html'): + r = [] + r.append('HTTP/1.1 200 OK') + r.append(httpdate()) + type = mime_types.get(extension, 'text/plain') + r.append('Content Type: %s' % type) + r.append('Content Length: %i' % len(data)) + r.append('') + r.append(data) + + return '\r\n'.join(r) + +def client_error_response(): + msg = '400 Error: Bad Request. This is not a supported request!' + r = [] + r.append('HTTP/1.1 400 Bad Request') + r.append(httpdate()) + r.append('Content Type: text/plain') + r.append('Content Length: %i' % len(msg)) + r.append('') + r.append(msg) + + return '\r\n'.join(r) + +def notfound_response(URI): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + resp = [] + resp.append('HTTP/1.1 404 Not Found') + resp.append(httpdate()) + resp.append('Content-Type: text/plain') + + msg = "404 Error:\n %s \n not found"%( URI ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + +def format_dir_list(dir_list): + msg = ["Directory Listing:"] + for d in dir_list: + msg.append(d) + return "\n".join(msg) + +def resolve_uri(u): + """Takes the URI and analyze it and return the proper HTTP code""" + root_dir = 'web' + URI = u.lstrip('/') + filename = os.path.join(root_dir, URI) + print 'The path requested is: %s' % filename + if os.path.isfile(filename): + response = client_error_response() + '\r\nFile Access is not supported yet!' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise NotImplementedError('File Access is not supported yet!') + elif os.path.isdir(filename): + data, ext = format_dir_list(os.listdir(filename)), 'txt' + response = ok_response(data, ext) + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + else: + response = notfound_response(u) + '\r\nNo such resource exist!' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('No such resource exist!') + +def parse_request(request): + """Parse a request and analyze the method, URI, and protocol, and return the proper response to the client""" + data = open('tiny_html.html', 'r').read() + lines = request.split('\r\n') + + method, URI, protocol = lines[0].split() + + if method != 'GET': + response = client_error_response() + '\r\nThis server currently can only process GET request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server currently can only process GET request') + elif protocol.split('/')[0] != 'HTTP': + response = client_error_response() + '\r\nThis server can only process HTTP request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server can only process HTTP request') + else: + print('URI requested is: %s') % URI + resolve_uri(URI) + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received: " + print request + parse_request(request) + diff --git a/assignments/week02/athome/http_server5.py b/assignments/week02/athome/http_server5.py new file mode 100644 index 00000000..1140bfa8 --- /dev/null +++ b/assignments/week02/athome/http_server5.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python + +import socket +import email.utils +import time +import os + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +mime_types = {} +mime_types['html'] = 'text/html' +mime_types['htm'] = 'text/html' +mime_types['txt'] = 'text/plain' +mime_types['py'] = 'text/plain' +mime_types['jpg'] = 'image/jpg' +mime_types['jpeg'] = 'image/jpg' +mime_types['png'] = 'image/png' + +def httpdate(): + """Returns a date/time value in RFC1123 format""" + now = time.gmtime() + stamp = time.mktime(now) + return email.utils.formatdate(stamp, False, True) + +def ok_response(data, extension = 'html'): + r = [] + r.append('HTTP/1.1 200 OK') + r.append(httpdate()) + type = mime_types.get(extension, 'text/plain') + r.append('Content Type: %s' % type) + r.append('Content Length: %i' % len(data)) + r.append('') + r.append(data) + + return '\r\n'.join(r) + +def client_error_response(): + msg = '400 Error: Bad Request. This is not a supported request!' + r = [] + r.append('HTTP/1.1 400 Bad Request') + r.append(httpdate()) + r.append('Content Type: text/plain') + r.append('Content Length: %i' % len(msg)) + r.append('') + r.append(msg) + + return '\r\n'.join(r) + +def notfound_response(URI): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + resp = [] + resp.append('HTTP/1.1 404 Not Found') + resp.append(httpdate()) + resp.append('Content-Type: text/plain') + + msg = "404 Error:\n %s \n not found"%( URI ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + +def format_dir_list(dir_list): + msg = ["Directory Listing:"] + for d in dir_list: + msg.append(d) + return "\n".join(msg) + +def resolve_uri(u): + """Takes the URI and analyze it and return the proper HTTP code""" + root_dir = 'web' + URI = u.lstrip('/') + filename = os.path.join(root_dir, URI) + print 'The path requested is: %s' % filename + if os.path.isfile(filename): + data = open(filename, 'rb').read() + ext = os.path.splitext(filename)[1].strip('.') + response = ok_response(data, ext) + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + elif os.path.isdir(filename): + data, ext = format_dir_list(os.listdir(filename)), 'txt' + response = ok_response(data, ext) + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + else: + response = notfound_response(u) + '\r\nNo such resource exist!' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('No such resource exist!') + +def parse_request(request): + """Parse a request and analyze the method, URI, and protocol, and return the proper response to the client""" + data = open('tiny_html.html', 'r').read() + lines = request.split('\r\n') + + method, URI, protocol = lines[0].split() + + if method != 'GET': + response = client_error_response() + '\r\nThis server currently can only process GET request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server currently can only process GET request') + elif protocol.split('/')[0] != 'HTTP': + response = client_error_response() + '\r\nThis server can only process HTTP request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server can only process HTTP request') + else: + print('URI requested is: %s') % URI + resolve_uri(URI) + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received: " + print request + parse_request(request) + diff --git a/assignments/week02/athome/http_server6.py b/assignments/week02/athome/http_server6.py new file mode 100644 index 00000000..e7e09eec --- /dev/null +++ b/assignments/week02/athome/http_server6.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import socket +import email.utils +import time +import os + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +mime_types = {} +mime_types['html'] = 'text/html' +mime_types['htm'] = 'text/html' +mime_types['txt'] = 'text/plain' +mime_types['py'] = 'text/plain' +mime_types['jpg'] = 'image/jpg' +mime_types['jpeg'] = 'image/jpg' +mime_types['png'] = 'image/png' + +def httpdate(): + """Returns a date/time value in RFC1123 format""" + now = time.gmtime() + stamp = time.mktime(now) + return email.utils.formatdate(stamp, False, True) + +def ok_response(data, extension = 'html'): + r = [] + r.append('HTTP/1.1 200 OK') + r.append(httpdate()) + type = mime_types.get(extension, 'text/plain') + r.append('Content Type: %s' % type) + r.append('Content Length: %i' % len(data)) + r.append('') + r.append(data) + + return '\r\n'.join(r) + +def client_error_response(): + msg = '400 Error: Bad Request. This is not a supported request!' + r = [] + r.append('HTTP/1.1 400 Bad Request') + r.append(httpdate()) + r.append('Content Type: text/plain') + r.append('Content Length: %i' % len(msg)) + r.append('') + r.append(msg) + + return '\r\n'.join(r) + +def notfound_response(URI): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + resp = [] + resp.append('HTTP/1.1 404 Not Found') + resp.append(httpdate()) + resp.append('Content-Type: text/plain') + + msg = "404 Error:\n %s \n not found"%( URI ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + +def format_dir_list(dir_list): + """Format the Directory Listing as HTML""" + html = [' '] + html.append('

Directory Listing

') + + for d in dir_list: + html.append('

%s

' % d) + html.append(' ') + return "\n".join(html) + +def get_time_page(u): + """Return a HTML page with current time listed in GMT format""" + time = httpdate() + html = "

%s

" % time + return html + +def resolve_uri(u): + """Takes the URI and analyze it and return the proper HTTP code""" + root_dir = 'web' + URI = u.lstrip('/') + if URI.lower() == 'time-page': + response = ok_response(get_time_page(URI), 'html') + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + else: + filename = os.path.join(root_dir, URI) + print 'The path requested is: %s' % filename + if os.path.isfile(filename): + data = open(filename, 'rb').read() + ext = os.path.splitext(filename)[1].strip('.') + response = ok_response(data, ext) + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + elif os.path.isdir(filename): + data, ext = format_dir_list(os.listdir(filename)), 'htm' + response = ok_response(data, ext) + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + else: + response = notfound_response(u) + '\r\nNo such resource exist!' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('No such resource exist!') + +def parse_request(request): + """Parse a request and analyze the method, URI, and protocol, and return the proper response to the client""" + data = open('tiny_html.html', 'r').read() + lines = request.split('\r\n') + + method, URI, protocol = lines[0].split() + + if method != 'GET': + response = client_error_response() + '\r\nThis server currently can only process GET request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server currently can only process GET request') + elif protocol.split('/')[0] != 'HTTP': + response = client_error_response() + '\r\nThis server can only process HTTP request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server can only process HTTP request') + else: + print('URI requested is: %s') % URI + resolve_uri(URI) + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received: " + print request + parse_request(request) + diff --git a/assignments/week02/athome/http_server7.py b/assignments/week02/athome/http_server7.py new file mode 100644 index 00000000..9a8febff --- /dev/null +++ b/assignments/week02/athome/http_server7.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python + +import socket +import email.utils +import time +import os + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +root_dir = 'web' + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +mime_types = {} +mime_types['html'] = 'text/html' +mime_types['htm'] = 'text/html' +mime_types['txt'] = 'text/plain' +mime_types['py'] = 'text/plain' +mime_types['jpg'] = 'image/jpg' +mime_types['jpeg'] = 'image/jpg' +mime_types['png'] = 'image/png' + +def httpdate(): + """Returns a date/time value in RFC1123 format""" + now = time.gmtime() + stamp = time.mktime(now) + return email.utils.formatdate(stamp, False, True) + +def ok_response(data, extension = 'html'): + r = [] + r.append('HTTP/1.1 200 OK') + r.append(httpdate()) + type = mime_types.get(extension, 'text/plain') + r.append('Content Type: %s' % type) + r.append('Content Length: %i' % len(data)) + r.append('') + r.append(data) + + return '\r\n'.join(r) + +def client_error_response(): + msg = '400 Error: Bad Request. This is not a supported request!' + r = [] + r.append('HTTP/1.1 400 Bad Request') + r.append(httpdate()) + r.append('Content Type: text/plain') + r.append('Content Length: %i' % len(msg)) + r.append('') + r.append(msg) + + return '\r\n'.join(r) + +def notfound_response(URI): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + resp = [] + resp.append('HTTP/1.1 404 Not Found') + resp.append(httpdate()) + resp.append('Content-Type: text/plain') + + msg = "404 Error:\n %s \n not found"%( URI ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + +def format_dir_list(u): + """Format the Directory Listing as HTML with links""" + + dir = os.path.join(root_dir, u) + names = os.listdir(dir) + + dirs = [] + files = [] + + for d in names: + if os.path.isdir(os.path.join(dir, d)): + dirs.append(d) + elif os.path.isfile(os.path.join(dir, d)): + files.append(d) + + html =[] + html.append(" ") + html.append("

%s

" % u) + print "URI:", u + if u: # don't need the parent dir at the root + html.append('Parent' ) + html.append("

Directories:

") + html.append(" ") + html.append("

Files:

") + html.append(" ") + html.append(" ") + return "\n".join(html) + +def get_time_page(u): + """Return a HTML page with current time listed in GMT format""" + time = httpdate() + html = "

%s

" % time + return html + +def resolve_uri(u): + """Takes the URI and analyze it and return the proper HTTP code""" + URI = u.lstrip('/') + if URI.lower() == 'time-page': + response = ok_response(get_time_page(URI), 'html') + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + else: + filename = os.path.join(root_dir, URI) + print 'The path requested is: %s' % filename + if os.path.isfile(filename): + data = open(filename, 'rb').read() + ext = os.path.splitext(filename)[1].strip('.') + response = ok_response(data, ext) + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + elif os.path.isdir(filename): + data = format_dir_list(URI) + response = ok_response(data, 'html') + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + else: + response = notfound_response(u) + '\r\nNo such resource exist!' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('No such resource exist!') + +def parse_request(request): + """Parse a request and analyze the method, URI, and protocol, and return the proper response to the client""" + data = open('tiny_html.html', 'r').read() + lines = request.split('\r\n') + + method, URI, protocol = lines[0].split() + + if method != 'GET': + response = client_error_response() + '\r\nThis server currently can only process GET request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server currently can only process GET request') + elif protocol.split('/')[0] != 'HTTP': + response = client_error_response() + '\r\nThis server can only process HTTP request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server can only process HTTP request') + else: + print('URI requested is: %s') % URI + resolve_uri(URI) + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received: " + print request + parse_request(request) + diff --git a/assignments/week02/athome/test_client.py b/assignments/week02/athome/test_client.py new file mode 100644 index 00000000..210ec545 --- /dev/null +++ b/assignments/week02/athome/test_client.py @@ -0,0 +1,20 @@ +import socket +import sys + +client = socket.socket() # Create a TCP/IP socket + +# Connect the socket to the port where the server is listening +server_address = ('localhost', 50000) +client.connect(server_address) + +try: + # Send data + message = 'GET / FTP/1.1\r\n\r\n' + client.sendall(message) + + # print the response + print(client.recv(4096)) + +finally: + # close the socket to clean up + client.close() diff --git a/assignments/week02/athome/tiny_html.html b/assignments/week02/athome/tiny_html.html new file mode 100644 index 00000000..c5dd01dc --- /dev/null +++ b/assignments/week02/athome/tiny_html.html @@ -0,0 +1,11 @@ + + +

This is a header

+

+ and this is some regular text +

+

+ and some more +

+ + diff --git a/assignments/week02/athome/web/a_web_page.html b/assignments/week02/athome/web/a_web_page.html new file mode 100644 index 00000000..e7c3c777 --- /dev/null +++ b/assignments/week02/athome/web/a_web_page.html @@ -0,0 +1,11 @@ + + + + +

My First Heading

+ +

My first paragraph.

+ + + + diff --git a/assignments/week02/athome/web/favicon.ico b/assignments/week02/athome/web/favicon.ico new file mode 100644 index 00000000..4e8c2d61 Binary files /dev/null and b/assignments/week02/athome/web/favicon.ico differ diff --git a/assignments/week02/athome/web/images/JPEG_example.jpg b/assignments/week02/athome/web/images/JPEG_example.jpg new file mode 100644 index 00000000..13506f01 Binary files /dev/null and b/assignments/week02/athome/web/images/JPEG_example.jpg differ diff --git a/assignments/week02/athome/web/images/Sample_Scene_Balls.jpg b/assignments/week02/athome/web/images/Sample_Scene_Balls.jpg new file mode 100644 index 00000000..1c0ccade Binary files /dev/null and b/assignments/week02/athome/web/images/Sample_Scene_Balls.jpg differ diff --git a/assignments/week02/athome/web/images/sample_1.png b/assignments/week02/athome/web/images/sample_1.png new file mode 100644 index 00000000..5b2f52df Binary files /dev/null and b/assignments/week02/athome/web/images/sample_1.png differ diff --git a/assignments/week02/athome/web/images/test/test.txt b/assignments/week02/athome/web/images/test/test.txt new file mode 100644 index 00000000..46fd6b2d --- /dev/null +++ b/assignments/week02/athome/web/images/test/test.txt @@ -0,0 +1 @@ +test test 123 \ No newline at end of file diff --git a/assignments/week02/athome/web/make_time.py b/assignments/week02/athome/web/make_time.py new file mode 100644 index 00000000..80166cee --- /dev/null +++ b/assignments/week02/athome/web/make_time.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +""" +make_time.py + +simple script that returns and HTML page with the current time +""" + +import datetime + +time_str = datetime.datetime.now().isoformat() + +html = """ + + +

The time is:

+

%s

+ + +"""% time_str + +print html + + + diff --git a/assignments/week02/athome/web/sample.txt b/assignments/week02/athome/web/sample.txt new file mode 100644 index 00000000..1e318a76 --- /dev/null +++ b/assignments/week02/athome/web/sample.txt @@ -0,0 +1,3 @@ +This is a very simple text file. +Just to show that we can server it up. +It is three lines long. diff --git a/assignments/week02/lab/echo_server.py b/assignments/week02/lab/echo_server.py deleted file mode 100644 index 3eb3400f..00000000 --- a/assignments/week02/lab/echo_server.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python - -import socket - -host = '' # listen on all connections (WiFi, etc) -port = 50000 -backlog = 5 # how many connections can we stack up -size = 1024 # number of bytes to receive at once - -## create the socket -s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -# set an option to tell the OS to re-use the socket -s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - -# the bind makes it a server -s.bind( (host,port) ) -s.listen(backlog) - -while True: # keep looking for new connections forever - client, address = s.accept() # look for a connection - data = client.recv(size) - if data: # if the connection was closed there would be no data - print "received: %s, sending it back"%data - client.send(data) - client.close() \ No newline at end of file diff --git a/assignments/week02/lab/http_server.py b/assignments/week02/lab/http_server.py new file mode 100644 index 00000000..db7a498b --- /dev/null +++ b/assignments/week02/lab/http_server.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +import socket + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +html = open('tiny_html.html', 'r').read() + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received: " + print request + client.send(html) + client.close() diff --git a/assignments/week02/lab/http_server2.py b/assignments/week02/lab/http_server2.py new file mode 100644 index 00000000..3f23d695 --- /dev/null +++ b/assignments/week02/lab/http_server2.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python + +import socket +import email.utils +import time + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +def httpdate(): + """Returns a date/time value in RFC1123 format""" + now = time.gmtime() + stamp = time.mktime(now) + return email.utils.formatdate(stamp, False, True) + +def ok_response(data): + r = [] + r.append('HTTP/1.1 200 OK') + r.append(httpdate()) + r.append('Content Type: text/html') + r.append('Content Length: %i' % len(data)) + r.append('') + r.append(data) + + return '\r\n'.join(r) + +html = open('tiny_html.html', 'r').read() + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + response = ok_response(html) + if request: # if the connection was closed there would be no data + print "received: " + print request + print 'sending: ' + print response + client.send(response) + client.close() diff --git a/assignments/week02/lab/http_server3.py b/assignments/week02/lab/http_server3.py new file mode 100644 index 00000000..9fe6e52e --- /dev/null +++ b/assignments/week02/lab/http_server3.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python + +import socket +import email.utils +import time + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +def httpdate(): + """Returns a date/time value in RFC1123 format""" + now = time.gmtime() + stamp = time.mktime(now) + return email.utils.formatdate(stamp, False, True) + +def ok_response(data): + r = [] + r.append('HTTP/1.1 200 OK') + r.append(httpdate()) + r.append('Content Type: text/html') + r.append('Content Length: %i' % len(data)) + r.append('') + r.append(data) + + return '\r\n'.join(r) + +def client_error_response(method, protocol): + msg = '400 Error: Bad Request. Either %s or %s is not a supported request' % (method, protocol.split('/')[0]) + r = [] + r.append('HTTP/1.1 400 Bad Request') + r.append(httpdate()) + r.append('Content Type: text/html') + r.append('Content Length: %i' % len(msg)) + r.append('') + r.append(msg) + + return '\r\n'.join(r) + +def parse_request(r, h): + """Parse a request and returns a URL""" + lines = r.split('\r\n') + + method, URI, protocol = lines[0].split() + + print('URI requested is: %s') % URI + + if method != 'GET': + response = client_error_response(method, protocol) + print 'sending: ' + print response + client.send(response) + client.close() + raise ValueError('This server currently can only process GET request') + elif protocol.split('/')[0] != 'HTTP': + response = client_error_response(method, protocol) + print 'sending: ' + print response + client.send(response) + client.close() + raise ValueError('This server can only process HTTP request') + else: + return ok_response(h) + +html = open('tiny_html.html', 'r').read() + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received: " + print request + response = parse_request(request, html) + print 'sending: ' + print response + client.send(response) + client.close() diff --git a/assignments/week02/lab/http_server4.py b/assignments/week02/lab/http_server4.py new file mode 100644 index 00000000..6c9ee91c --- /dev/null +++ b/assignments/week02/lab/http_server4.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python + +import socket +import email.utils +import time +import os + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +mime_types = {} +mime_types['html'] = 'text/html' +mime_types['htm'] = 'text/html' +mime_types['txt'] = 'text/plain' +mime_types['py'] = 'text/plain' +mime_types['jpg'] = 'image/jpg' +mime_types['jpeg'] = 'image/jpg' +mime_types['png'] = 'image/png' + +def httpdate(): + """Returns a date/time value in RFC1123 format""" + now = time.gmtime() + stamp = time.mktime(now) + return email.utils.formatdate(stamp, False, True) + +def ok_response(data, extension = 'html'): + r = [] + r.append('HTTP/1.1 200 OK') + r.append(httpdate()) + type = mime_types.get(extension, 'text/plain') + r.append('Content Type: %s' % type) + r.append('Content Length: %i' % len(data)) + r.append('') + r.append(data) + + return '\r\n'.join(r) + +def client_error_response(): + msg = '400 Error: Bad Request. This is not a supported request!' + r = [] + r.append('HTTP/1.1 400 Bad Request') + r.append(httpdate()) + r.append('Content Type: text/plain') + r.append('Content Length: %i' % len(msg)) + r.append('') + r.append(msg) + + return '\r\n'.join(r) + +def notfound_response(URI): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + resp = [] + resp.append('HTTP/1.1 404 Not Found') + resp.append(httpdate()) + resp.append('Content-Type: text/plain') + + msg = "404 Error:\n %s \n not found"%( URI ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + +def format_dir_list(dir_list): + msg = ["Directory Listing:"] + for d in dir_list: + msg.append(d) + return "\n".join(msg) + +def resolve_uri(u): + """Takes the URI and analyze it and return the proper HTTP code""" + root_dir = 'web' + URI = u.lstrip('/') + filename = os.path.join(root_dir, URI) + print 'The path requested is: %s' % filename + if os.path.isfile(filename): + response = client_error_response() + '\r\nFile Access is not supported yet!' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise NotImplementedError('File Access is not supported yet!') + elif os.path.isdir(filename): + data, ext = format_dir_list(os.listdir(filename)), 'txt' + response = ok_response(data, ext) + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + else: + response = notfound_response(u) + '\r\nNo such resource exist!' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('No such resource exist!') + +def parse_request(request): + """Parse a request and analyze the method, URI, and protocol, and return the proper response to the client""" + data = open('tiny_html.html', 'r').read() + lines = request.split('\r\n') + + method, URI, protocol = lines[0].split() + + if method != 'GET': + response = client_error_response() + '\r\nThis server currently can only process GET request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server currently can only process GET request') + elif protocol.split('/')[0] != 'HTTP': + response = client_error_response() + '\r\nThis server can only process HTTP request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server can only process HTTP request') + else: + print('URI requested is: %s') % URI + resolve_uri(URI) + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received: " + print request + parse_request(request) + diff --git a/assignments/week02/lab/http_server5.py b/assignments/week02/lab/http_server5.py new file mode 100644 index 00000000..1140bfa8 --- /dev/null +++ b/assignments/week02/lab/http_server5.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python + +import socket +import email.utils +import time +import os + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +mime_types = {} +mime_types['html'] = 'text/html' +mime_types['htm'] = 'text/html' +mime_types['txt'] = 'text/plain' +mime_types['py'] = 'text/plain' +mime_types['jpg'] = 'image/jpg' +mime_types['jpeg'] = 'image/jpg' +mime_types['png'] = 'image/png' + +def httpdate(): + """Returns a date/time value in RFC1123 format""" + now = time.gmtime() + stamp = time.mktime(now) + return email.utils.formatdate(stamp, False, True) + +def ok_response(data, extension = 'html'): + r = [] + r.append('HTTP/1.1 200 OK') + r.append(httpdate()) + type = mime_types.get(extension, 'text/plain') + r.append('Content Type: %s' % type) + r.append('Content Length: %i' % len(data)) + r.append('') + r.append(data) + + return '\r\n'.join(r) + +def client_error_response(): + msg = '400 Error: Bad Request. This is not a supported request!' + r = [] + r.append('HTTP/1.1 400 Bad Request') + r.append(httpdate()) + r.append('Content Type: text/plain') + r.append('Content Length: %i' % len(msg)) + r.append('') + r.append(msg) + + return '\r\n'.join(r) + +def notfound_response(URI): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + resp = [] + resp.append('HTTP/1.1 404 Not Found') + resp.append(httpdate()) + resp.append('Content-Type: text/plain') + + msg = "404 Error:\n %s \n not found"%( URI ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + +def format_dir_list(dir_list): + msg = ["Directory Listing:"] + for d in dir_list: + msg.append(d) + return "\n".join(msg) + +def resolve_uri(u): + """Takes the URI and analyze it and return the proper HTTP code""" + root_dir = 'web' + URI = u.lstrip('/') + filename = os.path.join(root_dir, URI) + print 'The path requested is: %s' % filename + if os.path.isfile(filename): + data = open(filename, 'rb').read() + ext = os.path.splitext(filename)[1].strip('.') + response = ok_response(data, ext) + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + elif os.path.isdir(filename): + data, ext = format_dir_list(os.listdir(filename)), 'txt' + response = ok_response(data, ext) + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + else: + response = notfound_response(u) + '\r\nNo such resource exist!' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('No such resource exist!') + +def parse_request(request): + """Parse a request and analyze the method, URI, and protocol, and return the proper response to the client""" + data = open('tiny_html.html', 'r').read() + lines = request.split('\r\n') + + method, URI, protocol = lines[0].split() + + if method != 'GET': + response = client_error_response() + '\r\nThis server currently can only process GET request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server currently can only process GET request') + elif protocol.split('/')[0] != 'HTTP': + response = client_error_response() + '\r\nThis server can only process HTTP request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server can only process HTTP request') + else: + print('URI requested is: %s') % URI + resolve_uri(URI) + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received: " + print request + parse_request(request) + diff --git a/assignments/week02/lab/http_server6.py b/assignments/week02/lab/http_server6.py new file mode 100644 index 00000000..e7e09eec --- /dev/null +++ b/assignments/week02/lab/http_server6.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import socket +import email.utils +import time +import os + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +mime_types = {} +mime_types['html'] = 'text/html' +mime_types['htm'] = 'text/html' +mime_types['txt'] = 'text/plain' +mime_types['py'] = 'text/plain' +mime_types['jpg'] = 'image/jpg' +mime_types['jpeg'] = 'image/jpg' +mime_types['png'] = 'image/png' + +def httpdate(): + """Returns a date/time value in RFC1123 format""" + now = time.gmtime() + stamp = time.mktime(now) + return email.utils.formatdate(stamp, False, True) + +def ok_response(data, extension = 'html'): + r = [] + r.append('HTTP/1.1 200 OK') + r.append(httpdate()) + type = mime_types.get(extension, 'text/plain') + r.append('Content Type: %s' % type) + r.append('Content Length: %i' % len(data)) + r.append('') + r.append(data) + + return '\r\n'.join(r) + +def client_error_response(): + msg = '400 Error: Bad Request. This is not a supported request!' + r = [] + r.append('HTTP/1.1 400 Bad Request') + r.append(httpdate()) + r.append('Content Type: text/plain') + r.append('Content Length: %i' % len(msg)) + r.append('') + r.append(msg) + + return '\r\n'.join(r) + +def notfound_response(URI): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + resp = [] + resp.append('HTTP/1.1 404 Not Found') + resp.append(httpdate()) + resp.append('Content-Type: text/plain') + + msg = "404 Error:\n %s \n not found"%( URI ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + +def format_dir_list(dir_list): + """Format the Directory Listing as HTML""" + html = [' '] + html.append('

Directory Listing

') + + for d in dir_list: + html.append('

%s

' % d) + html.append(' ') + return "\n".join(html) + +def get_time_page(u): + """Return a HTML page with current time listed in GMT format""" + time = httpdate() + html = "

%s

" % time + return html + +def resolve_uri(u): + """Takes the URI and analyze it and return the proper HTTP code""" + root_dir = 'web' + URI = u.lstrip('/') + if URI.lower() == 'time-page': + response = ok_response(get_time_page(URI), 'html') + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + else: + filename = os.path.join(root_dir, URI) + print 'The path requested is: %s' % filename + if os.path.isfile(filename): + data = open(filename, 'rb').read() + ext = os.path.splitext(filename)[1].strip('.') + response = ok_response(data, ext) + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + elif os.path.isdir(filename): + data, ext = format_dir_list(os.listdir(filename)), 'htm' + response = ok_response(data, ext) + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + else: + response = notfound_response(u) + '\r\nNo such resource exist!' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('No such resource exist!') + +def parse_request(request): + """Parse a request and analyze the method, URI, and protocol, and return the proper response to the client""" + data = open('tiny_html.html', 'r').read() + lines = request.split('\r\n') + + method, URI, protocol = lines[0].split() + + if method != 'GET': + response = client_error_response() + '\r\nThis server currently can only process GET request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server currently can only process GET request') + elif protocol.split('/')[0] != 'HTTP': + response = client_error_response() + '\r\nThis server can only process HTTP request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server can only process HTTP request') + else: + print('URI requested is: %s') % URI + resolve_uri(URI) + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received: " + print request + parse_request(request) + diff --git a/assignments/week02/lab/http_server7.py b/assignments/week02/lab/http_server7.py new file mode 100644 index 00000000..7c816b6a --- /dev/null +++ b/assignments/week02/lab/http_server7.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python + +import socket +import email.utils +import time +import os + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +root_dir = 'web' + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +mime_types = {} +mime_types['html'] = 'text/html' +mime_types['htm'] = 'text/html' +mime_types['txt'] = 'text/plain' +mime_types['py'] = 'text/plain' +mime_types['jpg'] = 'image/jpg' +mime_types['jpeg'] = 'image/jpg' +mime_types['png'] = 'image/png' + +def httpdate(): + """Returns a date/time value in RFC1123 format""" + now = time.gmtime() + stamp = time.mktime(now) + return email.utils.formatdate(stamp, False, True) + +def ok_response(data, extension = 'html'): + r = [] + r.append('HTTP/1.1 200 OK') + r.append(httpdate()) + type = mime_types.get(extension, 'text/plain') + r.append('Content Type: %s' % type) + r.append('Content Length: %i' % len(data)) + r.append('') + r.append(data) + + return '\r\n'.join(r) + +def client_error_response(): + msg = '400 Error: Bad Request. This is not a supported request!' + r = [] + r.append('HTTP/1.1 400 Bad Request') + r.append(httpdate()) + r.append('Content Type: text/plain') + r.append('Content Length: %i' % len(msg)) + r.append('') + r.append(msg) + + return '\r\n'.join(r) + +def notfound_response(URI): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + resp = [] + resp.append('HTTP/1.1 404 Not Found') + resp.append(httpdate()) + resp.append('Content-Type: text/plain') + + msg = "404 Error:\n %s \n not found"%( URI ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + +def format_dir_list(u): + """Format the Directory Listing as HTML with links""" + + dir = os.path.join(root_dir, u) + names = os.listdir(dir) + + dirs = [] + files = [] + + for d in names: + if os.path.isdir(os.path.join(dir, d)): + dirs.append(d) + elif os.path.isfile(os.path.join(dir, d)): + files.append(d) + + html =[] + html.append(" ") + html.append("

%s

" % u) + print "URI:", u + if u: # don't need the parent dir at the root + html.append('Parent' ) + html.append("

Directories:

") + html.append(" ") + html.append("

Files:

") + html.append(" ") + html.append(" ") + return "\n".join(html) + +def get_time_page(u): + """Return a HTML page with current time listed in GMT format""" + time = httpdate() + html = "

%s

" % time + return html + +def resolve_uri(u): + """Takes the URI and analyze it and return the proper HTTP code""" + URI = u.lstrip('/') + if URI.lower() == 'time-page': + response = ok_response(get_time_page(URI), 'html') + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + else: + filename = os.path.join(root_dir, URI) + print 'The path requested is: %s' % filename + if os.path.isfile(filename): + data = open(filename, 'rb').read() + ext = os.path.splitext(filename)[1].strip('.') + response = ok_response(data, ext) + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + elif os.path.isdir(filename): + data = format_dir_list(URI) + response = ok_response(data, 'html') + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + else: + response = notfound_response(u) + '\r\nNo such resource exist!' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('No such resource exist!') + +def parse_request(request): + """Parse a request and analyze the method, URI, and protocol, and return the proper response to the client""" + data = open('tiny_html.html', 'r').read() + lines = request.split('\r\n') + + method, URI, protocol = lines[0].split() + + if method != 'GET': + response = client_error_response() + '\r\nThis server currently can only process GET request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server currently can only process GET request') + elif protocol.split('/')[0] != 'HTTP': + response = client_error_response() + '\r\nThis server can only process HTTP request' + print 'sending: ' + print response, '\r\n' + client.send(response) + client.close() + raise ValueError('This server can only process HTTP request') + else: + print('URI requested is: %s') % URI + resolve_uri(URI) + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received: " + print request + parse_request(request) + diff --git a/assignments/week02/lab/test_client.py b/assignments/week02/lab/test_client.py new file mode 100644 index 00000000..210ec545 --- /dev/null +++ b/assignments/week02/lab/test_client.py @@ -0,0 +1,20 @@ +import socket +import sys + +client = socket.socket() # Create a TCP/IP socket + +# Connect the socket to the port where the server is listening +server_address = ('localhost', 50000) +client.connect(server_address) + +try: + # Send data + message = 'GET / FTP/1.1\r\n\r\n' + client.sendall(message) + + # print the response + print(client.recv(4096)) + +finally: + # close the socket to clean up + client.close() diff --git a/assignments/week02/lab/web/favicon.ico b/assignments/week02/lab/web/favicon.ico new file mode 100644 index 00000000..4e8c2d61 Binary files /dev/null and b/assignments/week02/lab/web/favicon.ico differ diff --git a/assignments/week02/lab/web/images/test/test.txt b/assignments/week02/lab/web/images/test/test.txt new file mode 100644 index 00000000..46fd6b2d --- /dev/null +++ b/assignments/week02/lab/web/images/test/test.txt @@ -0,0 +1 @@ +test test 123 \ No newline at end of file diff --git a/assignments/week03/athome/AllenFBfriendslocation.txt b/assignments/week03/athome/AllenFBfriendslocation.txt new file mode 100644 index 00000000..4922b560 --- /dev/null +++ b/assignments/week03/athome/AllenFBfriendslocation.txt @@ -0,0 +1,1543 @@ +{ + "data": [ + { + "name": "Jack Lin", + "location": { + "id": "104022926303756", + "name": "Palo Alto, California" + }, + "id": "2420699" + }, + { + "name": "Frances Shih", + "location": { + "id": "107847249250173", + "name": "Cambridge, Cambridgeshire" + }, + "id": "4801904" + }, + { + "name": "yinhsu liu", + "id": "8842479" + }, + { + "name": "Joyce Chen", + "id": "10706346" + }, + { + "name": "Aaron Lin", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "28102698" + }, + { + "name": "Sandy Fu", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "28105475" + }, + { + "name": "Ren Lu", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "28130638" + }, + { + "name": "Gary Wang", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "502079509" + }, + { + "name": "Donald Chuang", + "location": { + "id": "110363935657673", + "name": "Dongguan, Guangdong" + }, + "id": "503969190" + }, + { + "name": "Stephen Ma", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "504285248" + }, + { + "name": "Betty Chen", + "location": { + "id": "102160693158562", + "name": "Zurich, Switzerland" + }, + "id": "504324015" + }, + { + "name": "Julia Lin", + "id": "504324532" + }, + { + "name": "Tony H. Chang", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "504372181" + }, + { + "name": "Jacqueline Chiang", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "504372497" + }, + { + "name": "William Chen", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "504404676" + }, + { + "name": "Allison Chang", + "id": "504452284" + }, + { + "name": "Marian Hsueh", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "504461371" + }, + { + "name": "Tina Yuan", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "504494630" + }, + { + "name": "Brian Tsai", + "id": "504510545" + }, + { + "name": "Roger Feria Jr.", + "location": { + "id": "111983945494775", + "name": "Calgary, Alberta" + }, + "id": "504527849" + }, + { + "name": "Scott Lin", + "id": "504649869" + }, + { + "name": "Kelly Lee", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "504714772" + }, + { + "name": "Ivan Lee", + "id": "505323843" + }, + { + "name": "Pauline Chao", + "location": { + "id": "110843418940484", + "name": "Seattle, Washington" + }, + "id": "505374173" + }, + { + "name": "James J. H. Lu", + "location": { + "id": "103808096325310", + "name": "Zhongshan" + }, + "id": "505401510" + }, + { + "name": "Christine Jen", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "505570225" + }, + { + "name": "Derrick Lee", + "id": "505593579" + }, + { + "name": "Sandy Chang", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "506268341" + }, + { + "name": "Joseph Cheng", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "506545245" + }, + { + "name": "Alice Lee", + "id": "507482447" + }, + { + "name": "Samson Yang", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "510475827" + }, + { + "name": "Ann Wu", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "511710428" + }, + { + "name": "Emy I-an Tsai", + "location": { + "id": "110922325599480", + "name": "Taichung, Taiwan" + }, + "id": "511972231" + }, + { + "name": "Paul Lin", + "id": "512213329" + }, + { + "name": "Cindy Baba", + "id": "514393738" + }, + { + "name": "Carol Yuan", + "id": "515638793" + }, + { + "name": "Steven Ku", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "516209174" + }, + { + "name": "Grace Hung", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "516639500" + }, + { + "name": "Teser Wong", + "id": "517379523" + }, + { + "name": "Zoe Lin", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "519700226" + }, + { + "name": "Cindy Li", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "520270011" + }, + { + "name": "Chester Blue", + "location": { + "id": "109351672416286", + "name": "Puyallup, Washington" + }, + "id": "521111683" + }, + { + "name": "Michael Chen", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "521675376" + }, + { + "name": "Josie Hu", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "525087493" + }, + { + "name": "Eric Liang", + "id": "525300650" + }, + { + "name": "Eric Chu", + "location": { + "id": "113317605345751", + "name": "Hong Kong" + }, + "id": "525327300" + }, + { + "name": "David Han", + "location": { + "id": "191419727553758", + "name": "Kunshan" + }, + "id": "528807955" + }, + { + "name": "Sarah Wu", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "528893092" + }, + { + "name": "Mike Chuang", + "id": "530531430" + }, + { + "name": "Connie Wu", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "537718229" + }, + { + "name": "Louie Wang", + "location": { + "id": "103769672995729", + "name": "Diamond Bar, California" + }, + "id": "538281083" + }, + { + "name": "Ada Edwards", + "location": { + "id": "107991659233606", + "name": "Atlanta, Georgia" + }, + "id": "540175019" + }, + { + "name": "Melody Su", + "location": { + "id": "110843418940484", + "name": "Seattle, Washington" + }, + "id": "542645350" + }, + { + "name": "William CY Tsai", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "542825452" + }, + { + "name": "Marty Chou", + "id": "542905139" + }, + { + "name": "Ron Hou", + "id": "543706245" + }, + { + "name": "Phil Lai", + "location": { + "id": "106324046073002", + "name": "Shanghai, China" + }, + "id": "543915135" + }, + { + "name": "Ann Lee", + "id": "544377050" + }, + { + "name": "Angela Cheng", + "id": "548325382" + }, + { + "name": "Mikiko Yang", + "location": { + "id": "111948542155151", + "name": "San Jose, California" + }, + "id": "548708306" + }, + { + "name": "Liang-Hsin Sung", + "location": { + "id": "115217241824342", + "name": "Hsinchu, Taiwan" + }, + "id": "552253687" + }, + { + "name": "Tom Tseng", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "555692418" + }, + { + "name": "Joyce Huang", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "556530246" + }, + { + "name": "Steven Chen", + "id": "556735013" + }, + { + "name": "Tabitha Tsai", + "id": "559380092" + }, + { + "name": "Tzu.Ching Usa", + "id": "559396256" + }, + { + "name": "Morris Lin", + "id": "562436657" + }, + { + "name": "Eric Pan", + "location": { + "id": "114987875182625", + "name": "Pingtung" + }, + "id": "564490263" + }, + { + "name": "Virgil Yao-Feng Huang", + "id": "568432710" + }, + { + "name": "Jacklin Liu", + "location": { + "id": "114511591898165", + "name": "Kaohsiung, Taiwan" + }, + "id": "569501990" + }, + { + "name": "Tom Lin", + "location": { + "id": "114497808567786", + "name": "Vancouver, British Columbia" + }, + "id": "569645565" + }, + { + "name": "Ho-Lin Hsu", + "location": { + "id": "109972075699000", + "name": "Tainan, Taiwan" + }, + "id": "570886069" + }, + { + "name": "Cathy Liu", + "id": "573275350" + }, + { + "name": "Jimmy Lin", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "574049701" + }, + { + "name": "Ted Lin", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "575642400" + }, + { + "name": "Eric Tam", + "id": "575756182" + }, + { + "name": "Betty Chiang", + "id": "579598148" + }, + { + "name": "Derek Yeh", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "580842774" + }, + { + "name": "Sonia Ho", + "id": "584451139" + }, + { + "name": "I-Ming Chen", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "587337412" + }, + { + "name": "Mike Wang", + "location": { + "id": "112763262068685", + "name": "Waterloo, Ontario" + }, + "id": "589165719" + }, + { + "name": "Jennifer Soong", + "location": { + "id": "114497808567786", + "name": "Vancouver, British Columbia" + }, + "id": "589470429" + }, + { + "name": "Nelly Tsai", + "id": "589850225" + }, + { + "name": "Hua Liu", + "location": { + "id": "109394152420685", + "name": "Chino Hills, California" + }, + "id": "590040334" + }, + { + "name": "Linda Wang", + "id": "592586475" + }, + { + "name": "Drew Liaw", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "598480343" + }, + { + "name": "Johnson Huang", + "id": "601474143" + }, + { + "name": "Lance Wei", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "603275157" + }, + { + "name": "Ming Huang", + "id": "604620301" + }, + { + "name": "Sam Wang", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "604805673" + }, + { + "name": "Monica Lai", + "location": { + "id": "109351672416286", + "name": "Puyallup, Washington" + }, + "id": "605813453" + }, + { + "name": "Hui-Ting Cindy Wang", + "location": { + "id": "110843418940484", + "name": "Seattle, Washington" + }, + "id": "606370324" + }, + { + "name": "Sandy Liao", + "location": { + "id": "112204368792315", + "name": "Irvine, California" + }, + "id": "611976349" + }, + { + "name": "Jim Chiang", + "location": { + "id": "106262189412553", + "name": "Mississauga, Ontario" + }, + "id": "613523300" + }, + { + "name": "Tracy Shih", + "id": "613701946" + }, + { + "name": "Shirley Tseng", + "location": { + "id": "110585945628334", + "name": "Bangkok, Thailand" + }, + "id": "614600582" + }, + { + "name": "Fanny M. H. Lin", + "id": "614856055" + }, + { + "name": "Cathy Chen", + "location": { + "id": "110922325599480", + "name": "Taichung, Taiwan" + }, + "id": "617040890" + }, + { + "name": "Vivian Yl Yeh", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "618200751" + }, + { + "name": "Lotus Su", + "location": { + "id": "108707615821090", + "name": "Tacoma, Washington" + }, + "id": "620845113" + }, + { + "name": "Evan Kuo", + "id": "621369521" + }, + { + "name": "Jack Shih", + "location": { + "id": "102184499823699", + "name": "Montreal, Quebec" + }, + "id": "624266069" + }, + { + "name": "Piko Choi", + "location": { + "id": "113317605345751", + "name": "Hong Kong" + }, + "id": "629652554" + }, + { + "name": "Heather Yang", + "location": { + "id": "111948542155151", + "name": "San Jose, California" + }, + "id": "631685378" + }, + { + "name": "Nickie Chang", + "id": "636225631" + }, + { + "name": "Fennie Lee", + "location": { + "id": "112204368792315", + "name": "Irvine, California" + }, + "id": "637477988" + }, + { + "name": "Sandy Su", + "id": "640635507" + }, + { + "name": "William Lee", + "location": { + "id": "104044692966512", + "name": "Richmond Hill, Ontario" + }, + "id": "641575205" + }, + { + "name": "Julia Yeh", + "id": "642448600" + }, + { + "name": "Tracy Chen", + "id": "644305525" + }, + { + "name": "Danny Yang", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "648452138" + }, + { + "name": "Vickie Wang", + "id": "651764896" + }, + { + "name": "Evelyn Lee", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "654845702" + }, + { + "name": "Peter Huang", + "location": { + "id": "109972075699000", + "name": "Tainan, Taiwan" + }, + "id": "663595119" + }, + { + "name": "Marissa Feria", + "location": { + "id": "111983945494775", + "name": "Calgary, Alberta" + }, + "id": "666155960" + }, + { + "name": "Tom Huang", + "location": { + "id": "106033362761104", + "name": "Campbell, California" + }, + "id": "668371202" + }, + { + "name": "Rob Lu", + "id": "668475102" + }, + { + "name": "Joanna Yuan", + "id": "671365759" + }, + { + "name": "Darren Ho", + "id": "680570288" + }, + { + "name": "Andy Wang", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "686211946" + }, + { + "name": "Hy Hy", + "id": "688546194" + }, + { + "name": "Caroline Wei-Ling Yeh", + "id": "689721215" + }, + { + "name": "Ken Chuang", + "location": { + "id": "111957218824045", + "name": "Putian, Fujian" + }, + "id": "694577984" + }, + { + "name": "Elaine Lu", + "location": { + "id": "109738839051539", + "name": "Redmond, Washington" + }, + "id": "697661415" + }, + { + "name": "Swetal Patel", + "location": { + "id": "107991659233606", + "name": "Atlanta, Georgia" + }, + "id": "699032413" + }, + { + "name": "Eyleen Chen", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "701492743" + }, + { + "name": "Sean Yang", + "location": { + "id": "110714572282163", + "name": "San Diego, California" + }, + "id": "702816132" + }, + { + "name": "Helen Pan", + "location": { + "id": "108089905886149", + "name": "Fremont, California" + }, + "id": "703186998" + }, + { + "name": "Kevin Chou", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "703561113" + }, + { + "name": "Jenny Goldberg-George", + "id": "705649892" + }, + { + "name": "Wawabear Wa", + "location": { + "id": "114497808567786", + "name": "Vancouver, British Columbia" + }, + "id": "709691416" + }, + { + "name": "Albert Lee", + "location": { + "id": "108089905886149", + "name": "Fremont, California" + }, + "id": "713201963" + }, + { + "name": "Mandy Huang", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "723562298" + }, + { + "name": "Royce Lin", + "id": "725510514" + }, + { + "name": "Anny Ma", + "id": "728823012" + }, + { + "name": "George Chang", + "location": { + "id": "105923529439049", + "name": "Issaquah, Washington" + }, + "id": "732847358" + }, + { + "name": "Frank Chung", + "location": { + "id": "112009122149445", + "name": "Taipei" + }, + "id": "733470010" + }, + { + "name": "Jack C.H. Tseng", + "id": "735890459" + }, + { + "name": "Ting-Yuan Liu", + "location": { + "id": "110843418940484", + "name": "Seattle, Washington" + }, + "id": "735942593" + }, + { + "name": "Jack Yuan", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "738370021" + }, + { + "name": "Rose Lo", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "743460590" + }, + { + "name": "Leon Yen", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "743624321" + }, + { + "name": "Oliver Hsu", + "location": { + "id": "112202378796934", + "name": "Richmond, British Columbia" + }, + "id": "750338871" + }, + { + "name": "Eric Chou", + "location": { + "id": "105923529439049", + "name": "Issaquah, Washington" + }, + "id": "754368358" + }, + { + "name": "Alan Tu", + "location": { + "id": "114987875182625", + "name": "Pingtung" + }, + "id": "763880721" + }, + { + "name": "Chun-Tse Chien", + "id": "765789748" + }, + { + "name": "Eric Lin", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "770370622" + }, + { + "name": "Rob Yang", + "location": { + "id": "108659242498155", + "name": "Chicago, Illinois" + }, + "id": "770755709" + }, + { + "name": "Jackie Su", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "771620087" + }, + { + "name": "Stephanie Lin", + "id": "771800116" + }, + { + "name": "Vincent Teng", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "772895607" + }, + { + "name": "Agnes Hwang", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "773075382" + }, + { + "name": "Rudy Huang", + "location": { + "id": "110843418940484", + "name": "Seattle, Washington" + }, + "id": "777204026" + }, + { + "name": "Liann Chia-Hsi Lin", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "779491254" + }, + { + "name": "Michael Mei", + "location": { + "id": "109738839051539", + "name": "Redmond, Washington" + }, + "id": "786950122" + }, + { + "name": "Gary Yen", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "788800082" + }, + { + "name": "Andy Chen", + "location": { + "id": "115976748413086", + "name": "Edmonton, Alberta" + }, + "id": "804034227" + }, + { + "name": "Albert Tzu-Pin Lin", + "location": { + "id": "110843418940484", + "name": "Seattle, Washington" + }, + "id": "806005356" + }, + { + "name": "Michael Lee", + "location": { + "id": "106031246101831", + "name": "Kuala Lumpur, Malaysia" + }, + "id": "809910400" + }, + { + "name": "Marku Hsieh", + "location": { + "id": "110363935657673", + "name": "Dongguan, Guangdong" + }, + "id": "815678760" + }, + { + "name": "Robin Lee", + "location": { + "id": "115217241824342", + "name": "Hsinchu, Taiwan" + }, + "id": "820029605" + }, + { + "name": "Dorian Tung", + "location": { + "id": "114497808567786", + "name": "Vancouver, British Columbia" + }, + "id": "827845467" + }, + { + "name": "Christine Tu", + "location": { + "id": "112438218775062", + "name": "Baltimore, Maryland" + }, + "id": "844780710" + }, + { + "name": "Christine Ho", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "854110550" + }, + { + "name": "Jojo Ho", + "id": "858775723" + }, + { + "name": "Lisa Teng", + "id": "862710174" + }, + { + "name": "Angel Chuang", + "location": { + "id": "112204368792315", + "name": "Irvine, California" + }, + "id": "873995626" + }, + { + "name": "Amber I-Chun Chen", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "877855693" + }, + { + "name": "Tina Huang", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "899215556" + }, + { + "name": "Steve Cheng", + "id": "1012984653" + }, + { + "name": "Ken Fujiwara", + "id": "1014255768" + }, + { + "name": "David Lin", + "location": { + "id": "111723635511834", + "name": "Bellevue, Washington" + }, + "id": "1051114718" + }, + { + "name": "Judy Tsing-Lin", + "location": { + "id": "111723635511834", + "name": "Bellevue, Washington" + }, + "id": "1057954727" + }, + { + "name": "Meihsiu Chen", + "location": { + "id": "105923529439049", + "name": "Issaquah, Washington" + }, + "id": "1061034331" + }, + { + "name": "Sophie Yang", + "id": "1077849295" + }, + { + "name": "Cameron Liu", + "id": "1113026343" + }, + { + "name": "Larry Ho", + "id": "1125631939" + }, + { + "name": "Amie Callaway", + "location": { + "id": "110843418940484", + "name": "Seattle, Washington" + }, + "id": "1131738361" + }, + { + "name": "Kevin Lee", + "location": { + "id": "110922325599480", + "name": "Taichung, Taiwan" + }, + "id": "1143883392" + }, + { + "name": "Arvin Wu", + "id": "1172648067" + }, + { + "name": "Eris Lin", + "id": "1199915253" + }, + { + "name": "Henry Rowshan", + "location": { + "id": "111723635511834", + "name": "Bellevue, Washington" + }, + "id": "1267870492" + }, + { + "name": "Mauricio Flores", + "id": "1268205154" + }, + { + "name": "Jason Carnevale", + "id": "1309397504" + }, + { + "name": "STella O'lla C", + "id": "1313413083" + }, + { + "name": "Rex Lin", + "id": "1337303844" + }, + { + "name": "King Wang", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "1356648346" + }, + { + "name": "Annie Liang", + "id": "1388816436" + }, + { + "name": "Charlie Chiang", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "1400028831" + }, + { + "name": "Jim Su", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "1468617326" + }, + { + "name": "Momo Yen", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "1469560791" + }, + { + "name": "Christy Liang", + "location": { + "id": "109972075699000", + "name": "Tainan, Taiwan" + }, + "id": "1473487311" + }, + { + "name": "Martha Carnevale", + "id": "1511114071" + }, + { + "name": "Greg Hedgpeth", + "id": "1524429743" + }, + { + "name": "Weili Chiang", + "id": "1527283417" + }, + { + "name": "Lydia Lin", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "1531927861" + }, + { + "name": "Ruibiao Qiu", + "location": { + "id": "110843418940484", + "name": "Seattle, Washington" + }, + "id": "1558440130" + }, + { + "name": "Justin Callaway", + "location": { + "id": "110843418940484", + "name": "Seattle, Washington" + }, + "id": "1626337429" + }, + { + "name": "Ingrid Lo", + "id": "1649801992" + }, + { + "name": "Thomas Wu", + "location": { + "id": "108089905886149", + "name": "Fremont, California" + }, + "id": "1661436495" + }, + { + "name": "Paggie Eh", + "id": "1677757550" + }, + { + "name": "Ingrid Chen", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "1721100821" + }, + { + "name": "RenHuei Jap", + "location": { + "id": "101883206519751", + "name": "Singapore, Singapore" + }, + "id": "1721692440" + }, + { + "name": "Phoebe Chen", + "location": { + "id": "102173726491792", + "name": "Jakarta, Indonesia" + }, + "id": "100000027288628" + }, + { + "name": "Katherine Shen", + "id": "100000137814224" + }, + { + "name": "Jenny Lee", + "id": "100000245978544" + }, + { + "name": "Natalie Hung", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "100000273235557" + }, + { + "name": "Ching Yu Lin", + "location": { + "id": "110843418940484", + "name": "Seattle, Washington" + }, + "id": "100000290200527" + }, + { + "name": "Melody Huang", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "100000297879729" + }, + { + "name": "Queeniie Lin", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "100000316660768" + }, + { + "name": "Leanna Pai", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "100000360895890" + }, + { + "name": "Alice Lee", + "id": "100000424098578" + }, + { + "name": "Annie Su", + "location": { + "id": "108167739211442", + "name": "Gaithersburg, Maryland" + }, + "id": "100000448823951" + }, + { + "name": "Janice Wu", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "100000471954347" + }, + { + "name": "Ann Wu", + "location": { + "id": "114511591898165", + "name": "Kaohsiung, Taiwan" + }, + "id": "100000568431671" + }, + { + "name": "Snow Su", + "location": { + "id": "112501762094262", + "name": "North Potomac, Maryland" + }, + "id": "100000708595497" + }, + { + "name": "Amy Twinsmom", + "location": { + "id": "105923529439049", + "name": "Issaquah, Washington" + }, + "id": "100000724332700" + }, + { + "name": "Lily Tai", + "id": "100000763203733" + }, + { + "name": "William Lo", + "id": "100000826502483" + }, + { + "name": "Lucy Irving Shiao", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "100000898962726" + }, + { + "name": "Su Yih Shen Su", + "id": "100000978090722" + }, + { + "name": "Tinnwaie Chang", + "location": { + "id": "110765362279102", + "name": "Taipei, Taiwan" + }, + "id": "100001134796916" + }, + { + "name": "Min-Min Wong", + "location": { + "id": "111723635511834", + "name": "Bellevue, Washington" + }, + "id": "100001190041040" + }, + { + "name": "Michael Chen", + "id": "100001247314814" + }, + { + "name": "Vera Chi", + "id": "100001414367653" + }, + { + "name": "Sally Chuang", + "id": "100001642801206" + }, + { + "name": "Peter Lin", + "location": { + "id": "110941395597405", + "name": "Toronto, Ontario" + }, + "id": "100001928605065" + }, + { + "name": "Yu-Shiou Kao", + "id": "100002190771148" + }, + { + "name": "Yi-Pin Chen", + "location": { + "id": "114497808567786", + "name": "Vancouver, British Columbia" + }, + "id": "100002380398139" + }, + { + "name": "Fandy Tsai", + "id": "100002443206000" + }, + { + "name": "Oni Hu", + "id": "100002632837670" + }, + { + "name": "Emmy Ke", + "location": { + "id": "114511591898165", + "name": "Kaohsiung, Taiwan" + }, + "id": "100002759599890" + }, + { + "name": "Michael Lin", + "id": "100002853262651" + }, + { + "name": "Doreen Kuan", + "id": "100004392883063" + } + ], + "paging": { + "next": "https://graph.facebook.com/773995092/friends?fields=name,location&limit=5000&offset=5000&__after_id=100004392883063" + } +} \ No newline at end of file diff --git a/assignments/week03/athome/Week03 Assignment - Allen Su.py b/assignments/week03/athome/Week03 Assignment - Allen Su.py new file mode 100644 index 00000000..7fb5166b --- /dev/null +++ b/assignments/week03/athome/Week03 Assignment - Allen Su.py @@ -0,0 +1,73 @@ +# 1. Use Facebook Graph API to get name and location of friends +# 2. Parse the data obtained from Facebook Graph API and scrub it to the desired format +# 3. Plug the locations of my friends on Google Map using Google static map API + +import json, urllib2, pprint, webbrowser + +def get_mapping(url): + """Get the rank of the name from names.whitepages.com""" + page = urllib2.urlopen(url) + html = page.read() + parsed = BeautifulSoup(html) + entry = parsed.find('table', class_='rank inline_block') + rank = entry.attrs['title'].split()[3][:-2] + return rank + +def scrub_data(f_dic_u): + """Scrub the unicode dictionary passed in and returned a dictionary normalized sorted in different ways""" + new_dic = dict() + for element in f_dic_u['data']: + if 'location' in element: + loc = element['location']['name'].encode('ascii','ignore') + name = element['name'].encode('ascii','ignore') + + # Dictionary with name as the key and location as the value + #new_dic[name] = loc + + # Inverse dictionary with location as the key and a list of names as value + #if loc not in new_dic: + # new_dic[loc] = [name] + #else: + # new_dic[loc].append(name) + + # Inverse dictionary with location as the key and a number of count of names as value + if loc not in new_dic: + new_dic[loc] = 1 + else: + new_dic[loc] += 1 + + return new_dic + + # Return only the top 3 locations + #top3_loc = dict() + #for key in new_dic: + # if new_dic[key] >= 10: + # top3_loc[key] = new_dic[key] + + #return top3_loc + +def parse_data(file): + f = open(file, 'r') + f_dic = json.loads(f.read()) + f.close() + return f_dic + +def print_map(f_dic): + new = 2 + url_1 = 'http://maps.googleapis.com/maps/api/staticmap?center=honolulu,hawaii,hi&zoom=2&size=640x640&scale=2&markers=color:green' + for key in f_dic: + loc, num = key, f_dic[key] + url_1 += '|%s' % loc + + url_final = url_1 + '&sensor=false' + print url_final + webbrowser.open(url_final,new=new) + +def main(): + fb_dic_u = parse_data('AllenFBfriendslocation.txt') + fb_dic = scrub_data(fb_dic_u) + pprint.pprint(fb_dic) + print_map(fb_dic) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/assignments/week03/athome/Week03 Assignment - Allen Su.txt b/assignments/week03/athome/Week03 Assignment - Allen Su.txt new file mode 100644 index 00000000..61e684ef --- /dev/null +++ b/assignments/week03/athome/Week03 Assignment - Allen Su.txt @@ -0,0 +1,3 @@ +# 1. Use Facebook Graph API to get name and location of friends +# 2. Parse the data obtained from Facebook Graph API and scrub it to the desired format +# 3. Plug the locations of my friends on Google Map using Google static map API \ No newline at end of file diff --git a/assignments/week04/athome/week04assignmentallensu.py b/assignments/week04/athome/week04assignmentallensu.py new file mode 100644 index 00000000..1d006927 --- /dev/null +++ b/assignments/week04/athome/week04assignmentallensu.py @@ -0,0 +1,89 @@ +#!/usr/bin/python + +from cgi import parse_qs, escape +import re, bookdb + +database = bookdb.database #This is a local file + +def index(environ, start_response): + """This function will be mounted on "/" and display a link + to the hello world page""" + body = "" + for i in database: + url = "books?isbn=" + database[i]['isbn'] + title = database[i]['title'] + body += ' %s
' % (url,title) + start_response('200 OK', [('Content-Type', 'text/html')]) + return ["

Python Books

" + body] + + +def books(environ, start_response): + parameters = parse_qs(environ.get('QUERY_STRING', '')) + isbn = parameters['isbn'][0] + print isbn + for i in database: + if isbn == database[i]['isbn']: + title = database[i]['title'] + publisher = database[i]['publisher'] + author = database[i]['author'] + start_response('200 OK', [('Content-Type', 'text/html')]) + return ['''Title %s
+ Author %s
+ Publisher %s
+ ISBN %s''' % (title, author, publisher, isbn)] + +def hello(environ, start_response): + """Like the example above, but it uses teh name spacified in + URL.""" + # get teh name from teh URL if it was specified there + args = environ['myapp.url_args'] + if args: + subject = escape(args[0]) + else: + subject = 'World' + start_response('200 OK', [('Content-Type', 'text/html')]) + return ['''Hello %(subject)s + Hello %(subject)s! + ''' % {'subject': subject}] + +def not_found(environ, start_response): + """Called if no URL matches.""" + start_response('404 NOT FOUND', [('Content-Type', 'text/plain')]) + return ['NOT FOUND'] + +# map urls to functions +urls = [ + (r'^$', index), + (r'hello/?$', hello), + (r'hello/(.+)$', hello), + (r'books/?$', books) + ] + +def application(environ, start_response): + """ + The main WSGI application. Dispatch the current request to + the function from above and store teh regular expression + captures in the WSGI environment as `myapp.url_args` so that + the functions from above can access the url placeholders. + + If nothing matches call the 'not_found' function. + """ +# print environ + path = environ.get('PATH_INFO', '').lstrip('/') + for regex, callback in urls: + match = re.search(regex, path) + if match is not None: + """ + print "*" * 10 + print environ + print "*" * 10 + """ + environ['myapp.url_args'] = match.groups() + return callback(environ, start_response) + return not_found(environ, start_response) + + +if __name__ == '__main__': + from wsgiref.simple_server import make_server + srv = make_server('', 8080, application) + srv.serve_forever() \ No newline at end of file diff --git a/assignments/week04/lab/src/lab2_wsgi.py b/assignments/week04/lab/src/lab2_wsgi.py new file mode 100644 index 00000000..ace92076 --- /dev/null +++ b/assignments/week04/lab/src/lab2_wsgi.py @@ -0,0 +1,47 @@ +#!/usr/bin/python +import datetime + +body = """ + +Lab A - CGI experiments + + + +The server name is %s. (if an IP address, then a DNS problem)
+
+The server address is %s:%s.
+
+You are coming from %s:%s.
+
+The URI we are serving is %s.
+
+The request arrived at %s
+ + +""" + +def application(environ, start_response): + + print start_response + response_body = body % ( + environ.get('SERVER_NAME', 'Unset'), # server name + environ.get('SERVER_ADDR', 'Unset'), # server IP + environ.get('SERVER_PORT', 'Unset'), # server port + environ.get('REMOTE_ADDR', 'Unset'), # client IP + environ.get('REMOTE_PORT', 'Unset'), # client port + environ.get('SCRIPT_NAME', 'Unset'), # this script name + datetime.datetime.now().isoformat(), # time + ) + status = '200 OK' + + response_headers = [('Content-Type', 'text/html'), + ('Content-Length', str(len(response_body)))] + a = start_response(status, response_headers) + print a + + return [response_body] + +if __name__ == '__main__': + from wsgiref.simple_server import make_server + srv = make_server('localhost', 8080, application) + srv.serve_forever() diff --git a/assignments/week05/athome/flaskr.py b/assignments/week05/athome/flaskr.py new file mode 100644 index 00000000..ae3cc873 --- /dev/null +++ b/assignments/week05/athome/flaskr.py @@ -0,0 +1,108 @@ +import sqlite3 +from contextlib import closing + +from flask import Flask +from flask import g +from flask import render_template +from flask import session +from flask import request +from flask import redirect +from flask import flash +from flask import url_for +from flask import abort + +# configuration goes here +DATABASE = '/tmp/flaskr.db' +SECRET_KEY = 'development key' +USERNAME = 'admin' +PASSWORD = 'default' + +app = Flask(__name__) +app.config.from_object(__name__) + + +def connect_db(): + return sqlite3.connect(app.config['DATABASE']) + + +def init_db(): + with closing(connect_db()) as db: + with app.open_resource('schema.sql') as f: + db.cursor().executescript(f.read()) + db.commit() + + +@app.before_request +def before_request(): + g.db = connect_db() + + +@app.teardown_request +def teardown_request(exception): + g.db.close() + + +def write_entry(title, text): + g.db.execute('insert into entries (title, text) values (?, ?)', + [title, text]) + g.db.commit() + + +def get_all_entries(): + cur = g.db.execute('select title, text from entries order by id desc') + entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()] + return entries + + +@app.route('/') +def show_entries(): + entries = get_all_entries() + return render_template('show_entries.html', entries=entries) + + +def do_login(usr, pwd): + if usr != app.config['USERNAME']: + raise ValueError + elif pwd != app.config['PASSWORD']: + raise ValueError + else: + session['logged_in'] = True + + +@app.route('/login', methods=['GET', 'POST']) +def login(): + error = None + if request.method == 'POST': + try: + do_login(request.form['username'], + request.form['password']) + except ValueError: + error = "Invalid Login" + else: + flash('You were logged in') + return redirect(url_for('show_entries')) + return render_template('login.html', error=error) + + +@app.route('/logout') +def logout(): + session.pop('logged_in', None) + flash('You were logged out') + return redirect(url_for('show_entries')) + + +@app.route('/add', methods=['POST']) +def add_entry(): + if not session.get('logged_in'): + abort(401) + try: + write_entry(request.form['title'], request.form['text']) + flash('New entry was successfully posted') + except sqlite3.Error as e: + flash('There was an error: %s' % e.args[0]) + return redirect(url_for('show_entries')) + + +if __name__ == '__main__': + app.run(debug=True) + app.run(host = '0.0.0.0') diff --git a/assignments/week05/athome/flaskr_tests.py b/assignments/week05/athome/flaskr_tests.py new file mode 100644 index 00000000..e704c6dd --- /dev/null +++ b/assignments/week05/athome/flaskr_tests.py @@ -0,0 +1,115 @@ +import os +import flaskr +import unittest +import tempfile +from flask import session + + +class FlaskrTestCase(unittest.TestCase): + + def setUp(self): + self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp() + flaskr.app.config['TESTING'] = True + self.client = flaskr.app.test_client() + self.app = flaskr.app + flaskr.init_db() + + def tearDown(self): + os.close(self.db_fd) + os.unlink(flaskr.app.config['DATABASE']) + + def test_database_setup(self): + con = flaskr.connect_db() + cur = con.execute('PRAGMA table_info(entries);') + rows = cur.fetchall() + self.assertEqual(len(rows), 3) + + def test_write_entry(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + con = flaskr.connect_db() + cur = con.execute("select * from entries;") + rows = cur.fetchall() + self.assertEquals(len(rows), 1) + for val in expected: + self.assertTrue(val in rows[0]) + + + def test_get_all_entries_empty(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + entries = flaskr.get_all_entries() + self.assertEquals(len(entries), 0) + + + def test_get_all_entries(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + entries = flaskr.get_all_entries() + self.assertEquals(len(entries), 1) + for entry in entries: + self.assertEquals(expected[0], entry['title']) + self.assertEquals(expected[1], entry['text']) + + def test_empty_listing(self): + rv = self.client.get('/') + assert 'No entries here so far' in rv.data + + def test_listing(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + rv = self.client.get('/') + for value in expected: + assert value in rv.data + + def test_login_passes(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.do_login(flaskr.app.config['USERNAME'], + flaskr.app.config['PASSWORD']) + self.assertTrue(session.get('logged_in', False)) + + def test_login_fails(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + self.assertRaises(ValueError, flaskr.do_login, + flaskr.app.config['USERNAME'], + 'incorrectpassword') + def login(self, username, password): + return self.client.post('/login', data=dict( + username=username, + password=password + ), follow_redirects=True) + + def logout(self): + return self.client.get('/logout', follow_redirects=True) + + def test_login_logout(self): + rv = self.login('admin', 'default') + assert 'You were logged in' in rv.data + rv = self.logout() + assert 'You were logged out' in rv.data + rv = self.login('adminx', 'default') + assert 'Invalid Login' in rv.data + rv = self.login('admin', 'defaultx') + assert 'Invalid Login' in rv.data + + def test_add_entries(self): + self.login('admin', 'default') + rv = self.client.post('/add', data=dict( + title='Hello', + text='This is a post' + ), follow_redirects=True) + assert 'No entries here so far' not in rv.data + assert 'Hello' in rv.data + assert 'This is a post' in rv.data + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/assignments/week05/athome/schema.sql b/assignments/week05/athome/schema.sql new file mode 100644 index 00000000..71fe0588 --- /dev/null +++ b/assignments/week05/athome/schema.sql @@ -0,0 +1,6 @@ +drop table if exists entries; +create table entries ( + id integer primary key autoincrement, + title string not null, + text string not null +); diff --git a/assignments/week05/athome/static/style.css b/assignments/week05/athome/static/style.css new file mode 100644 index 00000000..f53d77f7 --- /dev/null +++ b/assignments/week05/athome/static/style.css @@ -0,0 +1,17 @@ +body { font-family: sans-serif; background: #eee; } +a, h1, h2 { color: #377BA8; } +h1, h2 { font-family: 'Georgia', serif; margin: 0; } +h1 { border-bottom: 2px solid #eee; } +h2 { font-size: 1.2em; } +.page { margin: 2em auto; width: 35em; border: 5px solid #ccc; + padding: 0.8em; background: white; } +.entries { list-style: none; margin: 0; padding: 0; } +.entries li { margin: 0.8em 1.2em; } +.entries li h2 { margin-left: -1em; } +.add-entry { font-size: 0.9em; border-bottom: 1px solid #ccc; } +.add-entry dl { font-weight: bold; } +.metanav { text-align: right; font-size: 0.8em; padding: 0.3em; + margin-bottom: 1em; background: #fafafa; } +.flash { background: #CEE5F5; padding: 0.5em; + border: 1px solid #AACBE2; } +.error { background: #F0D6D6; padding: 0.5em; } \ No newline at end of file diff --git a/assignments/week05/athome/templates/layout.html b/assignments/week05/athome/templates/layout.html new file mode 100644 index 00000000..4b595312 --- /dev/null +++ b/assignments/week05/athome/templates/layout.html @@ -0,0 +1,22 @@ + + + + Flaskr + + + +

Flaskr

+ {% if not session.logged_in %} + log in + {% else %} + log_out + {% endif %} + + {% for message in get_flashed_messages() %} +
{{ message }}
+ {% endfor %} +
+ {% block body %}{% endblock %} +
+ + \ No newline at end of file diff --git a/assignments/week05/athome/templates/login.html b/assignments/week05/athome/templates/login.html new file mode 100644 index 00000000..ed4554db --- /dev/null +++ b/assignments/week05/athome/templates/login.html @@ -0,0 +1,20 @@ +{% extends "layout.html" %} +{% block body %} +

Login

+ {% if error -%} +

Error {{ error }} + {%- endif %} +

+
+ + +
+
+ + +
+
+ +
+
+{% endblock %} diff --git a/assignments/week05/athome/templates/show_entries.html b/assignments/week05/athome/templates/show_entries.html new file mode 100644 index 00000000..f44fd92b --- /dev/null +++ b/assignments/week05/athome/templates/show_entries.html @@ -0,0 +1,31 @@ +{% extends "layout.html" %} +{% block body %} + {% if session.logged_in %} +
+
+ + +
+
+ + +
+
+ +
+
+ {% endif %} +

Posts

+ +{% endblock %} \ No newline at end of file diff --git a/assignments/week05/lab/book_app/book_app.py b/assignments/week05/lab/book_app/book_app.py index af2aaaed..6950cc87 100644 --- a/assignments/week05/lab/book_app/book_app.py +++ b/assignments/week05/lab/book_app/book_app.py @@ -1,24 +1,22 @@ -from flask import Flask -import bookdb - -app = Flask(__name__) - -db = bookdb.BookDB() - - -@app.route('/') -def books(): - # put code here that provides a list of books to a template named - # "book_list.html" - pass - - -@app.route('/book//') -def book(book_id): - # put code here that provides the details of a single book to a template - # named "book_detail.html" - pass - - -if __name__ == '__main__': - app.run(debug=True) +from flask import Flask +from flask import render_template +import bookdb + +app = Flask(__name__) + +db = bookdb.BookDB() + + +@app.route('/') +def books(): + books = db.titles() + return render_template('book_list.html', books = books) + +@app.route('/book//') +def book(book_id): + book = db.title_info(book_id) + return render_template('book_detail.html', book = book) + +if __name__ == '__main__': + app.run(debug=True) + app.run(host = '0.0.0.0') diff --git a/assignments/week05/lab/book_app/templates/book_detail.html b/assignments/week05/lab/book_app/templates/book_detail.html index 715e1f4f..2574231c 100644 --- a/assignments/week05/lab/book_app/templates/book_detail.html +++ b/assignments/week05/lab/book_app/templates/book_detail.html @@ -1,9 +1,15 @@ - - - - - - - - + + + + {{ book.title }} + + +

{{ book.title }}

+
+
Author
{{ book.author }}
+
Publisher
{{ book.publisher }}
+
ISBN
{{ book.isbn }}
+
+

Back to the list

+ \ No newline at end of file diff --git a/assignments/week05/lab/book_app/templates/book_list.html b/assignments/week05/lab/book_app/templates/book_list.html index ab4ac08f..72869676 100644 --- a/assignments/week05/lab/book_app/templates/book_list.html +++ b/assignments/week05/lab/book_app/templates/book_list.html @@ -1,12 +1,16 @@ - - - - Python Books - - -

Summer Reading

-

Here's a list of books you might enjoy. Click a title to read more - about that book.

- - + + + + Python Books + + +

Summer Reading

+

Here's a list of books you might enjoy. Click a title to read more + about that book.

+ + \ No newline at end of file diff --git a/assignments/week05/lab/flask_intro.py b/assignments/week05/lab/flask_intro.py new file mode 100644 index 00000000..25c2dd67 --- /dev/null +++ b/assignments/week05/lab/flask_intro.py @@ -0,0 +1,58 @@ +from flask import Flask, url_for, render_template, request +app = Flask(__name__) + +@app.route('/') +def index(): + return 'Index Page' + +@app.route('/hello/') +@app.route('/hello/') +def hello(name=None): + return render_template('hello.html', name=name) + +@app.route('/user/') +def show_user_profile(username): + # show the user profile for that user + return 'User %s' % username + +@app.route('/post/') +def show_post(post_id): + # show the post with the given id, the id is an integer + return 'Post %d' % post_id + +@app.route('/div//') +def divide(val): + return "%0.2f divided by 2 is %0.2f" % (val, val / 2) + +@app.route('/projects/') +def projects(): + return 'The project page' + +@app.route('/about') +def about(): + return 'The about page' + +@app.route('/login', methods=['GET', 'POST']) +def login(): + if request.method == 'POST': + do_the_login() + else: + show_the_login_form() + +@app.route('/blog/entry//', methods=['GET',]) +def read_entry(id): + return "reading entry %d" % id + +@app.route('/blog/entry//', methods=['POST', ]) +def write_entry(id): + return 'writing entry %d' % id + +if __name__ == '__main__': + app.debug = True + app.run(host='0.0.0.0') + + with app.test_request_context(): + print url_for('index') + print url_for('login') + print url_for('login', next='/') + print url_for('profile', username='John Doe') diff --git a/assignments/week05/lab/flaskr_1/flaskr.py b/assignments/week05/lab/flaskr_1/flaskr.py index a959bdf9..1f8ba452 100644 --- a/assignments/week05/lab/flaskr_1/flaskr.py +++ b/assignments/week05/lab/flaskr_1/flaskr.py @@ -1,11 +1,22 @@ -from flask import Flask - - -# configuration goes here - - -app = Flask(__name__) - - -if __name__ == '__main__': - app.run(debug=True) +from flask import Flask +import sqlite3 +from contextlib import closing + +# configuration goes here +DATABASE = '/tmp/flask.db' +SECRET_KEY = 'development key' + +app = Flask(__name__) +app.config.from_object(__name__) + +def connect_db(): + return sqlite3.connect(app.config['DATABASE']) + +def init_db(): + with closing(connect_db()) as db: + with app.open_resource('schema.sql') as f: + db.cursor().executescript(f.read()) + db.commit() + +if __name__ == '__main__': + app.run(debug=True) diff --git a/assignments/week05/lab/flaskr_1/flaskr_tests.py b/assignments/week05/lab/flaskr_1/flaskr_tests.py index e69de29b..87d8696e 100644 --- a/assignments/week05/lab/flaskr_1/flaskr_tests.py +++ b/assignments/week05/lab/flaskr_1/flaskr_tests.py @@ -0,0 +1,27 @@ +import os +import flaskr +import unittest +import tempfile + +class FlaskrTestCase(unittest.TestCase): + + def setUp(self): + db_fd = tempfile.mkstemp() + self.db_fd, flaskr.app.config['DATABASE'] = db_fd + flaskr.app.config['TESTING'] = True + self.client = flaskr.app.test_client() + self.app = flaskr.app + flaskr.init_db() + + def tearDown(self): + os.close(self.db_fd) + os.unlink(flaskr.app.config['DATABASE']) + + def test_database_setup(self): + con = flaskr.connect_db() + cur = con.execute('PRAGMA table_info(entries);') + rows = cur.fetchall() + self.assertEquals(len(rows), 3) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/assignments/week05/lab/flaskr_1/schema.sql b/assignments/week05/lab/flaskr_1/schema.sql index e69de29b..24b4ca8e 100644 --- a/assignments/week05/lab/flaskr_1/schema.sql +++ b/assignments/week05/lab/flaskr_1/schema.sql @@ -0,0 +1,6 @@ +drop table if exists entries; +create table entries ( + id integer primary key autoincrement, + title string not null, + text string not null +); \ No newline at end of file diff --git a/assignments/week05/lab/flaskr_2/flaskr.py b/assignments/week05/lab/flaskr_2/flaskr.py index a97d679d..bca257c5 100644 --- a/assignments/week05/lab/flaskr_2/flaskr.py +++ b/assignments/week05/lab/flaskr_2/flaskr.py @@ -1,27 +1,51 @@ -import sqlite3 -from contextlib import closing - -from flask import Flask - - -# configuration goes here -DATABASE = '/tmp/flaskr.db' -SECRET_KEY = 'development key' - -app = Flask(__name__) -app.config.from_object(__name__) - - -def connect_db(): - return sqlite3.connect(app.config['DATABASE']) - - -def init_db(): - with closing(connect_db()) as db: - with app.open_resource('schema.sql') as f: - db.cursor().executescript(f.read()) - db.commit() - - -if __name__ == '__main__': - app.run(debug=True) +import sqlite3 +from contextlib import closing + +from flask import Flask +from flask import g +from flask import render_template + + +# configuration goes here +DATABASE = '/tmp/flaskr.db' +SECRET_KEY = 'development key' + +app = Flask(__name__) +app.config.from_object(__name__) + + +def connect_db(): + return sqlite3.connect(app.config['DATABASE']) + + +def init_db(): + with closing(connect_db()) as db: + with app.open_resource('schema.sql') as f: + db.cursor().executescript(f.read()) + db.commit() + +@app.before_request +def before_request(): + g.db = connect_db() + +def teardown_request(exception): + g.db.close() + +def write_entry(title, text): + g.db.execute('insert into entries (title, text) values (?, ?)', + [title, text]) + g.db.commit() + +def get_all_entries(): + cur = g.db.execute('select title, text from entries order by id desc') + entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()] + return entries + +@app.route('/') +def show_entries(): + entries = get_all_entries() + return render_template('show_entries.html', entries=entries) + + +if __name__ == '__main__': + app.run(debug=True) diff --git a/assignments/week05/lab/flaskr_2/flaskr_tests.py b/assignments/week05/lab/flaskr_2/flaskr_tests.py index 50fef94d..71c3dcd2 100644 --- a/assignments/week05/lab/flaskr_2/flaskr_tests.py +++ b/assignments/week05/lab/flaskr_2/flaskr_tests.py @@ -1,28 +1,69 @@ -import os -import flaskr -import unittest -import tempfile - - -class FlaskrTestCase(unittest.TestCase): - - def setUp(self): - self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp() - flaskr.app.config['TESTING'] = True - self.client = flaskr.app.test_client() - self.app = flaskr.app - flaskr.init_db() - - def tearDown(self): - os.close(self.db_fd) - os.unlink(flaskr.app.config['DATABASE']) - - def test_database_setup(self): - con = flaskr.connect_db() - cur = con.execute('PRAGMA table_info(entries);') - rows = cur.fetchall() - self.assertTrue(len(rows) == 3) - - -if __name__ == '__main__': +import os +import flaskr +import unittest +import tempfile + + +class FlaskrTestCase(unittest.TestCase): + + def setUp(self): + self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp() + flaskr.app.config['TESTING'] = True + self.client = flaskr.app.test_client() + self.app = flaskr.app + flaskr.init_db() + + def tearDown(self): + os.close(self.db_fd) + os.unlink(flaskr.app.config['DATABASE']) + + def test_database_setup(self): + con = flaskr.connect_db() + cur = con.execute('PRAGMA table_info(entries);') + rows = cur.fetchall() + self.assertTrue(len(rows) == 3) + + def test_write_entry(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + con = flaskr.connect_db() + cur = con.execute("select * from entries;") + rows = cur.fetchall() + self.assertEquals(len(rows), 1) + for val in expected: + self.assertTrue(val in rows[0]) + + def test_get_all_entries_empty(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + entries = flaskr.get_all_entries() + self.assertEquals(len(entries), 0) + + def test_get_all_entries(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + entries = flaskr.get_all_entries() + self.assertEquals(len(entries), 1) + for entry in entries: + self.assertEquals(expected[0], entry['title']) + self.assertEquals(expected[1], entry['text']) + + def test_empty_listing(self): + rv = self.client.get('/') + assert 'No entries here so far' in rv.data + + def test_listing(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + rv = self.client.get('/') + for value in expected: + assert value in rv.data + +if __name__ == '__main__': unittest.main() \ No newline at end of file diff --git a/assignments/week05/lab/flaskr_2/templates/layout.html b/assignments/week05/lab/flaskr_2/templates/layout.html new file mode 100644 index 00000000..50f79fe9 --- /dev/null +++ b/assignments/week05/lab/flaskr_2/templates/layout.html @@ -0,0 +1,12 @@ + + + + Flaskr + + +

Flaskr

+
+ {% block body %}{% endblock %} +
+ + \ No newline at end of file diff --git a/assignments/week05/lab/flaskr_2/templates/show_entries.html b/assignments/week05/lab/flaskr_2/templates/show_entries.html new file mode 100644 index 00000000..fe4bf872 --- /dev/null +++ b/assignments/week05/lab/flaskr_2/templates/show_entries.html @@ -0,0 +1,15 @@ +{% extends "layout.html" %} +{% block body %} +

Posts

+
    + {% for entry in entries %} +
  • +

    {{ entry.title }}

    +
    + {{ entry.text|safe }} +
    +
  • + {% else %} +
  • No entries here so far
  • + {% endfor %} +
\ No newline at end of file diff --git a/assignments/week05/lab/flaskr_3/flaskr.py b/assignments/week05/lab/flaskr_3/flaskr.py index 70fed771..fe7ee2d1 100644 --- a/assignments/week05/lab/flaskr_3/flaskr.py +++ b/assignments/week05/lab/flaskr_3/flaskr.py @@ -1,50 +1,95 @@ -import sqlite3 -from contextlib import closing - -from flask import Flask -from flask import g - - -# configuration goes here -DATABASE = '/tmp/flaskr.db' -SECRET_KEY = 'development key' - -app = Flask(__name__) -app.config.from_object(__name__) - - -def connect_db(): - return sqlite3.connect(app.config['DATABASE']) - - -def init_db(): - with closing(connect_db()) as db: - with app.open_resource('schema.sql') as f: - db.cursor().executescript(f.read()) - db.commit() - - -@app.before_request -def before_request(): - g.db = connect_db() - - -@app.teardown_request -def teardown_request(exception): - g.db.close() - - -def write_entry(title, text): - g.db.execute('insert into entries (title, text) values (?, ?)', - [title, text]) - g.db.commit() - - -def get_all_entries(): - cur = g.db.execute('select title, text from entries order by id desc') - entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()] - return entries - - -if __name__ == '__main__': - app.run(debug=True) +import sqlite3 +from contextlib import closing + +from flask import Flask +from flask import g +from flask import render_template +from flask import session +from flask import request +from flask import redirect +from flask import flash +from flask import url_for +from flask import abort + +# configuration goes here +DATABASE = '/tmp/flaskr.db' +SECRET_KEY = 'development key' +USERNAME = 'admin' +PASSWORD = 'default' + +app = Flask(__name__) +app.config.from_object(__name__) + +def connect_db(): + return sqlite3.connect(app.config['DATABASE']) + +def init_db(): + with closing(connect_db()) as db: + with app.open_resource('schema.sql') as f: + db.cursor().executescript(f.read()) + db.commit() + +@app.before_request +def before_request(): + g.db = connect_db() + +@app.teardown_request +def teardown_request(exception): + g.db.close() + +def write_entry(title, text): + g.db.execute('insert into entries (title, text) values (?, ?)', + [title, text]) + g.db.commit() + +def get_all_entries(): + cur = g.db.execute('select title, text from entries order by id desc') + entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()] + return entries + +@app.route('/') +def show_entries(): + entries = get_all_entries() + return render_template('show_entries.html', entries=entries) + +def do_login(usr, pwd): + if usr != app.config['USERNAME']: + raise ValueError + elif pwd != app.config['PASSWORD']: + raise ValueError + else: + session['logged_in'] = True + +@app.route('/login', methods=['GET', 'POST']) +def login(): + error = None + if request.method == 'POST': + try: + do_login(request.form['username'], + request.form['password']) + except ValueError: + error = "Invalid Login" + else: + flash('You were logged in') + return redirect(url_for('show_entries')) + return render_template('login.html', error=error) + +@app.route('/logout') +def logout(): + session.pop('logged_in', None) + flash('You were logged out') + return redirect(url_for('show_entries')) + +@app.route('/add', methods=['POST']) +def add_entry(): + if not session.get('logged_in'): + abort(401) + try: + write_entry(request.form['title'], request.form['text']) + flash('New entry was successfully posted') + except sqlite3.Error as e: + flash('There was an error: %s' % e.args[0]) + return redirect(url_for('show_entries')) + +if __name__ == '__main__': + app.run(debug=True) diff --git a/assignments/week05/lab/flaskr_3/flaskr_tests.py b/assignments/week05/lab/flaskr_3/flaskr_tests.py index 4065dd31..a06b3514 100644 --- a/assignments/week05/lab/flaskr_3/flaskr_tests.py +++ b/assignments/week05/lab/flaskr_3/flaskr_tests.py @@ -1,59 +1,115 @@ -import os -import flaskr -import unittest -import tempfile - - -class FlaskrTestCase(unittest.TestCase): - - def setUp(self): - self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp() - flaskr.app.config['TESTING'] = True - self.client = flaskr.app.test_client() - self.app = flaskr.app - flaskr.init_db() - - def tearDown(self): - os.close(self.db_fd) - os.unlink(flaskr.app.config['DATABASE']) - - def test_database_setup(self): - con = flaskr.connect_db() - cur = con.execute('PRAGMA table_info(entries);') - rows = cur.fetchall() - self.assertEqual(len(rows), 3) - - def test_write_entry(self): - expected = ("My Title", "My Text") - with self.app.test_request_context('/'): - self.app.preprocess_request() - flaskr.write_entry(*expected) - con = flaskr.connect_db() - cur = con.execute("select * from entries;") - rows = cur.fetchall() - self.assertEquals(len(rows), 1) - for val in expected: - self.assertTrue(val in rows[0]) - - - def test_get_all_entries_empty(self): - with self.app.test_request_context('/'): - self.app.preprocess_request() - entries = flaskr.get_all_entries() - self.assertEquals(len(entries), 0) - - - def test_get_all_entries(self): - expected = ("My Title", "My Text") - with self.app.test_request_context('/'): - self.app.preprocess_request() - flaskr.write_entry(*expected) - entries = flaskr.get_all_entries() - self.assertEquals(len(entries), 1) - for entry in entries: - self.assertEquals(expected[0], entry['title']) - self.assertEquals(expected[1], entry['text']) - - -if __name__ == '__main__': +import os +import flaskr +import unittest +import tempfile + + +class FlaskrTestCase(unittest.TestCase): + + def setUp(self): + self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp() + flaskr.app.config['TESTING'] = True + self.client = flaskr.app.test_client() + self.app = flaskr.app + flaskr.init_db() + + def tearDown(self): + os.close(self.db_fd) + os.unlink(flaskr.app.config['DATABASE']) + + def test_database_setup(self): + con = flaskr.connect_db() + cur = con.execute('PRAGMA table_info(entries);') + rows = cur.fetchall() + self.assertEqual(len(rows), 3) + + def test_write_entry(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + con = flaskr.connect_db() + cur = con.execute("select * from entries;") + rows = cur.fetchall() + self.assertEquals(len(rows), 1) + for val in expected: + self.assertTrue(val in rows[0]) + + + def test_get_all_entries_empty(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + entries = flaskr.get_all_entries() + self.assertEquals(len(entries), 0) + + + def test_get_all_entries(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + entries = flaskr.get_all_entries() + self.assertEquals(len(entries), 1) + for entry in entries: + self.assertEquals(expected[0], entry['title']) + self.assertEquals(expected[1], entry['text']) + + def test_empty_listing(self): + rv = self.client.get('/') + assert 'No entries here so far' in rv.data + + def test_listing(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + rv = self.client.get('/') + for value in expected: + assert value in rv.data + + def test_login_passes(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.do_login(flaskr.app.config['USERNAME'], + flaskr.app.config['PASSWORD']) + self.assertTrue(session.get('logged_in', False)) + + def test_login_fails(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + self.assertRaises(ValueError, flaskr.do_login, + flaskr.app.config['USERNAME'], + 'incorrectpassword') + + def login(self, username, password): + return self.client.post('/login', data=dict( + username=username, + password=password + ), follow_redirects=True) + + def logout(self): + return self.client.get('/logout', follow_redirects=True) + + def test_login_logout(self): + rv = self.login('admin', 'default') + assert 'You were logged in' in rv.data + rv = self.logout() + assert 'You were logged out' in rv.data + rv = self.login('adminx', 'default') + assert 'Invalid Login' in rv.data + rv = self.login('admin', 'defaultx') + assert 'Invalid Login' in rv.data + + def test_add_entries(self): + self.login('admin', 'default') + rv = self.client.post('/add', data=dict( + title='Hello', + text='This is a post' + ), follow_redirects=True) + assert 'No entries here so far' not in rv.data + assert 'Hello' in rv.data + assert 'This is a post' in rv.data + + +if __name__ == '__main__': unittest.main() \ No newline at end of file diff --git a/assignments/week05/lab/flaskr_3/templates/New Text Document.txt b/assignments/week05/lab/flaskr_3/templates/New Text Document.txt new file mode 100644 index 00000000..e69de29b diff --git a/assignments/week05/lab/flaskr_3/templates/layout.html b/assignments/week05/lab/flaskr_3/templates/layout.html new file mode 100644 index 00000000..50f79fe9 --- /dev/null +++ b/assignments/week05/lab/flaskr_3/templates/layout.html @@ -0,0 +1,12 @@ + + + + Flaskr + + +

Flaskr

+
+ {% block body %}{% endblock %} +
+ + \ No newline at end of file diff --git a/assignments/week05/lab/flaskr_3/templates/login.html b/assignments/week05/lab/flaskr_3/templates/login.html new file mode 100644 index 00000000..2bbd936a --- /dev/null +++ b/assignments/week05/lab/flaskr_3/templates/login.html @@ -0,0 +1,32 @@ +{% extends "layout.html" %} +{% block body %} +

Login

+ {% if error -%} +

Error {{ error }} + {%- endif %} +

+
+ + +
+
+ + +
+
+ +
+
+ +

Flaskr

+
+{% if not session.logged_in %} + log in +{% else %} + log_out +{% endif %} +
+{% for message in get_flashed_messages() %} +
{{ message }}
+{% endfor %} +
\ No newline at end of file diff --git a/assignments/week05/lab/flaskr_3/templates/show_entries.html b/assignments/week05/lab/flaskr_3/templates/show_entries.html new file mode 100644 index 00000000..3f7ba5f5 --- /dev/null +++ b/assignments/week05/lab/flaskr_3/templates/show_entries.html @@ -0,0 +1,33 @@ +{% extends "layout.html" %} +{% block body %} +

Posts

+
    + {% for entry in entries %} +
  • +

    {{ entry.title }}

    +
    + {{ entry.text|safe }} +
    +
  • + {% else %} +
  • No entries here so far
  • + {% endfor %} +
+ +{% block body %} +{% if session.logged_in %} +
+
+ + +
+
+ + +
+
+ +
+
+{% endif %} +

Posts

\ No newline at end of file diff --git a/assignments/week05/lab/flaskr_4/flaskr.py b/assignments/week05/lab/flaskr_4/flaskr.py index d2a859ab..ae3cc873 100644 --- a/assignments/week05/lab/flaskr_4/flaskr.py +++ b/assignments/week05/lab/flaskr_4/flaskr.py @@ -105,3 +105,4 @@ def add_entry(): if __name__ == '__main__': app.run(debug=True) + app.run(host = '0.0.0.0') diff --git a/assignments/week06/athome/README.txt b/assignments/week06/athome/README.txt new file mode 100644 index 00000000..e1e1b7e5 --- /dev/null +++ b/assignments/week06/athome/README.txt @@ -0,0 +1,7 @@ +I was able to finish the tasks except the form (posting a new blog entry) and the dynamic filtering. + +I will try to work on it the next 2 days but not sure if I will be able to get it right. + +Thanks, + +Allen Su \ No newline at end of file diff --git a/assignments/week06/athome/djangor/__init__.py b/assignments/week06/athome/djangor/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/assignments/week06/athome/djangor/admin.py b/assignments/week06/athome/djangor/admin.py new file mode 100644 index 00000000..dc2d1bf6 --- /dev/null +++ b/assignments/week06/athome/djangor/admin.py @@ -0,0 +1,10 @@ +from django.contrib import admin +from djangor.models import BlogPost + +class BlogAdmin(admin.ModelAdmin): + list_display = ('pub_date', 'title', + 'published_today', 'owner') + list_filter = ('pub_date', ) + ordering = ('pub_date', ) + +admin.site.register(BlogPost, BlogAdmin) \ No newline at end of file diff --git a/assignments/week06/athome/djangor/models.py b/assignments/week06/athome/djangor/models.py new file mode 100644 index 00000000..6f45ee4e --- /dev/null +++ b/assignments/week06/athome/djangor/models.py @@ -0,0 +1,20 @@ +from django.db import models +from django.utils import timezone +from django.contrib.auth.models import User + +class BlogPost(models.Model): + title = models.CharField(max_length=200) + body = models.CharField(max_length=2000) + pub_date = models.DateTimeField('date published') + owner = models.ForeignKey(User) + + def __unicode__(self): + return self.title + + def published_today(self): + now = timezone.now() + time_delta = now - self.pub_date + return time_delta.days == 0 + published_today.boolean = True + published_today.short_description = "Published Today?" + diff --git a/assignments/week06/athome/djangor/templates/base.html b/assignments/week06/athome/djangor/templates/base.html new file mode 100644 index 00000000..f89925eb --- /dev/null +++ b/assignments/week06/athome/djangor/templates/base.html @@ -0,0 +1,20 @@ + + + + My Site + + +
+
+ {% if messages %} + {% for message in messages %} +

+ {{ message }}

+ {% endfor %} + {% endif %} + {% block content %} + {% endblock %} +
+
+ + diff --git a/assignments/week06/athome/djangor/templates/blogs/New Text Document.txt b/assignments/week06/athome/djangor/templates/blogs/New Text Document.txt new file mode 100644 index 00000000..e69de29b diff --git a/assignments/week06/athome/djangor/templates/blogs/detail.html b/assignments/week06/athome/djangor/templates/blogs/detail.html new file mode 100644 index 00000000..dd75cde4 --- /dev/null +++ b/assignments/week06/athome/djangor/templates/blogs/detail.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +

{{ title }}

+

{{ date }}

+

+{{ body }} +

+Back to the Blog Entries, please +{% endblock %} \ No newline at end of file diff --git a/assignments/week06/athome/djangor/templates/blogs/list.html b/assignments/week06/athome/djangor/templates/blogs/list.html new file mode 100644 index 00000000..3ddce447 --- /dev/null +++ b/assignments/week06/athome/djangor/templates/blogs/list.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block content %} +

Latest Blog Entries

+ {% for entry in blog_entries %} +
+

{{ entry.title }}

+
+ {% endfor %} +

Add a new blog entry

+{% endblock %} + + diff --git a/assignments/week06/athome/djangor/templates/blogs/result.html b/assignments/week06/athome/djangor/templates/blogs/result.html new file mode 100644 index 00000000..8937985a --- /dev/null +++ b/assignments/week06/athome/djangor/templates/blogs/result.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + +{% block content %} +

{{ poll }}

+
    + {% for choice in poll.choice_set.all %} +
  • {{ choice }} ({{choice.votes}} votes)
  • + {% endfor %} +
+Back to the polls, please +{% endblock %} \ No newline at end of file diff --git a/assignments/week06/athome/djangor/tests.py b/assignments/week06/athome/djangor/tests.py new file mode 100644 index 00000000..501deb77 --- /dev/null +++ b/assignments/week06/athome/djangor/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.assertEqual(1 + 1, 2) diff --git a/assignments/week06/athome/djangor/urls.py b/assignments/week06/athome/djangor/urls.py new file mode 100644 index 00000000..d0045357 --- /dev/null +++ b/assignments/week06/athome/djangor/urls.py @@ -0,0 +1,27 @@ +from django.conf.urls import patterns, url +from django.http import HttpResponse +from django.views.generic import ListView, DetailView + +from djangor.models import BlogPost +from djangor.views import BlogEntryList + +def stub(request, *args, **kwargs): + return HttpResponse('stub view', mimetype="text/plain") + +urlpatterns = patterns('', + url(http://github.com/r'%5E),%20BlogEntryList.as_view(), name="entry_list"), + url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/$', 'djangor.views.entry_detail', name="entry_detail"), + url(r'^new/$', stub, + # DetailView.as_view( + # model=BlogPost, + # template_name="blogs/detail.html"), + name="entry_new"), + #url(http://github.com/r'%5E(?P%3Cpk%3E\d+)//$', stub, + # #'polls.views.vote_view', + # name="poll_vote"), + #url(http://github.com/r'%5E(?P%3Cpk%3E\d+)//$', stub, + # #DetailView.as_view( + # # model=Poll, + # # template_name="blogs/result.html"), + # name="poll_result"), +) diff --git a/assignments/week06/athome/djangor/views.py b/assignments/week06/athome/djangor/views.py new file mode 100644 index 00000000..24a05ee4 --- /dev/null +++ b/assignments/week06/athome/djangor/views.py @@ -0,0 +1,41 @@ +from django.core.urlresolvers import reverse +from django.http import HttpResponseRedirect +from django.shortcuts import get_object_or_404 +from django.contrib import messages +from djangor.models import BlogPost +from django.views.generic import ListView, DetailView +from django.shortcuts import render_to_response + +class BlogEntryList(ListView): + model = BlogPost + template_name = "blogs/list.html" + context_object_name = 'blog_entries' + +def entry_detail(*args, **kwargs): + for arg in kwargs: + pk = kwargs[arg] + entry = BlogPost.objects.get(pk=pk) + return render_to_response('blogs/detail.html', {'title': entry.title, 'body': entry.body, 'date': entry.pub_date}) + +""" +def vote_view(request, pk): + poll = get_object_or_404(Poll, pk=pk) + if request.method == "POST": + try: + choice = poll.choice_set.get( + pk=request.POST.get('choice', 0)) + except Choice.DoesNotExist: + msg = "Ooops, pick a choice that exists, please" + messages.add_message(request, messages.ERROR, msg) + url = reverse('poll_detail', args=[pk, ]) + else: # vote and send to result + choice.votes += 1 + choice.save() + messages.add_message(request, messages.INFO, + "You voted for %s" % choice) + url = reverse('poll_result', args=[pk]) + else: # submitted via GET, ignore it + url = reverse('poll_detail', args=[pk, ]) + + return HttpResponseRedirect(url) +""" \ No newline at end of file diff --git a/assignments/week08/lab/edit.pt b/assignments/week08/lab/edit.pt new file mode 100644 index 00000000..542ba5ea --- /dev/null +++ b/assignments/week08/lab/edit.pt @@ -0,0 +1,14 @@ + + + Editing + Page Name Goes Here + + + +
+