This is using a template
I built this website using Bootstap for the front end, and Flask (a python package) for the back end. I started by taking classes on HTML, CSS, Bootstrap, and Jinja2 on Codecademy. I deployed the site using Nginx and Gunicorn on a Linode server.
You can check out the source code below.
This is the main file that handles all of the routing between webpages and sending of emails through the contact page.
from flask import Flask, render_template, url_for, flash, redirect
from forms import RegistrationForm
import smtplib, ssl
port = 465 # For SSL
smtp_server = "smtp.gmail.com"
sender_email = "******************@gmail.com"
receiver_email = "cole.domenico1997@gmail.com"
password = "********"
app = Flask(__name__)
app.config['SECRET_KEY'] = '***********'
@app.route("/home")
@app.route("/")
def home():
return render_template('home.html')
@app.route("/esra")
def esra():
return render_template('esra.html', title = "ESRA Overview")
@app.route("/daq")
def daq():
return render_template('daq.html', title = "ESRA DAQ Project")
@app.route("/watering")
def watering():
return render_template('watering.html', title = "Automated Water and Sunlight System")
@app.route("/website")
def website():
return render_template('website.html', title = "This Website!")
@app.route("/cnc_mill")
def mill():
return render_template('cnc_mill.html', title = "CNC Mill")
@app.route("/woodworking")
def woodworking():
return render_template('woodworking.html', title = "Woodworking")
@app.route("/nixie")
def nixie():
return render_template('nixie.html', title = "Nixie Clock")
@app.route("/contact",methods=['GET', 'POST'])
def contact():
form = RegistrationForm()
if form.validate_on_submit():
flash(f'Email sent!','success')
context = ssl.create_default_context()
with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:
server.login(sender_email, password)
message = "Subject: Website message: " + str(form.subject.data) + "\n\n" + str(form.message.data) + "\n\n From: " + str(form.email.data)
server.sendmail(sender_email, receiver_email, message)
return redirect(url_for('home'))
return render_template('contact.html', title='Contact', form=form)
if __name__ == '__main__':
app.run(debug=False)
The layout.html file contains the content that is displayed on every page such as the top navigation bar, tab titles, styling, and notifications.
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="/static/main.css">
<script defer src="https://use.fontawesome.com/releases/v5.0.13/js/solid.js" integrity="sha384-tzzSw1/Vo+0N5UhStP3bvwWPq+uvzCMfrN1fEFe+xBmv1C/AtVX5K0uZtmcHitFZ" crossorigin="anonymous"></script>
<script defer src="https://use.fontawesome.com/releases/v5.0.13/js/fontawesome.js" integrity="sha384-6OIrr52G08NpOFSZdxxz1xdNSndlD4vdcf/q2myIUVO0VsqaGHJsB0RaBE01VTOY" crossorigin="anonymous"></script>
{% if title %}
<title>Cole's Projects - {{title}}</title>
{%else %}
<title>Cole's Projects </title>
{% endif %}
</head>
<body>
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-dark" id="navbar">
<a class="navbar-brand" href="/home">Cole's Projects</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavDropdown">
<ul class="navbar-nav">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
ESRA
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<a class="dropdown-item" href="/esra">Project Overview</a>
<a class="dropdown-item" href="/daq">Data Acquisition System</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="/cnc_mill">CNC Mill</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/watering">Automated Irrigation</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/website">Website</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/static/media/Domenico_Cole_Resume.pdf" target="_blank">Resume</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://www.linkedin.com/in/cole-domenico/">LinkedIn</a>
</li>
</ul>
</div>
</nav>
<p>This is using a template</p>
<div class="container">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}" style="margin-top:3em;">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</div>
<!-- End of row with nav component -->
<!-- Bootstrap JavaScript Libraries -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
crossorigin="anonymous"></script>
</html>
The forms.py file handles the user input for the contact page and passes that information to main.py.
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, Email, EqualTo
class RegistrationForm(FlaskForm):
email = StringField('Email',validators=[DataRequired(), Email()])
confirm_email = StringField('Confirm email',validators=[EqualTo('email')])
subject = StringField('Subject')
message = StringField('Message', validators=[DataRequired()])
submit = SubmitField('Send')
The contact.html page displays the forms, setup in the forms.py file, as well as any error messages. Examples of error messages might include an invalid email, emails that do not match, or an empty message box.
{%extends "layout.html" %}
{% block content %}
<div class="content-section" style="margin-top:2em;">
<form action="" method="post">
{{form.hidden_tag()}}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Contact Me!</legend>
<div class="form-group">
{{form.email.label(class="form-control-label")}}
{% if form.email.errors %}
{{ form.email(class="form-control form-control-lg is-invalid")}}
<div class="invalid-feedback">
{% for error in form.email.errors %}
<span> {{ error }} </span>
{% endfor %}
</div>
{% else %}
{{form.email(class="form-control form-control-lg")}}
{% endif %}
</div>
<div class="form-group">
{{form.confirm_email.label(class="form-control-label")}}
{% if form.confirm_email.errors %}
{{ form.confirm_email(class="form-control form-control-lg is-invalid")}}
<div class="invalid-feedback">
{% for error in form.confirm_email.errors %}
<span> {{ error }} </span>
{% endfor %}
</div>
{% else %}
{{form.confirm_email(class="form-control form-control-lg")}}
{% endif %}
</div>
<div class="form-group">
{{form.subject.label(class="form-control-label")}}
{% if form.subject.errors %}
{{ form.subject(class="form-control form-control-lg is-invalid")}}
<div class="invalid-feedback">
{% for error in form.subject.errors %}message
<span> {{ error }} </span>
{% endfor %}
</div>
{% else %}
{{form.subject(class="form-control form-control-lg")}}
{% endif %}
</div>
<div class="form-group">
{{form.message.label(class="form-control-label")}}
{% if form.message.errors %}
{{ form.message(class="form-control form-control-lg is-invalid")}}
<div class="invalid-feedback">
{% for error in form.message.errors %}
<span> {{ error }} </span>
{% endfor %}
</div>
{% else %}
{{form.message(class="form-control form-control-lg")}}
{% endif %}
</div>
</fieldset>
<div class="form-group">
{{form.submit(class="btn btn-outline-info")}}
</div>
</form>
</div>
{% endblock content %}