Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ MY_NAME="Jon Snow"

## Usage

### Background Service

From within the virtual environment, ensure you can run each of the following files and see them produce their desired results of: printing today's weather forecast, and sending an example email, respectively.

```sh
Expand All @@ -66,3 +68,13 @@ python -m app.daily_briefing # note the module-syntax invocation
```

![](https://user-images.githubusercontent.com/1328807/77860069-173ef580-71db-11ea-83c6-5897bb9f4f51.png)

### Web App

Run the app:

```sh
FLASK_APP=web_app flask run
```

Then visit localhost:5000 in the browser!
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
python-dotenv
requests
sendgrid==6.0.5

Flask
23 changes: 23 additions & 0 deletions web_app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# web_app/__init__.py

import os
from dotenv import load_dotenv
from flask import Flask

from web_app.routes.home_routes import home_routes
from web_app.routes.weather_routes import weather_routes

load_dotenv()

SECRET_KEY = os.getenv("SECRET_KEY", default="super secret")

def create_app():
app = Flask(__name__)
app.config["SECRET_KEY"] = SECRET_KEY
app.register_blueprint(home_routes)
app.register_blueprint(weather_routes)
return app

if __name__ == "__main__":
my_app = create_app()
my_app.run(debug=True)
34 changes: 34 additions & 0 deletions web_app/routes/home_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

# web_app/routes/home_routes.py

from flask import Blueprint, render_template, flash, redirect, request

home_routes = Blueprint("home_routes", __name__)

@home_routes.route("/")
def index():
print("VISITED THE HOME PAGE...")
#return "Welcome Home (TODO)"
return render_template("home.html")

@home_routes.route("/about")
def about():
print("VISITED THE ABOUT PAGE...")
#return "About Me (TODO)"
return render_template("about.html")

@home_routes.route("/users/new")
def register():
print("VISITED THE NEW USER REGISTRATION PAGE...")
#return "Sign Up for our Product! (TODO)"
return render_template("registration_form.html")

@home_routes.route("/users/create", methods=["POST"])
def create_user():
print("CREATING A NEW USER...")
print("FORM DATA:", dict(request.form)) #> {'full_name': 'Example User', 'email_address': 'me@example.com', 'country': 'US'}
user = dict(request.form)
# todo: store in a database or google sheet!
#flash(f"User '{user['full_name']}' created successfully!", "success")
flash(f"User '{user['full_name']}' created successfully! (TODO)", "warning")
return redirect("/")
28 changes: 28 additions & 0 deletions web_app/routes/weather_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

# web_app/routes/home_routes.py

from flask import Blueprint, render_template, request

from app.weather_service import get_hourly_forecasts

weather_routes = Blueprint("weather_routes", __name__)

@weather_routes.route("/weather/form")
def weather_form():
print("VISITED THE WEATHER FORM...")
return render_template("weather_form.html")

@weather_routes.route("/weather/forecast", methods=["GET", "POST"])
def weather_forecast():
print("GENERATING A WEATHER FORECAST...")

if request.method == "POST":
print("FORM DATA:", dict(request.form)) #> {'zip_code': '20057'}
zip_code = request.form["zip_code"]
elif request.method == "GET":
print("URL PARAMS:", dict(request.args))
zip_code = request.args["zip_code"]

results = get_hourly_forecasts(zip_code)
print(results.keys())
return render_template("weather_forecast.html", zip_code=zip_code, results=results)
10 changes: 10 additions & 0 deletions web_app/templates/about.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{% extends "layout_bootstrap.html" %}
{% set active_page = "about" %}

{% block content %}

<h2>About</h2>

<p>This is a description of the app. Lorum ipsum.</p>

{% endblock %}
9 changes: 9 additions & 0 deletions web_app/templates/home.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% extends "layout_bootstrap.html" %}

{% block content %}

<h2>Home</h2>

<p>Welcome to my app! Lorum ipsum.</p>

{% endblock %}
37 changes: 37 additions & 0 deletions web_app/templates/layout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!doctype html>
<html>
<head>
{% block title %}
<title>My Starter Web App | Helps students learn how to use the Flask Python package.</title>
{% endblock %}
</head>

<body>

<!-- SITE NAVIGATION -->
<div class="container">
<div id="nav">
<h1><a href="/">My Web App</a></h1>
<ul>
<li><a href="/about">About</a></li>
<li><a href="/register">Sign Up</a></li>
</ul>
</div>
<hr>

<!-- PAGE CONTENTS -->
<div id="content">
{% block content %}
{% endblock %}
</div>

<!-- FOOTER -->
<div id="footer">
<hr>
&copy; Copyright 2019 Prof. MJ Rossetti |
<a href="https://github.com/prof-rossetti/">source</a>
</div>
</div>

</body>
</html>
87 changes: 87 additions & 0 deletions web_app/templates/layout_bootstrap.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<!doctype html>
<html>
<head>
{% block title %}
<title>My Starter Web App | Helps students learn how to use the Flask Python package.</title>
{% endblock %}

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>

<body>

<!-- FLASH MESSAGING -->
<!-- see: http://flask.pocoo.org/docs/1.0/patterns/flashing/#flashing-with-categories -->
<!-- see: https://getbootstrap.com/docs/4.3/components/alerts/ -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }} alert-dismissible" role="alert" style="margin-bottom:0px;">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}

<!-- SITE NAVIGATION -->
<!-- see: https://jinja.palletsprojects.com/en/2.11.x/tricks/ -->
<!-- see: https://getbootstrap.com/docs/4.0/components/navbar/ -->
{% set nav_links = [
('/about', 'about', 'About'),
('/weather/form', 'weather_form', 'Weather'),
('/users/new', 'new_user', 'Sign Up')
] -%}
{% set active_page = active_page|default('index') -%}
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<a class="navbar-brand" href="/">My Web App</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<ul class="nav navbar-nav ml-auto">
{% for href, id, link_text in nav_links %}
{% if id == active_page %}
{% set is_active = "active" -%}
{% else %}
{% set is_active = "" -%}
{% endif %}
<li class="nav-item">
<a class="nav-link {{ is_active }}" href="{{href}}">{{link_text}}</a>
</li>
{% endfor %}
</div>
</ul>
</nav>


<div class="container" style="margin-top:2em;">
<!-- PAGE CONTENTS -->
<div id="content">
{% block content %}
{% endblock %}
</div>

<!-- FOOTER -->
<div id="footer">
<hr>
&copy; Copyright 2019 Prof. MJ Rossetti |
<a href="https://github.com/prof-rossetti/">source</a>
</div>
</div>

<!-- JAVASCRIPT SECTION -->
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<script type="text/javascript">

console.log("Thanks for the page visit!")

// closes data-dismiss="alert" flash messages
// see: https://getbootstrap.com/docs/4.3/components/alerts/#javascript-behavior
//$().alert('close')

</script>
</body>
</html>
31 changes: 31 additions & 0 deletions web_app/templates/registration_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{% extends "layout_bootstrap.html" %}
{% set active_page = "register" %}

{% block content %}

<h2>New User Registration</h2>

<p>Sign up for daily weather report emails using the form below...</p>

<form action="/users/create" method="POST">

<label>Full Name:</label>
<input type="text" name="full_name" placeholder="Example User" value="Example User">
<br>

<label>Email Address:</label>
<input type="text" name="email_address" placeholder="me@example.com" value="me@example.com">
<br>

<label>Country:</label>
<select name="country">
<option value="US" selected="true">United States</option>
<option value="UK">United Kingdom</option>
<option value="Japan">Japan</option>
<option value="UAE">United Arab Emirates</option>
</select>
<br>

<button>Submit</button>
</form>
{% endblock %}
18 changes: 18 additions & 0 deletions web_app/templates/weather_forecast.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{% extends "layout_bootstrap.html" %}

{% block content %}

<h2>Weather Forecast for {{ results["city_name"].title() }}</h2>

<p>Zip Code: {{ zip_code }}</p>

<!-- TODO: consider using a table instead of a list -->
<!-- https://www.w3schools.com/html/html_tables.asp -->
<!-- https://getbootstrap.com/docs/4.0/content/tables/ -->
<ul>
{% for hourly in results["hourly_forecasts"] %}
<li>{{ hourly["timestamp"] }} | {{ hourly["temp"] }} | {{ hourly["conditions"].upper() }}</li>
{% endfor %}
</ul>

{% endblock %}
19 changes: 19 additions & 0 deletions web_app/templates/weather_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{% extends "layout_bootstrap.html" %}
{% set active_page = "weather_form" %}

{% block content %}

<h2>Weather Form</h2>

<p>Request an hourly forecast for your zip code...</p>

<form action="/weather/forecast" method="POST">

<label>Zip Code:</label>
<input type="text" name="zip_code" placeholder="20057" value="20057">
<br>

<button>Submit</button>
</form>

{% endblock %}