""" routes.py module ---------------- This Python module contains the logic supporting: 1. Navigating between website pages 2. Interpreting user requests to the server 3. Dispatching requested content back to the user Python dependencies: - flask: provides web application features - forms: provides secure user form submission - sqlalchemy: provides communication with database on server. Personal imports: These are used to avoid cluttering this file with placeholder data for posts' content. """ from flask import Flask, render_template, request, redirect, flash, url_for, jsonify from flask_sqlalchemy import SQLAlchemy from flask_bootstrap import Bootstrap from flask_wtf import FlaskForm from wtforms import ( SubmitField, SelectField, RadioField, HiddenField, StringField, IntegerField, FloatField, ) from wtforms.validators import InputRequired, Length, Regexp, NumberRange from datetime import datetime import placeholders as p app = Flask(__name__) # Flask-Bootstrap requires this line Bootstrap(app) # Flask-WTF encryption key app.config["SECRET_KEY"] = "Scooby_Lu,_where_are_you?" # Our database name db_name = "fapg.db" app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + db_name app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True db = SQLAlchemy(app) class Users(db.Model): id = db.Column(db.Integer, primary_key=True) name_first = db.Column(db.String(20), nullable=False) name_last = db.Column(db.String(20), nullable=False) email = db.Column(db.String(20), nullable=False) phone_mobile = db.Column(db.Integer, nullable=False) phone_alternative = db.Column(db.Integer) updated = db.Column(db.String) def __init__( self, name_first, name_last, email, phone_mobile, phone_alternative, updated ): self.name_first = name_first self.name_last = name_last self.email = email self.phone_mobile = phone_mobile self.phone_alternative = phone_alternative self.updated = updated def __repr__(self): return f"" class Products(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(20), nullable=False) supplier = db.Column(db.String(20), nullable=False) price = db.Column(db.Float(10), nullable=False) updated = db.Column(db.String) def __init__(self, name, supplier, price, updated): self.name = name self.supplier = supplier self.price = price self.updated = updated def __repr__(self): return f"" class Projects(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(20), nullable=False) name_full = db.Column(db.String(20), nullable=False) nickname = db.Column(db.String(20), nullable=False) city = db.Column(db.String(20), nullable=False) def __repr__(self): return f"" class Modules(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(20), unique=True, nullable=False) description = db.Column(db.String(50), nullable=False) def __init__(self, name, description, updated): self.name = name self.description = description self.updated = updated def __repr__(self): return f"" class AddProduct(FlaskForm): # id used only by update/edit id = HiddenField() name = StringField("Product name", validators=[InputRequired()]) supplier = SelectField( "Choose a supplier", choices=[ ("", ""), ("Mister Brown", "Mister Brown"), ("Madame Cerise", "Madame Cerise"), ("Biton la Malice", "G. Biton la Malice"), ("Leroy Merlin", "Leroy Merlin"), ("other", "Other"), ], ) price = FloatField("Retail price per unit") # updated - date - handled in the route function updated = HiddenField() submit = SubmitField("Add/Update Product") # add a new product to the database @app.route("/add_product", methods=["GET", "POST"]) def add_product(): form = AddProduct() if form.validate_on_submit(): name = request.form["name"] supplier = request.form["supplier"] price = request.form["price"] # get today's date from function, above all the routes updated = datetime.now().strftime("%Y-%m-%d %H:%M:%S") # the data to be inserted into FAPG model - the table, products record = Products(name, supplier, price, updated) # Flask-SQLAlchemy magic adds record to database db.session.add(record) db.session.commit() # create a message to send to the template message = f"The data for product {name} has been submitted." return render_template("add_product.html", message=message) else: # show validaton errors # see https://pythonprogramming.net/flash-flask-tutorial/ for field, errors in form.errors.items(): for error in errors: flash( "Error in {}: {}".format(getattr(form, field).label.text, error), "error", ) return render_template("add_product.html", form=form) @app.route("/") @app.route("/fapg/home") def project(): """This is our project welcome page.""" michel = Users( name_first="Michel", name_last="Peter", email="le-boss@fapg.com", phone_mobile="00000000", phone_alternative="0000000000", updated="2022-04-21", ) modules = Modules.query.all() print(module.name for module in modules) return render_template("home.html", user=michel, project=fapg, modules=modules) @app.route("/module/") def render_module(module): modules = Modules.query.all() catalog = Products.query.all() user_modules = [module.name for module in modules] print(user_modules) # If a module was purchased by a user and added to their database, # they have access to the corresponding module route. if module in user_modules: return render_template( f"modules/{module}.html", modules=modules, catalog=catalog, ) else: return render_template("errors/module-not-found.html", module=module) # If this file is executed as a script (i.e. double-clicked), # the Python interpreter will run the Flask process and begin serving # the web pages on the standard localhost address (127.0.0.1). # But if this file is called as a module by another Python script, it will not # serve content to the web pages, but the function definitions contained in # this file will be available to the calling script. # E.g. calling script will know what the yes() function is. if __name__ == "__main__": app.run(debug=True)