A => .gitignore +267 -0
@@ 1,267 @@
+# Created by https://www.toptal.com/developers/gitignore/api/python,flask
+# Edit at https://www.toptal.com/developers/gitignore?templates=python,flask
+
+uploads/
+### Flask ###
+instance/*
+!instance/.gitignore
+.webassets-cache
+.env
+
+### Flask.Python Stack ###
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
+
+### Python ###
+# Byte-compiled / optimized / DLL files
+
+# C extensions
+
+# Distribution / packaging
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+
+# Installer logs
+
+# Unit test / coverage reports
+
+# Translations
+
+# Django stuff:
+
+# Flask stuff:
+
+# Scrapy stuff:
+
+# Sphinx documentation
+
+# PyBuilder
+
+# Jupyter Notebook
+
+# IPython
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+
+# Celery stuff
+
+# SageMath parsed files
+
+# Environments
+
+# Spyder project settings
+
+# Rope project settings
+
+# mkdocs documentation
+
+# mypy
+
+# Pyre type checker
+
+# pytype static type analyzer
+
+# Cython debug symbols
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+
+### Python Patch ###
+# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
+poetry.toml
+
+# ruff
+.ruff_cache/
+
+# LSP config files
+pyrightconfig.json
+
+# End of https://www.toptal.com/developers/gitignore/api/python,flask
+
+# Configuration file
+%APPNAME%/config.py
+.env
A => Makefile +45 -0
@@ 1,45 @@
+SHELL := /bin/bash
+all: clean
+
+# Clean up temp files
+#------------------------------------------------------------------
+clean:
+ @echo "Cleaning up temp files"
+ @find . -name '*~' -ls -delete
+ @find . -name '*.bak' -ls -delete
+ @echo "Cleaning up __pycache__ directories"
+ @find . -name __pycache__ -type d -not -path "./.venv/*" -ls -exec rm -r {} +
+ @echo "Cleaning up logfiles"
+ @find ./logs -name '*.log*' -ls -delete
+ @echo "Cleaning up flask_session"
+ @find . -name flask_session -type d -not -path "./.venv/*" -ls -exec rm -r {} +
+
+init_env:
+ python3 -m venv .venv
+ source .venv/bin/activate && pip3 install --upgrade pip
+ source .venv/bin/activate && pip3 install -r requirements.txt txt
+
+upgrade_env:
+ source .venv/bin/activate && pip3 install --upgrade -r requirements.txt
+
+make_migrations:
+ source .venv/bin/activate && flask db migrate
+
+run_migrations:
+ source .venv/bin/activate && flask db upgrade
+
+daemon:
+ @echo "--- STARTING UWSGI DAEMON ---"
+ @echo ""
+ @echo ""
+ source .venv/bin/activate && FLASK_DEBUG=True flask run
+ @echo ""
+ @echo ""
+ @echo "--- STARTING UWSGI DAEMON ---"
+
+
+post_upgrade: upgrade_env run_migrations
+ # Make sure a tmp directory exists
+ @mkdir -p %APPNAME%/tmp
+ # Create upload directory
+ @mkdir -p %APPNAME%/uploads
A => README.md +12 -0
@@ 1,12 @@
+# Template app created with create-flask-app
+
+## Makefile
+This project comes with a helpful Makefile! The following recipes may help with
+development and deployment:
+
+- `init_env`: Creates a new virtual environment in `.venv`
+- `upgrade_env`: Installs updated versions of the packages in `requirements.txt`
+to your virtual environment
+- `run_migrations`: Runs any unapplied migrations
+- `post_upgrade`: Runs `upgrade_env` and `run_migrations`, as well as making
+sure that required directories exist
A => appname/__init__.py +32 -0
@@ 1,32 @@
+from flask import Flask
+import os
+from flask_sqlalchemy import SQLAlchemy
+from flask_migrate import Migrate
+from flask_login import LoginManager
+from flask_bootstrap import Bootstrap5
+
+from werkzeug.middleware.proxy_fix import ProxyFix
+
+db = SQLAlchemy()
+migrate = Migrate()
+login = LoginManager()
+bootstrap = Bootstrap5()
+
+
+def create_app():
+ app = Flask(__name__)
+
+ app.wsgi_app = ProxyFix(app.wsgi_app)
+
+ app.config.from_pyfile('config.py')
+
+ db.init_app(app)
+ migrate.init_app(app, db)
+ login.init_app(app)
+ bootstrap.init_app(app)
+
+
+ from .models import User
+
+ return app
+
A => appname/config.py +4 -0
@@ 1,4 @@
+SQLALCHEMY_DATABASE_URI="postgresql://localhost/%APPNAME%"
+SECRET_KEY="bad-key-change-me"
+DEBUG=True
+
A => appname/models.py +28 -0
@@ 1,28 @@
+from flask import flash, redirect, url_for
+from flask_login import UserMixin
+from sqlalchemy import Boolean, Column, Date, DateTime, ForeignKey, Integer, String, null
+import csv
+from . import db
+from . import login
+
+class User(db.Model, UserMixin):
+ __tablename__ = "%APPSHORT%_users"
+ id = Column(String, primary_key=True)
+ email = Column(String, unique=True, nullable=True)
+ password = Column(String, nullable=False)
+ first_name = Column(String, nullable=False)
+ last_name = Column(String, nullable=False)
+ created = Column(DateTime, nullable=False)
+ last_login = Column(DateTime, nullable=False)
+ active = Column(Boolean, nullable=False, default=True)
+ is_admin = Column(Boolean, nullable=False, default=False)
+
+
+@login.user_loader
+def user_loader(user_id):
+ return User.query.filter_by(id=user_id).first()
+
+@login.unauthorized_handler
+def unauth():
+ flash("Please log in first!")
+ return redirect("/")
A => requirements.txt +9 -0
@@ 1,9 @@
+Flask
+Flask-Login
+Flask-SQLAlchemy
+Flask-Migrate
+psycopg2
+ulid
+WTForms
+flask_wtf
+Bootstrap-Flask
A => wsgi.py +3 -0
@@ 1,3 @@
+from %APPNAME% import create_app
+
+application = create_app()