-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Liam Bates
committed
Mar 9, 2019
1 parent
be88b20
commit 53bfd1f
Showing
10 changed files
with
170 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,9 @@ | ||
""" Helpful functions used in the auto_maint app. """ | ||
import datetime | ||
import os | ||
import smtplib | ||
from email.message import EmailMessage | ||
from functools import wraps | ||
|
||
from flask import redirect, render_template, session | ||
|
||
from auto_maint import app | ||
from auto_maint.models import User | ||
from flask import redirect, session | ||
|
||
|
||
def login_required(f): | ||
|
@@ -27,7 +22,7 @@ def decorated_function(*args, **kwargs): | |
return decorated_function | ||
|
||
|
||
def email(message): | ||
def send_email(message): | ||
""" Sends the provided email message using SMTP. """ | ||
# Send message to the email server. | ||
server = smtplib.SMTP(os.environ['SMTP_SERVER']) | ||
|
@@ -37,40 +32,6 @@ def email(message): | |
server.quit() | ||
|
||
|
||
def notify_users(): | ||
""" Routine script to send email notifications when a vehicle is overdue | ||
maintenance. """ | ||
# Context to access DB from function | ||
with app.app_context(): | ||
print("NOTIFY USERS RUNNING") | ||
for user in User.query.all(): | ||
for user_vehicle in user.vehicles: | ||
status = user_vehicle.status() | ||
if 'Soon' in status or 'Overdue' in status: | ||
if user_vehicle.last_notification: | ||
days_since = datetime.datetime.today( | ||
) - user_vehicle.last_notification | ||
if days_since < datetime.timedelta(days=3): | ||
continue | ||
|
||
# Generate Email message to send | ||
msg = EmailMessage() | ||
msg['Subject'] = 'Your vehicle is due maintenance' | ||
msg['From'] = '[email protected]' | ||
msg['To'] = user.email | ||
|
||
# Generate HTML for email | ||
html = render_template( | ||
'email/reminder.html', vehicle=user_vehicle) | ||
msg.set_content(html, subtype='html') | ||
|
||
# Send email | ||
email(msg) | ||
|
||
# Update DB to with timestamp | ||
user_vehicle.notification_sent() | ||
|
||
|
||
def standard_schedule(vehicle): | ||
# Based on a 2001 Honda Accord | ||
vehicle.add_maintenance( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,11 @@ | ||
""" auto_maint app models defined """ | ||
import datetime | ||
from email.message import EmailMessage | ||
|
||
from flask import session | ||
from flask import render_template, session, url_for | ||
|
||
from auto_maint import db | ||
from auto_maint import db, ts | ||
from auto_maint.helpers import send_email | ||
|
||
|
||
class User(db.Model): | ||
|
@@ -15,6 +17,7 @@ class User(db.Model): | |
name = db.Column(db.String(64), nullable=False) | ||
failed_logins = db.Column(db.SmallInteger, default=0, nullable=False) | ||
blocked = db.Column(db.Boolean, default=False, nullable=False) | ||
email_confirmed = db.Column(db.Boolean, default=False, nullable=False) | ||
vehicles = db.relationship('Vehicle', cascade='all,delete', backref='user') | ||
|
||
def __init__(self, email, password_hash, name): | ||
|
@@ -45,6 +48,26 @@ def failed_login(self): | |
# Commit to db | ||
db.session.commit() | ||
|
||
def verification_email(self): | ||
""" Send the user a welcome email with a verification link. """ | ||
# Generate Email message to send | ||
msg = EmailMessage() | ||
msg['Subject'] = 'Welcome to Auto Maintenance!' | ||
msg['From'] = '[email protected]' | ||
msg['To'] = self.email | ||
|
||
# Generate email confirmation token and URL | ||
token = ts.dumps(self.email, salt='email-confirm-key') | ||
confirm_url = url_for('confirm_email', token=token, _external=True) | ||
|
||
# Generate HTML for email | ||
html = render_template( | ||
'email/welcome.html', user=self, confirm_url=confirm_url) | ||
msg.set_content(html, subtype='html') | ||
|
||
# Send email | ||
send_email(msg) | ||
|
||
def delete(self): | ||
""" Method to delete the current vehicle object from the DB. """ | ||
db.session.delete(self) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import datetime | ||
from email.message import EmailMessage | ||
|
||
from flask import render_template | ||
|
||
from auto_maint import app | ||
from auto_maint.helpers import send_email | ||
from auto_maint.models import User | ||
|
||
|
||
def notify_users(): | ||
""" Routine script to send email notifications when a vehicle is overdue | ||
maintenance. """ | ||
# Context to access DB from function | ||
with app.app_context(): | ||
print("NOTIFY USERS RUNNING") | ||
for user in User.query.all(): | ||
for user_vehicle in user.vehicles: | ||
status = user_vehicle.status() | ||
if 'Soon' in status or 'Overdue' in status: | ||
if user_vehicle.last_notification: | ||
days_since = datetime.datetime.today( | ||
) - user_vehicle.last_notification | ||
if days_since < datetime.timedelta(days=3): | ||
continue | ||
|
||
# Generate Email message to send | ||
msg = EmailMessage() | ||
msg['Subject'] = 'Your vehicle is due maintenance' | ||
msg['From'] = '[email protected]' | ||
msg['To'] = user.email | ||
|
||
# Generate HTML for email | ||
html = render_template( | ||
'email/reminder.html', vehicle=user_vehicle) | ||
msg.set_content(html, subtype='html') | ||
|
||
# Send email | ||
send_email(msg) | ||
|
||
# Update DB to with timestamp | ||
user_vehicle.notification_sent() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,16 @@ | ||
""" Auto Maintenance views. Also features GET routes for the deletion of | ||
objects. """ | ||
from email.message import EmailMessage | ||
|
||
from flask import flash, jsonify, redirect, render_template, request, session | ||
from werkzeug.security import generate_password_hash | ||
|
||
from auto_maint import app, db | ||
from auto_maint.forms import ( | ||
AddVehicleForm, EditMaintenanceForm, EditVehicleForm, LoginForm, | ||
NewLogForm, NewMaintenanceForm, NewOdometerForm, RegistrationForm, | ||
UpdateEmail, UpdateName, UpdatePassword) | ||
from auto_maint.helpers import email, login_required, standard_schedule | ||
from auto_maint import app, db, ts | ||
from auto_maint.forms import (AddVehicleForm, EditMaintenanceForm, | ||
EditVehicleForm, LoginForm, NewLogForm, | ||
NewMaintenanceForm, NewOdometerForm, | ||
RegistrationForm, UpdateEmail, UpdateName, | ||
UpdatePassword) | ||
from auto_maint.helpers import login_required, standard_schedule | ||
from auto_maint.models import Log, Maintenance, Odometer, User, Vehicle | ||
|
||
|
||
|
@@ -48,24 +48,16 @@ def index(): | |
generate_password_hash(registration_form.password.data), | ||
registration_form.name.data) | ||
# Flash thank you message | ||
flash('Account succesfully created.', 'success') | ||
flash( | ||
"""Account succesfully created. Please check your email and | ||
confirm your email address using the link provided in the email.""", | ||
'success') | ||
|
||
# Start a new user session | ||
session["user_id"] = user.user_id | ||
# Save to DB | ||
db.session.commit() | ||
|
||
# Generate Email message to send | ||
msg = EmailMessage() | ||
msg['Subject'] = 'Welcome to Auto Maintenance!' | ||
msg['From'] = '[email protected]' | ||
msg['To'] = user.email | ||
|
||
# Generate HTML for email | ||
html = render_template('email/welcome.html', user=user) | ||
msg.set_content(html, subtype='html') | ||
|
||
# Send email | ||
email(msg) | ||
# Send the user a welcome / verification email | ||
user.verification_email() | ||
|
||
# Confirm to browser that all okay | ||
return jsonify(status='ok') | ||
|
@@ -79,6 +71,35 @@ def index(): | |
'index.html', login_form=login_form, reg_form=registration_form) | ||
|
||
|
||
@app.route('/confirm/<token>') | ||
def confirm_email(token): | ||
""" Takes the email confirmation token from the user and updates the DB to | ||
reflect the confirmation. """ | ||
# Attempt to confirm confirmation token otherwise flash error | ||
try: | ||
user_email = ts.loads(token, salt="email-confirm-key", max_age=86400) | ||
except: | ||
flash('Unknown or outdated email confirmation.', 'danger') | ||
return redirect('/') | ||
|
||
# Find user in DB by email | ||
user = User.query.filter(User.email == user_email).first() | ||
|
||
# Set user's email confirmed value to true | ||
user.email_confirmed = True | ||
|
||
flash('Thank you for confirming your email address.', 'success') | ||
|
||
# Log the user in | ||
session["user_id"] = user.user_id | ||
|
||
# Save to DB | ||
db.session.commit() | ||
|
||
# Send user to home page | ||
return home() | ||
|
||
|
||
@app.route('/home', methods=['POST', 'GET']) | ||
@login_required | ||
def home(): | ||
|
@@ -99,7 +120,7 @@ def home(): | |
'success') | ||
# Confirm to browser that all okay | ||
return jsonify(status='ok') | ||
# Query db for users info and vehicles | ||
# Query DB for users info and vehicles | ||
vehicles = Vehicle.query.filter( | ||
Vehicle.user_id == session["user_id"]).all() | ||
user = User.query.filter(User.user_id == session["user_id"]).first() | ||
|
@@ -114,7 +135,7 @@ def vehicle(vehicle_id): | |
""" Provides an overview of a vehicle record and allows posting of new | ||
odometer readings. """ | ||
|
||
# Pull vehicle from db using id | ||
# Pull vehicle from DB using id | ||
lookup_vehicle = Vehicle.query.filter( | ||
Vehicle.vehicle_id == vehicle_id).first() | ||
|
||
|
@@ -193,7 +214,7 @@ def vehicle(vehicle_id): | |
def delete_vehicle(vehicle_id): | ||
""" Takes a URL and deletes the vehicle, by the ID provided. """ | ||
|
||
# Query the db for a matching vehicle | ||
# Query the DB for a matching vehicle | ||
del_vehicle = Vehicle.query.filter_by(vehicle_id=vehicle_id).first() | ||
|
||
# Test whatever was returned to see if the vehicle is owned by the user | ||
|
@@ -213,7 +234,7 @@ def delete_vehicle(vehicle_id): | |
def delete_odometer(reading_id): | ||
""" Takes a URL and deletes the odometer, by the ID provided. """ | ||
|
||
# Query the db for a matching vehicle | ||
# Query the DB for a matching vehicle | ||
del_odom = Odometer.query.filter_by(reading_id=reading_id).first() | ||
|
||
# Test whatever was returned to see if the vehicle is owned by the user | ||
|
@@ -237,7 +258,7 @@ def delete_odometer(reading_id): | |
def maintenance(maintenance_id): | ||
""" Shows a details of a particular scheduled maintenance event and allows | ||
the user to create log entries for that task when performed. """ | ||
# Pull vehicle, maintenance and user reocrds from db using id | ||
# Pull vehicle, maintenance and user reocrds from DB using id | ||
lookup_maintenance = Maintenance.query.filter( | ||
Maintenance.maintenance_id == maintenance_id).first() | ||
|
||
|
@@ -293,7 +314,7 @@ def maintenance(maintenance_id): | |
def delete_maintenance(maintenance_id): | ||
""" Takes a URL and deletes the vehicle, by the ID provided. """ | ||
|
||
# Query the db for a matching vehicle | ||
# Query the DB for a matching vehicle | ||
del_maintenance = Maintenance.query.filter_by( | ||
maintenance_id=maintenance_id).first() | ||
|
||
|
@@ -313,7 +334,7 @@ def delete_maintenance(maintenance_id): | |
def delete_log(log_id): | ||
""" Takes a URL and deletes the log entry, by the ID provided. """ | ||
|
||
# Query the db for a matching vehicle | ||
# Query the DB for a matching vehicle | ||
del_log = Log.query.filter_by(log_id=log_id).first() | ||
|
||
# Test whatever was returned to see if the vehicle is owned by the user | ||
|
Oops, something went wrong.