diff --git a/Labs/Lab9/Flask Lab 2.docx b/Labs/Lab9/Flask Lab 2.docx new file mode 100644 index 0000000..61f5f2f Binary files /dev/null and b/Labs/Lab9/Flask Lab 2.docx differ diff --git a/Labs/Lab9/Flask Lab 2.txt b/Labs/Lab9/Flask Lab 2.txt new file mode 100644 index 0000000..661dc9b --- /dev/null +++ b/Labs/Lab9/Flask Lab 2.txt @@ -0,0 +1,46 @@ +Flask Lab 2 +In this lab weÕll be implementing a simple survey web app using Flask. +The general concepts weÕll be covering are: +* Routing +* Templating +* Passing Parameters +* Sessions +We will walk through this lab in class and for homework you should redesign the questions and the survey and get creative. Also, make the e-mail link work and send the survey results to us! +Requirements +1. Download the flaskLab2.zip file from bCourses>Files>Labs +Creating a login page +2. Open the Ôlogin.htmlÕ template in your text editor +a. Make this file an extension of the Ôbase.htmlÕ template +b. Use the existing form and create form inputs that capture the userÕs name and email +c. Make sure the HTML in this file is replacing the block called ÔcontentÕ in the Ôbase.htmlÕ template +d. Make the form submit to the Ô/loginÕ endpoint +Creating a session +3. Open the Ôviews.pyÕ file in your text editor +a. Find the route for Ô/loginÕ +b. Within the Ôlogin()Õ function, if the request method is POST +i. set the sessionÕs ÔusernameÕ key to whatever the user entered for their username +ii. Redirect the user to the ÔindexÕ route +Extending and reusing content from the Ôbase.htmlÕ template for the Ôsurvey.htmlÕ template +4. Open the Ôsurvey.htmlÕ template in your text editor +a. Make this file an extension of the Ôbase.htmlÕ template +b. The HTML in this file for the form with the id of ÔlogoutÕ is currently replacing the entire contents of the
tag in the Ôbase.htmlÕ template. Using the super() function, pull in the original contents of the
tag from the Ôbase.htmlÕ template +c. Make sure the HTML in this file from the

and down is replacing the block called ÔcontentÕ in the Ôbase.htmlÕ template +Creating an Ajax request with the userÕs form inputs from Ôsurvey.htmlÕ +5. Open the Ôinteraction.jsÕ script in your text editor +a. Notice that the button from the Ôsurvey.htmlÕ template with the id Ôsubmit-surveyÕ has a click event binding +b. Also notice that there are variable declarations for each of the form input fields +c. Create a $.post() Ajax request within this ÔclickÕ event handler +i. The url for this Ajax request should point to Ôsubmit-surveyÕ +ii. The data parameter of this Ajax request should be an object whose key-value pairs correspond to the variables for each form input field +iii. The success function for this Ajax request should set the innerHTML of document.body.parentNode to the response data object +Rendering the survey results via Flask +6. Go back to the Ôviews.pyÕ file in your text editor +a. Find the route for Ô/submit-surveyÕ +b. YouÕll notice that an empty object has been assigned to the variable name ÔsurveyResponseÕ +c. YouÕll also notice that Ôfe-beforeÕ and Ôfe-afterÕ keys in the ÔsurveyResponseÕ object have been assigned values that correspond to values in the data object we passed in from step 5 above. +i. Assign the keys ÔcolorÕ, ÔfoodÕ, and ÔvacationÕ for the ÔsurveyResponseÕ object to corresponding values from the passed-in data object in a similar fashion +7. You should now be able to do the following: +a. Log into this simple survey web app with a username and email +b. Take the survey +c. See the survey results displayed + diff --git a/Labs/Lab9/flaskLab2/.spyderworkspace b/Labs/Lab9/flaskLab2/.spyderworkspace new file mode 100755 index 0000000..be24de3 Binary files /dev/null and b/Labs/Lab9/flaskLab2/.spyderworkspace differ diff --git a/Labs/Lab9/flaskLab2/app/__init__.py b/Labs/Lab9/flaskLab2/app/__init__.py new file mode 100755 index 0000000..9a4e940 --- /dev/null +++ b/Labs/Lab9/flaskLab2/app/__init__.py @@ -0,0 +1,4 @@ +from flask import Flask + +myapp = Flask(__name__) +from app import views diff --git a/Labs/Lab9/flaskLab2/app/__init__.pyc b/Labs/Lab9/flaskLab2/app/__init__.pyc new file mode 100755 index 0000000..4d4e5ad Binary files /dev/null and b/Labs/Lab9/flaskLab2/app/__init__.pyc differ diff --git a/Labs/Lab9/flaskLab2/app/__pycache__/__init__.cpython-35.pyc b/Labs/Lab9/flaskLab2/app/__pycache__/__init__.cpython-35.pyc new file mode 100644 index 0000000..2c7c65d Binary files /dev/null and b/Labs/Lab9/flaskLab2/app/__pycache__/__init__.cpython-35.pyc differ diff --git a/Labs/Lab9/flaskLab2/app/__pycache__/views.cpython-35.pyc b/Labs/Lab9/flaskLab2/app/__pycache__/views.cpython-35.pyc new file mode 100644 index 0000000..2120e3c Binary files /dev/null and b/Labs/Lab9/flaskLab2/app/__pycache__/views.cpython-35.pyc differ diff --git a/Labs/Lab9/flaskLab2/app/static/interactions.js b/Labs/Lab9/flaskLab2/app/static/interactions.js new file mode 100755 index 0000000..12d61f9 --- /dev/null +++ b/Labs/Lab9/flaskLab2/app/static/interactions.js @@ -0,0 +1,48 @@ +$('#submit-survey').on('click', function submitSurvey() { + var background = $("input[name=background]").val(); + var language = $("input[name=language]").val(); + var course = $("input[name=course]").val(); + var feBefore = $("input[name=front-end-before]").val(); + var feAfter = $("input[name=front-end-after]").val(); + $.post("submit-survey", + {background: background, + language: language, + course: course, + feBefore: feBefore, + feAfter: feAfter}, + function(data) { + $("html").html(data); + }); +}); + +$("#results-email-container").on('click', '#email-results-button', function emailResults() { + $.post("/send_email", + { + "destination_email": $("#visitor-email").val() + }, + function response(data) { + $("#results-email-container").html(data.statusMsg) + }, + "json" + ) + + console.log($(this)); +}); + +$("#site-title-wrapper").on('click', function goHome() { + window.location.href = '/'; +}); + +$(document).ready(function applySliderLabels() { + var currentValue = $("#fe-before").val(); + $("#fe-before").next().html(currentValue); + + currentValue = $("#fe-after").val(); + $("#fe-after").next().html(currentValue); +}); + + +$("input[type='range']").on('change', function updateLabel() { + var currentValue = $(this).val(); + $(this).next().html(currentValue); +}); \ No newline at end of file diff --git a/Labs/Lab9/flaskLab2/app/static/main.css b/Labs/Lab9/flaskLab2/app/static/main.css new file mode 100755 index 0000000..35532a5 --- /dev/null +++ b/Labs/Lab9/flaskLab2/app/static/main.css @@ -0,0 +1,225 @@ +/*----------------- CSS RESET ------------------*/ + +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, 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, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + +/*----------------- CSS RESET ------------------*/ + +html, body { + background-color: #f9f9f9; + font-family: 'Open Sans', sans-serif; + font-size: 16px; +} + +header { + background-color: #1abc9c; + box-shadow: 0 2px 6px 1px #a7a7a7; + color: #ecf0f1; + height: 5rem; +} + +footer { + background-color: #16a085; + bottom: 0; + color: #ecf0f1; + height: 7rem; + margin-top: 2em; + text-align: center; + width: 100%; +} + +footer p { + height: 7rem; + line-height: 7rem; +} + +h1, h3 { + padding: 4px; +} + +h1 { + font-size: 2rem; + font-weight: bold; +} + +h3 { + font-size: 1.4rem; +} + +a { + text-decoration: none; +} + +input[type="text"], input[type="range"] { + border: 1px solid #bdc3c7; + border-radius: 2px; + margin-left: 1rem; + vertical-align: middle; +} + +input[type=range]{ + -webkit-appearance: none; +} + +input[type=range]::-webkit-slider-thumb { + -webkit-appearance: none; + border: none; + height: 1.2rem; + width: 1.2rem; + border-radius: 50%; + background: #1abc9c; + margin-top: -.5rem; +} + +input[type=range]::-webkit-slider-runnable-track { + background: #ccc; + height: .2rem; +} + +.action-button { + background-color: #1abc9c; + border: none; + border-bottom: 3px solid #16a085; + border-radius: 2px; + color: #ecf0f1; + display: inline-block; + font-size: 1rem; + font-weight: bold; + height: 3rem; + padding: 4px; + width: 6rem; +} + +.action-button:hover { + background-color: #16a085; +} + +#site-title-wrapper { + display: inline-block; + height: 5rem; + width: 15%; +} + +#site-icon-wrapper { + display: inline-block; + margin-left: 1rem; + margin-top: -.5rem; + vertical-align: middle; + width: 2.5rem; +} + +#site-icon-wrapper img { + display: inline-block; + max-height: 100%; + max-width: 100% +} + +#site-title { + display: inline-block; + font-weight: bold; + height: 5rem; + line-height: 5rem; + margin-left: .1rem; +} + +#username { + margin-right: .7rem; +} + +#logout { + float: right; + height: inherit; + line-height: 5rem; + margin-right: 1rem; +} + +#logout-button { + background-color: #ecf0f1; + border-bottom-color: #bdc3c7; + color: #222222; + height: 2.5rem; + width: 5rem; +} + +#logout-button:hover { + background-color: #bdc3c7; +} + +#content { + margin-top: 2rem; + text-align: center; + width: 100%; +} + +.main-container { + background: #ecf0f1; + border-radius: 4px; + box-shadow: 0px 2px 10px 2px #95a5a6; + display: block; + min-height: 50vh; + margin: 2rem 0 0 25%; + padding: 1rem; + text-align: left; + width: 50%; +} + +.survey-item, .result-item, #results-email-container { + box-sizing: border-box; + display: block; + margin: 1.5rem 0; + padding: 4px; +} + +.survey-item span { + font-size: 1rem; + margin-left: 1rem; +} + +#email-results-button, #goHome { + height: 2rem; + line-height: 2rem; + margin-left: 1rem; + text-align: center; +} + diff --git a/Labs/Lab9/flaskLab2/app/templates/base.html b/Labs/Lab9/flaskLab2/app/templates/base.html new file mode 100755 index 0000000..eb802bc --- /dev/null +++ b/Labs/Lab9/flaskLab2/app/templates/base.html @@ -0,0 +1,33 @@ + + + + + + {% block title %}{% endblock %} - Ape Ask + + + + {% block styles %}{% endblock %} + + + + +
+ {% block header %} +
+
+ +
+

Ape Ask

+
+ {% endblock %} +
+
{% block content %}{% endblock %}
+ +
+

© Copyright 2016 Ape Ask, all rights reserved

+
+ + + + \ No newline at end of file diff --git a/Labs/Lab9/flaskLab2/app/templates/login.html b/Labs/Lab9/flaskLab2/app/templates/login.html new file mode 100755 index 0000000..9c9e99a --- /dev/null +++ b/Labs/Lab9/flaskLab2/app/templates/login.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} + +{% block title %} + Login +{% endblock %} + +{% block content %} +

Hi There! Welcome to Ape Ask, the leading online survey site.

+
+

Let's get you logged in

+
+
+{% endblock %} \ No newline at end of file diff --git a/Labs/Lab9/flaskLab2/app/templates/not_authorized.html b/Labs/Lab9/flaskLab2/app/templates/not_authorized.html new file mode 100755 index 0000000..99a0c25 --- /dev/null +++ b/Labs/Lab9/flaskLab2/app/templates/not_authorized.html @@ -0,0 +1,13 @@ + + + + + Oops! + + +

Uh Oh! You're not authorized

+ +
+ Take me back home, already! + + \ No newline at end of file diff --git a/Labs/Lab9/flaskLab2/app/templates/page_not_found.html b/Labs/Lab9/flaskLab2/app/templates/page_not_found.html new file mode 100755 index 0000000..dadcc99 --- /dev/null +++ b/Labs/Lab9/flaskLab2/app/templates/page_not_found.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} + +{% block title %} + Oops! +{% endblock %} + +{% block content %} +

Oh, Pooh Bear! You're stuck because we don't have that page for you.

+ +
+ Go back! +{% endblock %} \ No newline at end of file diff --git a/Labs/Lab9/flaskLab2/app/templates/results.html b/Labs/Lab9/flaskLab2/app/templates/results.html new file mode 100755 index 0000000..c6437f8 --- /dev/null +++ b/Labs/Lab9/flaskLab2/app/templates/results.html @@ -0,0 +1,33 @@ +{% extends "base.html" %} + +{% block title %} + Survey +{% endblock %} + +{% block header %} + {{ super() }} +
+ Logged in as {{ name }} + +
+{% endblock %} + +{% block content %} +

Great news - your results are in! Check it out...

+
+

Here are some of your favorite things

+ Your background was {{ surveyResponse['background']}} + Your favorite programming language is {{ surveyResponse['language']}} + Your favorite course is {{ surveyResponse['course']}} + +

Wow! Your front end skillz are getting sharp!

+ Before IO Lab, your front end skillz were at a {{ surveyResponse['fe-before']}} + But in just a few short weeks of IO Lab, your front end skillz are now a {{ surveyResponse['fe-after']}} + +
+ Want your survey results emailed to you? If so, please enter your email: + + Yes! +
+
+{% endblock %} \ No newline at end of file diff --git a/Labs/Lab9/flaskLab2/app/templates/survey.html b/Labs/Lab9/flaskLab2/app/templates/survey.html new file mode 100755 index 0000000..037584e --- /dev/null +++ b/Labs/Lab9/flaskLab2/app/templates/survey.html @@ -0,0 +1,32 @@ +{% extends "base.html" %} + +{% block title %} + Survey +{% endblock %} + + +{% block header %} +{{ super() }} +
+ Logged in as {{ name }} + +
+{% endblock %} + +{% block content %} +

A Little Survey About You

+
+

Some of your favorites

+ + + + +

Let's look at your front end skillz progression

+ + + + +
+{% endblock %} \ No newline at end of file diff --git a/Labs/Lab9/flaskLab2/app/views.py b/Labs/Lab9/flaskLab2/app/views.py new file mode 100755 index 0000000..bb1356b --- /dev/null +++ b/Labs/Lab9/flaskLab2/app/views.py @@ -0,0 +1,89 @@ +from app import myapp +from flask import request, render_template, session, redirect, url_for, escape, jsonify +from flask_mail import Mail, Message +import os + +myapp.secret_key = os.urandom(24) + +# Setup email. +myapp.config.update(dict( + DEBUG = True, + MAIL_SERVER = 'smtp.gmail.com', + MAIL_PORT = 587, + MAIL_USE_TLS = True, + MAIL_USE_SSL = False, + MAIL_USERNAME = 'shuting_liang@berkeley.edu', + MAIL_PASSWORD = '17011701Lst!', +)) + +mail = Mail(myapp) + +@myapp.route('/') +@myapp.route('/index') +def index(): + username = '' + if 'username' in session: + username = escape(session['username']) + return render_template('survey.html', name=username) + else: + return render_template('login.html') + +@myapp.route('/login', methods=['GET', 'POST']) +def login(): + if request.method == 'POST': + session['username'] = request.form.get("username") + session['email'] = request.form.get("email") + return redirect(url_for('index')) + + +@myapp.route('/logout') +def logout(): + session.pop('username', None) + session.pop('email', None) + return redirect(url_for('index')) + +@myapp.route('/submit-survey', methods=['GET', 'POST']) +def submitSurvey(): + username = '' + email = '' + if 'username' in session: + username = escape(session['username']) # a global variable + email = escape(session['email']) + surveyResponse = {} + surveyResponse['background'] = request.form.get('background') + surveyResponse['language'] = request.form.get('language') + surveyResponse['course'] = request.form.get('course') + surveyResponse['fe-before'] = request.form.get('feBefore') + surveyResponse['fe-after'] = request.form.get('feAfter') + session['email_content'] = render_template('results.html', name=username, email=email, surveyResponse=surveyResponse) + + return session['email_content'] + else: + return render_template('login.html') + +@myapp.route('/send_email', methods=['GET', 'POST']) +def sendEmail(): + # check if session['email_content'] still exists before attempting to send. + + if (request.form.get('destination_email')): + recipient_list = [] + recipient_list.append(request.form.get('destination_email')) + + if (session.get('email_content')): + email_content = session['email_content'] + else: + email_content = "Oops, session timed out!" + + msg = Message(body=email_content, recipients=recipient_list, subject="Your survey results") + + mail.send(msg) + + ResultMsg = "Your email has been sent to " + request.form.get("destination_email") + else: + ResultMsg = "Failed to send email!" + + return jsonify(statusMsg=ResultMsg) + +@myapp.errorhandler(404) +def page_not_found(error): + return render_template('page_not_found.html'), 404 \ No newline at end of file diff --git a/Labs/Lab9/flaskLab2/app/views.pyc b/Labs/Lab9/flaskLab2/app/views.pyc new file mode 100755 index 0000000..259c8d1 Binary files /dev/null and b/Labs/Lab9/flaskLab2/app/views.pyc differ diff --git a/Labs/Lab9/flaskLab2/run.py b/Labs/Lab9/flaskLab2/run.py new file mode 100755 index 0000000..dae9904 --- /dev/null +++ b/Labs/Lab9/flaskLab2/run.py @@ -0,0 +1,3 @@ +#!flask/bin/python +from app import myapp +myapp.run(debug=True,host='0.0.0.0')