From 1374f36a6a2f1aeb29bb5227ad599b56d0296a1c Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Tue, 13 Jan 2026 10:06:00 +0000 Subject: [PATCH 01/25] tidy whitespace --- templates/layout.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/templates/layout.html b/templates/layout.html index ffdf242..2a093c7 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -17,10 +17,8 @@

{{ site.WebsiteName }}

{% else %}
  • Login
  • {% endif %} - -
    @@ -34,7 +32,6 @@

    {{ site.WebsiteName }}

    {% endblock %} From 6279ba13bd38e13642bdd252fc1dc3d74e9931a0 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Tue, 13 Jan 2026 10:16:51 +0000 Subject: [PATCH 02/25] Enhance privacy policy for Auth0 integration and clarify data collection practices --- templates/privacy.html | 89 ++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 20 deletions(-) diff --git a/templates/privacy.html b/templates/privacy.html index 106520c..4d60147 100644 --- a/templates/privacy.html +++ b/templates/privacy.html @@ -23,26 +23,45 @@

    2. Who We Are (Data Controller)

    3. The Information We Collect

    -

    We collect very limited personal information - when you log in using your GitHub or Google account:

    +{% if auth_provider == "Auth0" %} +

    We collect limited personal information when you log in using Auth0, our third-party authentication provider:

    • - Google/GitHub User - ID: When you log in using the third-party authentication service (Google or - GitHub), we retrieve your user name and ID number and store only your unique user ID number. This is a - persistent identifier provided - by the third party. + User ID: When you log in using Auth0 (which supports authentication via Google, GitHub, + or other identity providers), we receive and store your unique user ID from Auth0. This is a persistent + identifier that allows us to recognize you on subsequent visits. +
    • +
    • + Email Address: We receive your email address from Auth0 to identify your account. +
    • +
    • + Name: We may receive your name from Auth0 as provided by your chosen identity provider.
    • Session Data: We use a session cookie to maintain your logged-in status. This cookie - itself stores a secure, random string (session ID) that links back to your user ID & name on our server. The + stores a secure, random string (session ID) that links back to your user information on our server. The + data is only stored for the duration of your visit (session). +
    • +
    +

    We do not collect additional personal details such as location, browsing history, + or any other information beyond what is necessary for authentication and service provision.

    +{% else %} +

    We collect very limited personal information when you log in using your GitHub account:

    +
      +
    • + GitHub User ID: When you log in using GitHub authentication, we retrieve your + user name and ID number and store only your unique user ID number. This is a persistent identifier + provided by GitHub. +
    • +
    • + Session Data: We use a session cookie to maintain your logged-in status. This cookie + stores a secure, random string (session ID) that links back to your user ID & name on our server. The data is only stored for the duration of your visit (session).
    • -
    -

    We do not collect your - name, email address, profile picture, location, or any other personal details unless explicitly stated - here.

    +

    We do not collect your email address, profile picture, location, or any other personal + details unless explicitly stated here.

    +{% endif %}

    4. How We Use Your Information

    We use the collected information for the @@ -65,18 +84,40 @@

    4. How We Use Your Information

    analytics, or any other non-essential purpose.

    5. Third-Party Data Sharing

    -

    We use a third-party service for - authentication:

    +{% if auth_provider == "Auth0" %} +

    We use third-party services for authentication and these services process your data:

    +
      +
    • + Auth0 (by Okta): We use Auth0 as our authentication service provider. When you log in, + Auth0 handles the authentication process and provides us with your user ID, email, and name. Auth0 acts + as a data processor on our behalf. Auth0 may store additional information about your authentication sessions. + Please review the Auth0 Privacy Policy + for details on how they handle your data. +
    • +
    • + Identity Providers (Google, GitHub, etc.): When you choose to log in via Google, GitHub, + or another identity provider through Auth0, you interact with their services. These providers authenticate + your identity and share limited information with Auth0, which then shares it with us. Please review their + respective privacy policies: +
        +
      • Google Privacy Policy
      • +
      • GitHub Privacy Statement
      • +
      + + +

      We do not share your information with any other third parties for marketing or other purposes.

      +{% else %} +

      We use a third-party service for authentication:

      • - GitHub/Google: When you log in, you interact with their - services. They provide us with your unique user ID. Please review the GitHub Privacy - Statement or Google Privacy Policy for details on - how they handle your data. + GitHub: When you log in, you interact with GitHub's authentication service. + They provide us with your unique user ID and username. Please review the + GitHub Privacy Statement + for details on how they handle your data.
      -

      We do not share your information with any other - third parties.

      +

      We do not share your information with any other third parties.

      +{% endif %}

      6. Our Cookie Policy

      We only use strictly @@ -126,7 +167,15 @@

      7. Your Data Protection Rights

      UK Information Commissioner's Office (ICO) if you believe we have not handled your information correctly.

      +{% if auth_provider == "Auth0" %} +

      8. Data Retention

      +

      We retain your user ID, email, and name for as long as your account is active. If you wish to delete your + account and associated data, please contact us at the email address provided above.

      + +

      9. Updates to this Policy

      +{% else %}

      8. Updates to this Policy

      +{% endif %}

      We may update this policy from time to time. The latest version will always be posted on this page.

      {% endblock %} \ No newline at end of file From a3eca668b74811a1095a938dc06ca360edb525bb Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Tue, 13 Jan 2026 10:37:59 +0000 Subject: [PATCH 03/25] Fixing Render --- README.md | 111 +++++++++++++++++++++++++++++++++++++++++++++++++--- render.yaml | 31 ++++++++++----- 2 files changed, 128 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c4e9538..016fab7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - # Flask Todo App with Dual Authentication ![Python](https://img.shields.io/badge/Python-3.10-blue) @@ -186,10 +185,112 @@ Once you have your code how you want ## Deployment on Render -- Add `render.yaml` to repo -- Push to GitHub -- Create Blueprint on Render -- Add environment variables in Render dashboard +### Prerequisites + +1. **GitHub Repository**: Your code must be pushed to a GitHub repository +2. **Render Account**: Sign up at [render.com](https://render.com) (free tier available) +3. **Auth0 Application**: Configured with your production callback URL + +### Step 1: Prepare Your Repository + +Ensure your repository contains: +- `render.yaml` (blueprint configuration file) +- `requirements.txt` (Python dependencies) +- All application code pushed to GitHub + +### Step 2: Create a Blueprint on Render + +1. **Log in to Render Dashboard** + - Go to [dashboard.render.com](https://dashboard.render.com) + +2. **Create New Blueprint** + - Click the "New +" button in the top right + - Select "Blueprint" from the dropdown menu + - [Direct Link to Create Blueprint](https://dashboard.render.com/select-repo?type=blueprint) + +3. **Connect Your GitHub Repository** + - Click "Connect account" if this is your first time + - Authorize Render to access your GitHub repositories + - Search for and select `mr-eggleton/python-flask-todo` (or your fork) + - Click "Connect" + +4. **Review Blueprint Configuration** + - Render will detect your `render.yaml` file + - Review the services that will be created (web service, database, etc.) + - Give your blueprint instance a name (e.g., "flask-todo-app") + - Click "Apply" + +### Step 3: Configure Environment Variables + +After the blueprint is created, you need to add your environment variables: + +1. **Navigate to Your Web Service** + - In the Render dashboard, click on your web service + - Go to the "Environment" tab + +2. **Add Environment Variables** + - Click "Add Environment Variable" + - Add each variable from your `.env` file: + ``` + APP_SECRET_KEY= + AUTH0_DOMAIN=.auth0.com + AUTH0_CLIENT_ID= + AUTH0_CLIENT_SECRET= + AUTH0_CALLBACK_URL=https://.onrender.com/callback + ``` + - **Important**: Generate a NEW `APP_SECRET_KEY` for production (don't reuse your local one) + - **Note**: Do NOT set `OAUTHLIB_INSECURE_TRANSPORT` in production + - Click "Save Changes" + +3. **Automatic Deployment** + - Render will automatically build and deploy your application + - Wait for the build to complete (check the "Logs" tab) + - Your app will be available at `https://.onrender.com` + +### Step 4: Update Auth0 Settings + +1. **Add Production Callback URL** + - Go to [Auth0 Dashboard](https://manage.auth0.com) + - Navigate to your application settings + - Add to "Allowed Callback URLs": `https://.onrender.com/callback` + - Add to "Allowed Logout URLs": `https://.onrender.com/` + - Add to "Allowed Web Origins": `https://.onrender.com` + - Click "Save Changes" + +### Step 5: Test Your Deployment + +1. Visit your Render URL: `https://.onrender.com` +2. Click "Login" - should redirect to Auth0 +3. Complete authentication +4. Verify you can create and manage todos + +### Continuous Deployment + +Once set up, Render automatically deploys when you push to your main branch: + +1. Make changes to your code locally +2. Commit and push to GitHub: + ```bash + git add . + git commit -m "Your commit message" + git push origin main + ``` +3. Render detects the push and automatically rebuilds/redeploys +4. Monitor deployment progress in the Render dashboard + +### Troubleshooting + +- **Build Fails**: Check the "Logs" tab in Render dashboard for errors +- **Auth0 Redirect Error**: Verify callback URLs match exactly (including https://) +- **Environment Variables**: Ensure all required variables are set in Render +- **Database Issues**: Render free tier databases sleep after inactivity; first request may be slow + +### Useful Links + +- [Render Blueprint Documentation](https://render.com/docs/infrastructure-as-code) +- [Render Python Deployment Guide](https://render.com/docs/deploy-flask) +- [Render Environment Variables](https://render.com/docs/environment-variables) +- [Auth0 Production Checklist](https://auth0.com/docs/deploy-monitor/deploy/production-checklist) ## Things we are ignoring diff --git a/render.yaml b/render.yaml index 837f8ce..ed7197e 100644 --- a/render.yaml +++ b/render.yaml @@ -1,19 +1,32 @@ - services: - type: web name: flask-todo-app env: python plan: free - buildCommand: "pip install -r requirements.txt" - startCommand: "gunicorn app:app" + buildCommand: pip install -r requirements.txt + startCommand: gunicorn app:app envVars: + - key: PYTHON_VERSION + value: 3.10 + - key: OAUTHLIB_INSECURE_TRANSPORT + value: "0" - key: APP_SECRET_KEY + generateValue: true + - key: AUTH0_DOMAIN sync: false - - key: GITHUB_CLIENT_ID - sync: false - - key: GITHUB_CLIENT_SECRET - sync: false - - key: GOOGLE_CLIENT_ID + - key: AUTH0_CLIENT_ID sync: false - - key: GOOGLE_CLIENT_SECRET + - key: AUTH0_CLIENT_SECRET sync: false + - key: AUTH0_CALLBACK_URL + value: https://${RENDER_EXTERNAL_HOSTNAME}/callback + - key: DATABASE_URL + fromDatabase: + name: flask-todo-db + property: connectionString + +databases: + - name: flask-todo-db + databaseName: flask_todo + plan: free + region: oregon From 40e1081415761467d8b4539025228759738aa38b Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Tue, 13 Jan 2026 10:45:04 +0000 Subject: [PATCH 04/25] SQLite for now, postgress later --- POSTGRESQL_SETUP.md | 214 ++++++++++++++++++++++++++++++++++++++++++++ README.md | 17 ++-- render.yaml | 10 --- 3 files changed, 224 insertions(+), 17 deletions(-) create mode 100644 POSTGRESQL_SETUP.md diff --git a/POSTGRESQL_SETUP.md b/POSTGRESQL_SETUP.md new file mode 100644 index 0000000..7e25f0c --- /dev/null +++ b/POSTGRESQL_SETUP.md @@ -0,0 +1,214 @@ +# Migrating to PostgreSQL + +This guide explains how to upgrade your Flask Todo App from SQLite to PostgreSQL for production use on Render. + +## Why Migrate to PostgreSQL? + +- **Reliability**: SQLite is file-based and not ideal for production web apps +- **Concurrency**: PostgreSQL handles multiple concurrent users better +- **Scalability**: Better performance as your app grows +- **Data Persistence**: Render's free PostgreSQL databases are more stable than file-based SQLite + +## When to Migrate + +- Your app is getting real users +- You need guaranteed data persistence +- You're moving beyond testing/development + +## Prerequisites + +- Existing Flask Todo App deployed on Render +- Access to your Render dashboard +- Your app source code updated locally + +## Step 1: Create PostgreSQL Database on Render + +1. **Log in to Render Dashboard** + - Go to [dashboard.render.com](https://dashboard.render.com) + +2. **Create New PostgreSQL Database** + - Click "New +" button + - Select "PostgreSQL" + - Choose your preferred region (same as your web service recommended) + - Name your database (e.g., "flask-todo-db") + - Plan: Free tier available + - Click "Create Database" + +3. **Wait for Database to Initialize** + - This takes a few minutes + - Once ready, you'll see the connection details + +## Step 2: Update Your Application Code + +### Install PostgreSQL Driver + +Add psycopg2 to your `requirements.txt`: + +``` +Flask==2.3.0 +SQLAlchemy==2.0.0 +psycopg2-binary==2.9.6 +# ...other dependencies... +``` + +### Update Database Configuration + +In your `app.py`, update the database URI to use PostgreSQL when the `DATABASE_URL` environment variable is present: + +```python +import os +from flask import Flask +from sqlalchemy import create_engine + +app = Flask(__name__) + +# Use DATABASE_URL if available (Render), otherwise use SQLite +database_url = os.getenv('DATABASE_URL') +if database_url: + # Fix the PostgreSQL URI format for SQLAlchemy + if database_url.startswith('postgres://'): + database_url = database_url.replace('postgres://', 'postgresql://', 1) + app.config['SQLALCHEMY_DATABASE_URI'] = database_url +else: + app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db' + +app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False +``` + +## Step 3: Update render.yaml + +Update your `render.yaml` to include the PostgreSQL database and link it to your web service: + +```yaml +services: + - type: web + name: flask-todo-app + env: python + plan: free + buildCommand: pip install -r requirements.txt + startCommand: gunicorn app:app + envVars: + - key: PYTHON_VERSION + value: 3.10 + - key: OAUTHLIB_INSECURE_TRANSPORT + value: "0" + - key: APP_SECRET_KEY + generateValue: true + - key: AUTH0_DOMAIN + sync: false + - key: AUTH0_CLIENT_ID + sync: false + - key: AUTH0_CLIENT_SECRET + sync: false + - key: AUTH0_CALLBACK_URL + value: https://${RENDER_EXTERNAL_HOSTNAME}/callback + - key: DATABASE_URL + fromDatabase: + name: flask-todo-db + property: connectionString + +databases: + - name: flask-todo-db + databaseName: flask_todo + plan: free +``` + +## Step 4: Create Database Tables + +When your app first connects to PostgreSQL, it needs to create the tables: + +### Option A: Automatic (Recommended) + +Update your app initialization to create tables on startup: + +```python +from flask_sqlalchemy import SQLAlchemy + +db = SQLAlchemy(app) + +# In your init_todo() function or app creation: +with app.app_context(): + db.create_all() +``` + +### Option B: Manual via Shell + +1. SSH into your Render web service +2. Run: + ```bash + python + >>> from app import app, db + >>> with app.app_context(): + ... db.create_all() + >>> exit() + ``` + +## Step 5: Deploy Updated Code + +1. **Commit and push your changes** + ```bash + git add requirements.txt app.py render.yaml + git commit -m "Add PostgreSQL support" + git push origin main + ``` + +2. **Render automatically redeploys** + - Check the "Logs" tab in Render dashboard + - Wait for build to complete + +## Step 6: Verify Migration + +1. Visit your app: `https://.onrender.com` +2. Create a test todo +3. Refresh the page - data should persist +4. Check Render PostgreSQL dashboard to confirm queries are running + +## Rollback to SQLite (If Needed) + +If you need to go back to SQLite: + +1. Remove the `DATABASE_URL` environment variable from Render +2. Revert your `app.py` to use SQLite only +3. Push to GitHub +4. Render will redeploy with SQLite + +## Troubleshooting + +### "Ident authentication failed" + +- Your `DATABASE_URL` may be malformed +- Ensure you're using `postgresql://` not `postgres://` +- Check that the connection string includes username and password + +### "relation 'todo' does not exist" + +- Tables haven't been created yet +- Ensure `db.create_all()` runs on app startup +- Check application logs for errors + +### Connection Timeout + +- PostgreSQL service may still be starting +- Wait a few minutes and try again +- Check that your web service can reach the database (same region recommended) + +### Data Lost After Redeploy + +- Free tier databases may have limitations +- Consider upgrading to a paid plan for production +- Alternatively, implement regular backups + +## Useful Links + +- [Render PostgreSQL Documentation](https://render.com/docs/databases) +- [SQLAlchemy PostgreSQL Dialect](https://docs.sqlalchemy.org/en/20/dialects/postgresql.html) +- [PostgreSQL Connection Strings](https://www.postgresql.org/docs/current/libpq-envars.html) +- [Database Migrations with Flask-Migrate](https://flask-migrate.readthedocs.io/) + +## Next Steps + +Once PostgreSQL is running reliably: + +- Implement database migrations using [Flask-Migrate](https://flask-migrate.readthedocs.io/) +- Set up automated backups in Render +- Consider upgrading to a paid database plan for production use diff --git a/README.md b/README.md index 016fab7..781603a 100644 --- a/README.md +++ b/README.md @@ -171,17 +171,19 @@ Without this, Auth0 cannot reach your callback URL and login will fail. ## The Database -This code uses [SQLAlchemy](https://www.sqlalchemy.org/) to set up classes that have methods to talk to many [databases](https://docs.sqlalchemy.org/en/20/dialects/index.html) we use SQLite for simplicity here. +This code uses [SQLAlchemy](https://www.sqlalchemy.org/) to set up classes that have methods to talk to many [databases](https://docs.sqlalchemy.org/en/20/dialects/index.html). We use **SQLite for simplicity and easy local development**. -### SQLite Viewer extension +### Local Development (SQLite) -The database file is in /instance/ +The database file is stored in `/instance/todo.db` -The database can be changed to +### Production Deployment (SQLite) -## First deployment +For initial deployment on Render, SQLite works fine for testing and small user bases. The database persists in Render's filesystem. -Once you have your code how you want +### Upgrading to PostgreSQL + +Once your app grows and you need a more robust database, see [POSTGRESQL_SETUP.md](POSTGRESQL_SETUP.md) for a complete migration guide. ## Deployment on Render @@ -230,7 +232,7 @@ After the blueprint is created, you need to add your environment variables: 2. **Add Environment Variables** - Click "Add Environment Variable" - - Add each variable from your `.env` file: + - Add each variable: ``` APP_SECRET_KEY= AUTH0_DOMAIN=.auth0.com @@ -246,6 +248,7 @@ After the blueprint is created, you need to add your environment variables: - Render will automatically build and deploy your application - Wait for the build to complete (check the "Logs" tab) - Your app will be available at `https://.onrender.com` + - **Note**: The SQLite database file will persist on Render's filesystem ### Step 4: Update Auth0 Settings diff --git a/render.yaml b/render.yaml index ed7197e..1c9f6ad 100644 --- a/render.yaml +++ b/render.yaml @@ -20,13 +20,3 @@ services: sync: false - key: AUTH0_CALLBACK_URL value: https://${RENDER_EXTERNAL_HOSTNAME}/callback - - key: DATABASE_URL - fromDatabase: - name: flask-todo-db - property: connectionString - -databases: - - name: flask-todo-db - databaseName: flask_todo - plan: free - region: oregon From bf109a22020e637d1327b8ebc7456b4ba52de31a Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Tue, 13 Jan 2026 10:52:33 +0000 Subject: [PATCH 05/25] Update Python version to 3.12.1 in render.yaml --- render.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/render.yaml b/render.yaml index 1c9f6ad..12b55d0 100644 --- a/render.yaml +++ b/render.yaml @@ -7,7 +7,7 @@ services: startCommand: gunicorn app:app envVars: - key: PYTHON_VERSION - value: 3.10 + value: 3.12.1 - key: OAUTHLIB_INSECURE_TRANSPORT value: "0" - key: APP_SECRET_KEY From eaacba54785b053bc63843992722223351d3a790 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Tue, 13 Jan 2026 11:46:29 +0000 Subject: [PATCH 06/25] fix on render --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index f34dcae..f01572b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ Flask-SQLAlchemy==3.1.1 Flask-Dance==7.0.0 gunicorn==21.2.0 python-dotenv==1.0.0 +psycopg2-binary==2.9.11 \ No newline at end of file From 09b811cfade525294185b46efbf5bac64bd961ec Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Tue, 13 Jan 2026 12:06:54 +0000 Subject: [PATCH 07/25] gunicorn fix --- render.yaml | 2 +- requirements.txt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/render.yaml b/render.yaml index 12b55d0..4946f01 100644 --- a/render.yaml +++ b/render.yaml @@ -4,7 +4,7 @@ services: env: python plan: free buildCommand: pip install -r requirements.txt - startCommand: gunicorn app:app + startCommand: python -m gunicorn app:app envVars: - key: PYTHON_VERSION value: 3.12.1 diff --git a/requirements.txt b/requirements.txt index f01572b..f8efd1d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,5 +3,4 @@ Flask==2.3.2 Flask-SQLAlchemy==3.1.1 Flask-Dance==7.0.0 gunicorn==21.2.0 -python-dotenv==1.0.0 -psycopg2-binary==2.9.11 \ No newline at end of file +python-dotenv==1.0.0 \ No newline at end of file From 8ee1f24fb3dfab7bfcd011c37b1bcd2934d40ff5 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Tue, 13 Jan 2026 14:06:41 +0000 Subject: [PATCH 08/25] gunicorn compatibility --- README.md | 1 + app.py | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/README.md b/README.md index 781603a..587aafd 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,7 @@ Ensure your repository contains: - `render.yaml` (blueprint configuration file) - `requirements.txt` (Python dependencies) - All application code pushed to GitHub +- Use `python -m gunicorn app:app --bind 0.0.0.0:5000` to confirm that everything works ok under gunicorn before trying Render ### Step 2: Create a Blueprint on Render diff --git a/app.py b/app.py index 7bedf09..8115d6e 100644 --- a/app.py +++ b/app.py @@ -1,3 +1,7 @@ +# Load environment variables from .env file (needed for gunicorn) +from dotenv import load_dotenv +load_dotenv() + import os from flask import Flask from auth import auth_bp, auth0_bp, github_bp, github_auth_bp @@ -35,5 +39,13 @@ def inject_dict_for_all_templates(): # Initialize todo module (db and tables) init_todo(app) +# Set AUTH0_CALLBACK_URL dynamically based on Render's hostname +if 'RENDER_EXTERNAL_HOSTNAME' in os.environ: + auth0_callback_url = f"https://{os.environ['RENDER_EXTERNAL_HOSTNAME']}/callback" +else: + auth0_callback_url = os.environ.get('AUTH0_CALLBACK_URL', 'http://localhost:5000/callback') + +# Use auth0_callback_url in your Auth0 configuration + if __name__ == '__main__': app.run(debug=True) From 3e0ad4cf32e000682d08160e04a5e16f65943a80 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Tue, 13 Jan 2026 14:41:43 +0000 Subject: [PATCH 09/25] Render Fix --- app.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app.py b/app.py index 8115d6e..baf4eb8 100644 --- a/app.py +++ b/app.py @@ -45,6 +45,8 @@ def inject_dict_for_all_templates(): else: auth0_callback_url = os.environ.get('AUTH0_CALLBACK_URL', 'http://localhost:5000/callback') +app.config['AUTH0_CALLBACK_URL'] = auth0_callback_url + # Use auth0_callback_url in your Auth0 configuration if __name__ == '__main__': From 2cfd6af768a5b756cdf04df4ef4049c678dc5c65 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Wed, 14 Jan 2026 09:56:37 +0000 Subject: [PATCH 10/25] Documentation updates --- CODESPACES_SETUP.md | 100 +++++++++++++++++++++++++ README.md | 175 +++----------------------------------------- RENDER_SETUP.md | 136 ++++++++++++++++++++++++++++++++++ 3 files changed, 245 insertions(+), 166 deletions(-) create mode 100644 CODESPACES_SETUP.md create mode 100644 RENDER_SETUP.md diff --git a/CODESPACES_SETUP.md b/CODESPACES_SETUP.md new file mode 100644 index 0000000..67b4632 --- /dev/null +++ b/CODESPACES_SETUP.md @@ -0,0 +1,100 @@ +# GitHub Codespaces Setup + +GitHub Codespaces is a flexible cloud-based development environment. Your editor runs in the cloud, allowing you to work from anywhere. + +## Creating and Starting a Codespace + +### Create a New Codespace + +1. **Go to the Repository** + - Navigate to [https://github.com/stretchyboy/python-todo](https://github.com/stretchyboy/python-todo) (or your fork) + +2. **Create a Codespace** + - Click the green **"Code"** button + - Select the **"Codespaces"** tab + - Click **"Create codespace on main"** (or your preferred branch) + +3. **Wait for Setup** + - GitHub will provision your Codespace (this takes 1-2 minutes) + - VS Code will open in your browser automatically + - The environment is ready when you see the terminal + +### Start an Existing Codespace + +If you've created a Codespace before: + +1. **Go to Your Codespaces** + - Visit [https://github.com/codespaces](https://github.com/codespaces) + - Click on your Codespace name to open it + +2. **Or via GitHub** + - Click the green **"Code"** button on the repository + - Select the **"Codespaces"** tab + - Click on an existing Codespace to resume it + +## Install Dependencies + +```bash +py -m pip install -r requirements.txt +``` + +## Copy Example Environment File + +```bash +# On linux or codespaces +cp .env.example .env +``` + +## Auth0 Setup (Codespaces & Production) + +For Codespaces and Render deployment: + +1. **Create an Auth0 Account** + - Go to [auth0.com](https://auth0.com) and sign up + +2. **Create an Application** + - Dashboard → Applications → Create Application + - Choose "Regular Web Applications" + - Name: Flask Todo App + +3. **Configure Application Settings** + - "Allowed Callback URLs": `https:///callback` + - "Allowed Logout URLs": `https:///` + - "Allowed Web Origins": `https://` + - Codespaces URL format: `https://-5000./` + - Example: `https://shiny-space-pancake-g5w6pqr4v7h2pgx-5000.app.github.dev/callback` + +4. **Copy Credentials** + - Add Auth0 Domain, Client ID, and Client Secret to `.env` + +## Running the Application + +Start the Flask development server: + +```bash +python -m flask run +``` + +The app will be available at [http://localhost:5000](http://localhost:5000) + +## Important: Codespaces Port Configuration + +If you're running in **GitHub Codespaces**, you must set the forwarded port to **Public** for Auth0 callbacks to work: + +1. Open the **Ports** panel (bottom of VS Code) +2. Right-click the port 5000 +3. Select "Port Visibility" → **Public** + +Without this, Auth0 cannot reach your callback URL and login will fail. + +## Using the App + +1. Visit [http://localhost:5000](http://localhost:5000) +2. Click "Login" - it will automatically route to Auth0 +3. After successful login, manage your todos + +## Authentication Resources + +- [Flask-Dance Documentation](https://flask-dance.readthedocs.io/) +- [Auth0 Python Quickstart](https://auth0.com/docs/quickstart/webapp/python) +- [Auth0 Dashboard](https://manage.auth0.com/) diff --git a/README.md b/README.md index 587aafd..79f2a4a 100644 --- a/README.md +++ b/README.md @@ -112,32 +112,6 @@ For local Windows development with GitHub Desktop: 3. **Enable Insecure Transport for Local Dev** - Set `OAUTHLIB_INSECURE_TRANSPORT=1` in `.env` (only for local development) -### Auth0 Setup (Codespaces & Production) - -For Codespaces and Render deployment: - -1. **Create an Auth0 Account** - - Go to [auth0.com](https://auth0.com) and sign up - -2. **Create an Application** - - Dashboard → Applications → Create Application - - Choose "Regular Web Applications" - - Name: Flask Todo App - -3. **Configure Application Settings** - - "Allowed Callback URLs": - - Local: `http://localhost:5000/callback` - - Codespaces: `https:///callback` - - Production: `https://your-app.onrender.com/callback` - - "Allowed Logout URLs": - - Local: `http://localhost:5000/` - - Production: `https://your-app.onrender.com/` - - "Allowed Web Origins": Same as callback URLs - - Codespaces URL format: `https://-5000./` (use `/callback` for the callback and `/` for logout) - -4. **Copy Credentials** - - Add Auth0 Domain, Client ID, and Client Secret to `.env` - ## Running the Application Start the Flask development server: @@ -148,27 +122,6 @@ python -m flask run The app will be available at [http://localhost:5000](http://localhost:5000) -### Important: Codespaces Port Configuration - -If you're running in **GitHub Codespaces**, you must set the forwarded port to **Public** for Auth0 callbacks to work: - -1. Open the **Ports** panel (bottom of VS Code) -2. Right-click the port 5000 -3. Select "Port Visibility" → **Public** - -Without this, Auth0 cannot reach your callback URL and login will fail. - -**To use the app:** -1. Visit [http://localhost:5000](http://localhost:5000) -2. Click "Login" - it will automatically route to GitHub (local) or Auth0 (Codespaces) -3. After successful login, manage your todos - -## Authentication Resources - -- [Flask-Dance Documentation](https://flask-dance.readthedocs.io/) -- [Auth0 Python Quickstart](https://auth0.com/docs/quickstart/webapp/python) -- [Auth0 Dashboard](https://manage.auth0.com/) - ## The Database This code uses [SQLAlchemy](https://www.sqlalchemy.org/) to set up classes that have methods to talk to many [databases](https://docs.sqlalchemy.org/en/20/dialects/index.html). We use **SQLite for simplicity and easy local development**. @@ -177,129 +130,19 @@ This code uses [SQLAlchemy](https://www.sqlalchemy.org/) to set up classes that The database file is stored in `/instance/todo.db` -### Production Deployment (SQLite) +## Things we are ignoring -For initial deployment on Render, SQLite works fine for testing and small user bases. The database persists in Render's filesystem. +- Persistent records in a database. The current database will be destroyed each time you push to render, ( You can modify the code once it's on Render to move to PostgreSQL ). +- Changing database structure SQLAlchemy Migrations. Currently we aren't handling changes to the database structure so you need to delete the local .db and start again (render wil do this anyway on a rebuild as mentioned above). They can be handled with Migrations +- Storing any user data in a database (other than an id from github ). To have users on this system to store any other PII refer to [https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy](https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy) and change the privacy statement. +- Adding extra security [https://flask-security.readthedocs.io/en/stable/quickstart.html#basic-flask-sqlalchemy-application](https://flask-security.readthedocs.io/en/stable/quickstart.html#basic-flask-sqlalchemy-application) +- Testing. There are no tests in this code. -### Upgrading to PostgreSQL +## Codespaces Setup -Once your app grows and you need a more robust database, see [POSTGRESQL_SETUP.md](POSTGRESQL_SETUP.md) for a complete migration guide. +See [CODESPACES_SETUP.md](CODESPACES_SETUP.md) for complete GitHub Codespaces setup instructions. ## Deployment on Render -### Prerequisites - -1. **GitHub Repository**: Your code must be pushed to a GitHub repository -2. **Render Account**: Sign up at [render.com](https://render.com) (free tier available) -3. **Auth0 Application**: Configured with your production callback URL - -### Step 1: Prepare Your Repository - -Ensure your repository contains: -- `render.yaml` (blueprint configuration file) -- `requirements.txt` (Python dependencies) -- All application code pushed to GitHub -- Use `python -m gunicorn app:app --bind 0.0.0.0:5000` to confirm that everything works ok under gunicorn before trying Render - -### Step 2: Create a Blueprint on Render - -1. **Log in to Render Dashboard** - - Go to [dashboard.render.com](https://dashboard.render.com) - -2. **Create New Blueprint** - - Click the "New +" button in the top right - - Select "Blueprint" from the dropdown menu - - [Direct Link to Create Blueprint](https://dashboard.render.com/select-repo?type=blueprint) - -3. **Connect Your GitHub Repository** - - Click "Connect account" if this is your first time - - Authorize Render to access your GitHub repositories - - Search for and select `mr-eggleton/python-flask-todo` (or your fork) - - Click "Connect" - -4. **Review Blueprint Configuration** - - Render will detect your `render.yaml` file - - Review the services that will be created (web service, database, etc.) - - Give your blueprint instance a name (e.g., "flask-todo-app") - - Click "Apply" - -### Step 3: Configure Environment Variables - -After the blueprint is created, you need to add your environment variables: - -1. **Navigate to Your Web Service** - - In the Render dashboard, click on your web service - - Go to the "Environment" tab - -2. **Add Environment Variables** - - Click "Add Environment Variable" - - Add each variable: - ``` - APP_SECRET_KEY= - AUTH0_DOMAIN=.auth0.com - AUTH0_CLIENT_ID= - AUTH0_CLIENT_SECRET= - AUTH0_CALLBACK_URL=https://.onrender.com/callback - ``` - - **Important**: Generate a NEW `APP_SECRET_KEY` for production (don't reuse your local one) - - **Note**: Do NOT set `OAUTHLIB_INSECURE_TRANSPORT` in production - - Click "Save Changes" - -3. **Automatic Deployment** - - Render will automatically build and deploy your application - - Wait for the build to complete (check the "Logs" tab) - - Your app will be available at `https://.onrender.com` - - **Note**: The SQLite database file will persist on Render's filesystem - -### Step 4: Update Auth0 Settings - -1. **Add Production Callback URL** - - Go to [Auth0 Dashboard](https://manage.auth0.com) - - Navigate to your application settings - - Add to "Allowed Callback URLs": `https://.onrender.com/callback` - - Add to "Allowed Logout URLs": `https://.onrender.com/` - - Add to "Allowed Web Origins": `https://.onrender.com` - - Click "Save Changes" - -### Step 5: Test Your Deployment - -1. Visit your Render URL: `https://.onrender.com` -2. Click "Login" - should redirect to Auth0 -3. Complete authentication -4. Verify you can create and manage todos - -### Continuous Deployment - -Once set up, Render automatically deploys when you push to your main branch: - -1. Make changes to your code locally -2. Commit and push to GitHub: - ```bash - git add . - git commit -m "Your commit message" - git push origin main - ``` -3. Render detects the push and automatically rebuilds/redeploys -4. Monitor deployment progress in the Render dashboard - -### Troubleshooting - -- **Build Fails**: Check the "Logs" tab in Render dashboard for errors -- **Auth0 Redirect Error**: Verify callback URLs match exactly (including https://) -- **Environment Variables**: Ensure all required variables are set in Render -- **Database Issues**: Render free tier databases sleep after inactivity; first request may be slow - -### Useful Links - -- [Render Blueprint Documentation](https://render.com/docs/infrastructure-as-code) -- [Render Python Deployment Guide](https://render.com/docs/deploy-flask) -- [Render Environment Variables](https://render.com/docs/environment-variables) -- [Auth0 Production Checklist](https://auth0.com/docs/deploy-monitor/deploy/production-checklist) +See [RENDER_SETUP.md](RENDER_SETUP.md) for complete Render deployment instructions, including setup, configuration, environment variables, and continuous deployment. -## Things we are ignoring - -- Persistent records in a database. The current database will be destroyed each time you push to render, ( we are only testing, not building a real system that works for years). -- Changing database structure SQLAlchemy Migrations. Currently we aren't handling changes to the database structure so you need to delete the local .db and start again (render wil do this anyway on a rebuild as mentioned above). They can be handled with Migrations -- Storing any user data in a database (other than an id from github ). To have users on this system to store any other PII refer to [https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy](https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy) and change the privacy statement. -- Adding extra security [https://flask-security.readthedocs.io/en/stable/quickstart.html#basic-flask-sqlalchemy-application](https://flask-security.readthedocs.io/en/stable/quickstart.html#basic-flask-sqlalchemy-application) -- Testing. There are no tests in this code. diff --git a/RENDER_SETUP.md b/RENDER_SETUP.md new file mode 100644 index 0000000..b494983 --- /dev/null +++ b/RENDER_SETUP.md @@ -0,0 +1,136 @@ +# Deployment on Render + +## Prerequisites + +1. **GitHub Repository**: Your code must be pushed to a GitHub repository +2. **Render Account**: Sign up at [render.com](https://render.com) (free tier available) +3. **Auth0 Application**: Configured with your production callback URL + +## Auth0 Setup (Production) + +Before deploying to Render, set up Auth0 for production: + +1. **Create an Auth0 Account** + - Go to [auth0.com](https://auth0.com) and sign up + +2. **Create an Application** + - Dashboard → Applications → Create Application + - Choose "Regular Web Applications" + - Name: Flask Todo App + +3. **Configure Application Settings** + - "Allowed Callback URLs": `https://.onrender.com/callback` + - "Allowed Logout URLs": `https://.onrender.com/` + - "Allowed Web Origins": `https://.onrender.com` + - Example: `https://flask-todo-app.onrender.com/callback` + +4. **Save Credentials** + - Copy your Auth0 Domain, Client ID, and Client Secret + - You'll need these for Render environment variables in Step 3 + +## Step 1: Prepare Your Repository + +Ensure your repository contains: +- `render.yaml` (blueprint configuration file) +- `requirements.txt` (Python dependencies) +- All application code pushed to GitHub +- Use `python -m gunicorn app:app --bind 0.0.0.0:5000` to confirm that everything works ok under gunicorn before trying Render + +## Step 2: Create a Blueprint on Render + +1. **Log in to Render Dashboard** + - Go to [dashboard.render.com](https://dashboard.render.com) + +2. **Create New Blueprint** + - Click the "New +" button in the top right + - Select "Blueprint" from the dropdown menu + - [Direct Link to Create Blueprint](https://dashboard.render.com/select-repo?type=blueprint) + +3. **Connect Your GitHub Repository** + - Click "Connect account" if this is your first time + - Authorize Render to access your GitHub repositories + - Search for and select `mr-eggleton/python-flask-todo` (or your fork) + - Click "Connect" + +4. **Review Blueprint Configuration** + - Render will detect your `render.yaml` file + - Review the services that will be created (web service, database, etc.) + - Give your blueprint instance a name (e.g., "flask-todo-app") + - Click "Apply" + +## Step 3: Configure Environment Variables + +After the blueprint is created, you need to add your environment variables: + +1. **Navigate to Your Web Service** + - In the Render dashboard, click on your web service + - Go to the "Environment" tab + +2. **Add Environment Variables** + - Click "Add Environment Variable" + - Add each variable: + ``` + APP_SECRET_KEY= + AUTH0_DOMAIN=.auth0.com + AUTH0_CLIENT_ID= + AUTH0_CLIENT_SECRET= + AUTH0_CALLBACK_URL=https://.onrender.com/callback + ``` + - **Important**: Generate a NEW `APP_SECRET_KEY` for production (don't reuse your local one) + - **Note**: Do NOT set `OAUTHLIB_INSECURE_TRANSPORT` in production + - Click "Save Changes" + +3. **Automatic Deployment** + - Render will automatically build and deploy your application + - Wait for the build to complete (check the "Logs" tab) + - Your app will be available at `https://.onrender.com` + - **Note**: The SQLite database file will persist on Render's filesystem + +## Step 4: Update Auth0 Settings + +1. **Add Production Callback URL** + - Go to [Auth0 Dashboard](https://manage.auth0.com) + - Navigate to your application settings + - Add to "Allowed Callback URLs": `https://.onrender.com/callback` + - Add to "Allowed Logout URLs": `https://.onrender.com/` + - Add to "Allowed Web Origins": `https://.onrender.com` + - Click "Save Changes" + +## Step 5: Test Your Deployment + +1. Visit your Render URL: `https://.onrender.com` +2. Click "Login" - should redirect to Auth0 +3. Complete authentication +4. Verify you can create and manage todos + +## Continuous Deployment + +Once set up, Render automatically deploys when you push to your main branch: + +1. Make changes to your code locally +2. Commit and push to GitHub: + ```bash + git add . + git commit -m "Your commit message" + git push origin main + ``` +3. Render detects the push and automatically rebuilds/redeploys +4. Monitor deployment progress in the Render dashboard + +## Troubleshooting + +- **Build Fails**: Check the "Logs" tab in Render dashboard for errors +- **Auth0 Redirect Error**: Verify callback URLs match exactly (including https://) +- **Environment Variables**: Ensure all required variables are set in Render +- **Database Issues**: Render free tier databases sleep after inactivity; first request may be slow + +## Upgrading to PostgreSQL + +Once your app grows and you need a more robust database, see [POSTGRESQL_SETUP.md](POSTGRESQL_SETUP.md) for a complete migration guide. + +## Useful Links + +- [Render Blueprint Documentation](https://render.com/docs/infrastructure-as-code) +- [Render Python Deployment Guide](https://render.com/docs/deploy-flask) +- [Render Environment Variables](https://render.com/docs/environment-variables) +- [Auth0 Production Checklist](https://auth0.com/docs/deploy-monitor/deploy/production-checklist) From 45ff8b15027181f512a06b56ee6179376c332b0e Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Wed, 14 Jan 2026 10:07:28 +0000 Subject: [PATCH 11/25] Tweaks to environment variables --- .env.example | 14 ++++---------- RENDER_SETUP.md | 33 +++++++++++++-------------------- app.py | 17 ++++++++++++++++- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/.env.example b/.env.example index 9f78f6d..043d9db 100644 --- a/.env.example +++ b/.env.example @@ -1,15 +1,9 @@ -DATABASE_URL=sqlite:///todo.db APP_SECRET_KEY=your_flask_secret - - -# GitHub OAuth for local development -GITHUB_CLIENT_ID=your-github-client-id -GITHUB_CLIENT_SECRET=your-github-client-secret -# Only needed for local/GitHub OAuth OAUTHLIB_INSECURE_TRANSPORT=0 +DATABASE_URL=sqlite:///todo.db # Example environment variables for Auth0 integration -AUTH0_DOMAIN=your-auth0-domain.auth0.com -AUTH0_CLIENT_ID=your-auth0-client-id -AUTH0_CLIENT_SECRET=your-auth0-client-secret +AUTH0_DOMAIN=your_auth0_domain +AUTH0_CLIENT_ID=your_client_id +AUTH0_CLIENT_SECRET=your_client_secret AUTH0_CALLBACK_URL=http://localhost:5000/callback diff --git a/RENDER_SETUP.md b/RENDER_SETUP.md index b494983..29848b9 100644 --- a/RENDER_SETUP.md +++ b/RENDER_SETUP.md @@ -59,26 +59,19 @@ Ensure your repository contains: - Click "Apply" ## Step 3: Configure Environment Variables - -After the blueprint is created, you need to add your environment variables: - -1. **Navigate to Your Web Service** - - In the Render dashboard, click on your web service - - Go to the "Environment" tab - -2. **Add Environment Variables** - - Click "Add Environment Variable" - - Add each variable: - ``` - APP_SECRET_KEY= - AUTH0_DOMAIN=.auth0.com - AUTH0_CLIENT_ID= - AUTH0_CLIENT_SECRET= - AUTH0_CALLBACK_URL=https://.onrender.com/callback - ``` - - **Important**: Generate a NEW `APP_SECRET_KEY` for production (don't reuse your local one) - - **Note**: Do NOT set `OAUTHLIB_INSECURE_TRANSPORT` in production - - Click "Save Changes" + + Add these in Render Dashboard → Environment: + + ``` + AUTH0_CLIENT_ID=your_client_id + AUTH0_CLIENT_SECRET=your_client_secret + AUTH0_DOMAIN=your_auth0_domain + APP_SECRET_KEY=your_secret_key + ``` + + **Important:** Do NOT set `RENDER_EXTERNAL_HOSTNAME` manually. Render sets this automatically, but it's only available at runtime, not during build. + + **For Auth0 Configuration:** Use your actual Render app URL (e.g., `https://python-todo.onrender.com`) in Auth0 settings, not the variable name. 3. **Automatic Deployment** - Render will automatically build and deploy your application diff --git a/app.py b/app.py index baf4eb8..a3261d7 100644 --- a/app.py +++ b/app.py @@ -17,7 +17,7 @@ } app = Flask(__name__) -app.secret_key = os.getenv("APP_SECRET_KEY", "supersecret") +app.secret_key = os.environ.get("APP_SECRET_KEY") app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', 'sqlite:///todo.db') app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False @@ -47,6 +47,21 @@ def inject_dict_for_all_templates(): app.config['AUTH0_CALLBACK_URL'] = auth0_callback_url +# Set redirect_uri based on environment +if os.getenv('CODESPACE_NAME'): + # Running in GitHub Codespaces + redirect_uri = f"https://{os.getenv('CODESPACE_NAME')}-5000.{os.getenv('GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN')}/callback" +elif os.getenv('RENDER'): + # Running on Render - use RENDER_EXTERNAL_URL which is set at runtime + render_url = os.getenv('RENDER_EXTERNAL_URL', '') + if render_url: + redirect_uri = f"{render_url}/callback" + else: + redirect_uri = None # Will fall back to default +else: + # Local development + redirect_uri = "http://localhost:5000/callback" + # Use auth0_callback_url in your Auth0 configuration if __name__ == '__main__': From 638be9d5337107e4b922f177aac1292b1e07fae2 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Wed, 14 Jan 2026 10:56:51 +0000 Subject: [PATCH 12/25] Update Auth0 callback URL handling and documentation for Render deployment --- RENDER_SETUP.md | 3 +++ app.py | 11 ++--------- render.yaml | 2 +- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/RENDER_SETUP.md b/RENDER_SETUP.md index 29848b9..9259767 100644 --- a/RENDER_SETUP.md +++ b/RENDER_SETUP.md @@ -67,8 +67,11 @@ Ensure your repository contains: AUTH0_CLIENT_SECRET=your_client_secret AUTH0_DOMAIN=your_auth0_domain APP_SECRET_KEY=your_secret_key + AUTH0_CALLBACK_URL=https://your-app-name.onrender.com/callback ``` + **Important:** Replace `your-app-name.onrender.com` with your actual Render app URL (found in your Render dashboard). + **Important:** Do NOT set `RENDER_EXTERNAL_HOSTNAME` manually. Render sets this automatically, but it's only available at runtime, not during build. **For Auth0 Configuration:** Use your actual Render app URL (e.g., `https://python-todo.onrender.com`) in Auth0 settings, not the variable name. diff --git a/app.py b/app.py index a3261d7..47ca576 100644 --- a/app.py +++ b/app.py @@ -51,16 +51,9 @@ def inject_dict_for_all_templates(): if os.getenv('CODESPACE_NAME'): # Running in GitHub Codespaces redirect_uri = f"https://{os.getenv('CODESPACE_NAME')}-5000.{os.getenv('GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN')}/callback" -elif os.getenv('RENDER'): - # Running on Render - use RENDER_EXTERNAL_URL which is set at runtime - render_url = os.getenv('RENDER_EXTERNAL_URL', '') - if render_url: - redirect_uri = f"{render_url}/callback" - else: - redirect_uri = None # Will fall back to default else: - # Local development - redirect_uri = "http://localhost:5000/callback" + # Use AUTH0_CALLBACK_URL from environment (for both local and production) + redirect_uri = os.getenv('AUTH0_CALLBACK_URL', 'http://localhost:5000/callback') # Use auth0_callback_url in your Auth0 configuration diff --git a/render.yaml b/render.yaml index 4946f01..51eaa26 100644 --- a/render.yaml +++ b/render.yaml @@ -19,4 +19,4 @@ services: - key: AUTH0_CLIENT_SECRET sync: false - key: AUTH0_CALLBACK_URL - value: https://${RENDER_EXTERNAL_HOSTNAME}/callback + sync: false From 3bbf969f43d5a330dc393f771e485e894a5bbfdb Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Wed, 14 Jan 2026 12:58:32 +0000 Subject: [PATCH 13/25] Refactor README for clarity and detail on features and setup --- README.md | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 79f2a4a..150f89d 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,15 @@ -# Flask Todo App with Dual Authentication +# Flask Todo App Starter ![Python](https://img.shields.io/badge/Python-3.10-blue) ![Flask](https://img.shields.io/badge/Flask-2.3-green) ![Render](https://img.shields.io/badge/Deploy-Render-purple) ## Features - + ### Flask + - Webserver with routing (a function for each url endpoint) + - Jinja templates for looping though and outputting data. + - todo.py contains the endpoints for the Todo app -### SQLAlchemy & SQLite +### SQLAlchemy & SQLite / PostgreSQL + - SQL Database + - Managed by SQLAlchemy an Object Relationship Manager which allows you to write classes that define the data and provides the storage & CRUD for you. + - ORMs build the database for you from your classes, start with SQLite but you can move PostgreSQL or others when you are ready. + - todo.py includes the Todo class that provdes all you need for the building of the database and all the CRUD. ### Authentication (GitHub + Auth0) + - GitHub OAuth (Flask-Dance) for local Windows development + - Auth0 OAuth for Codespaces and Render production -### Render - -### Github Actions +### Render & Github Actions +- Ready for Render deployment +- GitHub Actions CI/CD ## Setup @@ -138,6 +150,12 @@ The database file is stored in `/instance/todo.db` - Adding extra security [https://flask-security.readthedocs.io/en/stable/quickstart.html#basic-flask-sqlalchemy-application](https://flask-security.readthedocs.io/en/stable/quickstart.html#basic-flask-sqlalchemy-application) - Testing. There are no tests in this code. +## Your Development + + + + + ## Codespaces Setup See [CODESPACES_SETUP.md](CODESPACES_SETUP.md) for complete GitHub Codespaces setup instructions. From 44a47cfa58515437aec23ec43a598945444603a2 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Wed, 14 Jan 2026 12:58:40 +0000 Subject: [PATCH 14/25] Refactor Todo model to use SQLAlchemy's mapped_column and remove dataclass decorator --- todo.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/todo.py b/todo.py index d6361a6..299a7ed 100644 --- a/todo.py +++ b/todo.py @@ -1,26 +1,27 @@ # todo.py - todo functionality from flask import Blueprint, render_template, request, redirect, session +# models.py from flask_sqlalchemy import SQLAlchemy -from dataclasses import dataclass +from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass, Mapped, mapped_column from auth import get_current_user + +# Base that adds dataclass behaviors to mapped classes +class Base(MappedAsDataclass, DeclarativeBase): + pass + + todo_bp = Blueprint('todo', __name__) -db = SQLAlchemy() +db = SQLAlchemy(model_class=Base) -@dataclass class Todo(db.Model): - id: int - task: str - done: bool - user_id: str - - __tablename__ = 'todos' + __tablename__ = "todos" - id = db.Column(db.Integer, primary_key=True) - task = db.Column(db.String(200), nullable=False) - done = db.Column(db.Boolean, default=False) - user_id = db.Column(db.String(100), nullable=False) + id: Mapped[int] = mapped_column(primary_key=True, init=False) + task: Mapped[str] = mapped_column(db.String(200), nullable=False) + user_id: Mapped[str] = mapped_column(db.String(100), nullable=False) + done: Mapped[bool] = mapped_column(db.Boolean, default=False) @todo_bp.route('/') From 4d9483d05abb8042a8583f19709b645acf0cb12f Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Wed, 14 Jan 2026 13:38:47 +0000 Subject: [PATCH 15/25] Add admin interface with authentication and update requirements - Implemented AuthenticatedAdminIndexView and AuthenticatedModelView for secured admin access. - Initialized admin interface in app.py. - Added freeze.txt for dependency management. - Updated requirements.txt to include flask-admin with necessary extras. - Minor formatting adjustments in todo.py. --- admin.py | 32 +++++++++++ app.py | 6 +- freeze.txt | 145 +++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 4 +- todo.py | 1 + 5 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 admin.py create mode 100644 freeze.txt diff --git a/admin.py b/admin.py new file mode 100644 index 0000000..be8e3a3 --- /dev/null +++ b/admin.py @@ -0,0 +1,32 @@ +from flask import redirect, request, url_for +from flask_admin import Admin, AdminIndexView +from flask_admin.contrib.sqla import ModelView +from flask_babel import Babel +from auth import get_current_user + + +class AuthenticatedAdminIndexView(AdminIndexView): + def is_accessible(self): + return get_current_user() is not None + + def inaccessible_callback(self, name, **kwargs): + return redirect(url_for('auth.login', next=request.url)) + + +class AuthenticatedModelView(ModelView): + def is_accessible(self): + return get_current_user() is not None + + def inaccessible_callback(self, name, **kwargs): + return redirect(url_for('auth.login', next=request.url)) + + +def init_admin(app, db, model): + """Attach Babel and register secured admin views for the given model.""" + Babel(app, locale_selector=lambda: 'en') + admin = Admin(app, name="Admin", template_mode="bootstrap4", + index_view=AuthenticatedAdminIndexView()) + admin.add_view(AuthenticatedModelView(model, db.session, + endpoint="todo_admin", + name="Todos")) + return admin diff --git a/app.py b/app.py index 47ca576..89d09fd 100644 --- a/app.py +++ b/app.py @@ -7,6 +7,9 @@ from auth import auth_bp, auth0_bp, github_bp, github_auth_bp from auth import is_codespaces, is_render from todo import todo_bp, init_app as init_todo +from todo import db, Todo +from admin import init_admin + SITE = { "WebsiteName": "TodoApp", @@ -55,7 +58,8 @@ def inject_dict_for_all_templates(): # Use AUTH0_CALLBACK_URL from environment (for both local and production) redirect_uri = os.getenv('AUTH0_CALLBACK_URL', 'http://localhost:5000/callback') -# Use auth0_callback_url in your Auth0 configuration +# Initialize admin interface (secured) +init_admin(app, db, Todo) if __name__ == '__main__': app.run(debug=True) diff --git a/freeze.txt b/freeze.txt new file mode 100644 index 0000000..97f331f --- /dev/null +++ b/freeze.txt @@ -0,0 +1,145 @@ +anyio==4.11.0 +argon2-cffi==25.1.0 +argon2-cffi-bindings==25.1.0 +arrow==1.4.0 +asttokens==3.0.0 +async-lru==2.0.5 +attrs==25.4.0 +babel==2.17.0 +beautifulsoup4==4.14.2 +bleach==6.3.0 +blinker==1.9.0 +boto3==1.42.27 +botocore==1.42.27 +certifi==2025.10.5 +cffi==2.0.0 +charset-normalizer==3.4.4 +click==8.3.1 +colorama==0.4.6 +comm==0.2.3 +contourpy==1.3.3 +cycler==0.12.1 +debugpy==1.8.17 +decorator==5.2.1 +defusedxml==0.7.1 +executing==2.2.1 +fastjsonschema==2.21.2 +filelock==3.19.1 +Flask==2.3.2 +Flask-Admin==2.0.2 +flask-babel==4.0.0 +Flask-Dance==7.0.0 +Flask-SQLAlchemy==3.1.1 +fonttools==4.60.1 +fqdn==1.5.1 +fsspec==2025.9.0 +gitdb==4.0.12 +GitPython==3.1.45 +greenlet==3.2.4 +gunicorn==21.2.0 +h11==0.16.0 +httpcore==1.0.9 +httpx==0.28.1 +idna==3.11 +ipykernel==7.1.0 +ipython==9.7.0 +ipython_pygments_lexers==1.1.1 +isoduration==20.11.0 +itsdangerous==2.2.0 +jedi==0.19.2 +Jinja2==3.1.6 +jmespath==1.0.1 +joblib==1.5.2 +json5==0.12.1 +jsonpointer==3.0.0 +jsonschema==4.25.1 +jsonschema-specifications==2025.9.1 +jupyter-events==0.12.0 +jupyter-lsp==2.3.0 +jupyter-server-mathjax==0.2.6 +jupyter_client==8.6.3 +jupyter_core==5.9.1 +jupyter_server==2.17.0 +jupyter_server_terminals==0.5.3 +jupyterlab==4.4.10 +jupyterlab_git==0.51.2 +jupyterlab_pygments==0.3.0 +jupyterlab_server==2.28.0 +kiwisolver==1.4.9 +lark==1.3.1 +MarkupSafe==3.0.3 +matplotlib==3.10.7 +matplotlib-inline==0.2.1 +mistune==3.1.4 +mpmath==1.3.0 +narwhals==2.10.2 +nbclient==0.10.2 +nbconvert==7.16.6 +nbdime==4.0.2 +nbformat==5.10.4 +nest-asyncio==1.6.0 +networkx==3.5 +notebook_shim==0.2.4 +numpy==2.3.4 +oauthlib==3.3.1 +packaging==25.0 +pandas==2.3.3 +pandocfilters==1.5.1 +parso==0.8.5 +pexpect==4.9.0 +pillow==12.0.0 +platformdirs==4.5.0 +plotly==6.4.0 +prometheus_client==0.23.1 +prompt_toolkit==3.0.52 +psutil==7.1.3 +psycopg2-binary==2.9.11 +ptyprocess==0.7.0 +pure_eval==0.2.3 +pycparser==2.23 +Pygments==2.19.2 +pyparsing==3.2.5 +python-dateutil==2.9.0.post0 +python-dotenv==1.0.0 +python-json-logger==4.0.0 +pytz==2025.2 +PyYAML==6.0.3 +pyzmq==27.1.0 +referencing==0.37.0 +requests==2.32.5 +requests-oauthlib==2.0.0 +rfc3339-validator==0.1.4 +rfc3986-validator==0.1.1 +rfc3987-syntax==1.1.0 +rpds-py==0.28.0 +s3transfer==0.16.0 +scikit-learn==1.7.2 +scipy==1.16.3 +seaborn==0.13.2 +Send2Trash==1.8.3 +setuptools==80.9.0 +six==1.17.0 +smmap==5.0.2 +sniffio==1.3.1 +soupsieve==2.8 +SQLAlchemy==2.0.44 +stack-data==0.6.3 +sympy==1.14.0 +tablib==3.9.0 +terminado==0.18.1 +threadpoolctl==3.6.0 +tinycss2==1.4.0 +torch==2.9.0+cpu +tornado==6.5.2 +traitlets==5.14.3 +typing_extensions==4.15.0 +tzdata==2025.2 +uri-template==1.3.0 +urllib3==2.5.0 +URLObject==3.0.0 +wcwidth==0.2.14 +webcolors==25.10.0 +webencodings==0.5.1 +websocket-client==1.9.0 +Werkzeug==3.1.4 +WTForms==3.2.1 diff --git a/requirements.txt b/requirements.txt index f8efd1d..45a1f4f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,6 @@ Flask==2.3.2 Flask-SQLAlchemy==3.1.1 Flask-Dance==7.0.0 gunicorn==21.2.0 -python-dotenv==1.0.0 \ No newline at end of file +python-dotenv==1.0.0 +flask-admin[sqlalchemy,s3,images,export,translation]==1.6.1 +setuptools<81 \ No newline at end of file diff --git a/todo.py b/todo.py index 299a7ed..e8f2e97 100644 --- a/todo.py +++ b/todo.py @@ -1,5 +1,6 @@ # todo.py - todo functionality from flask import Blueprint, render_template, request, redirect, session + # models.py from flask_sqlalchemy import SQLAlchemy from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass, Mapped, mapped_column From 1f4d3885664ae256a3c6d532daaceafc5b204537 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Wed, 14 Jan 2026 14:03:04 +0000 Subject: [PATCH 16/25] Refactor README for improved formatting and clarity --- README.md | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 150f89d..4b6191d 100644 --- a/README.md +++ b/README.md @@ -18,22 +18,27 @@ - Ready for Render deployment - GitHub Actions CI/CD --> + ### Flask - - Webserver with routing (a function for each url endpoint) - - Jinja templates for looping though and outputting data. - - todo.py contains the endpoints for the Todo app + +- Webserver with routing (a function for each url endpoint) +- Jinja templates for looping though and outputting data. +- todo.py contains the endpoints for the Todo app ### SQLAlchemy & SQLite / PostgreSQL - - SQL Database - - Managed by SQLAlchemy an Object Relationship Manager which allows you to write classes that define the data and provides the storage & CRUD for you. - - ORMs build the database for you from your classes, start with SQLite but you can move PostgreSQL or others when you are ready. - - todo.py includes the Todo class that provdes all you need for the building of the database and all the CRUD. + +- SQL Database +- Managed by SQLAlchemy an Object Relationship Manager which allows you to write classes that define the data and provides the storage & CRUD for you. +- ORMs build the database for you from your classes, start with SQLite but you can move PostgreSQL or others when you are ready. +- todo.py includes the Todo class that provdes all you need for the building of the database and all the CRUD. ### Authentication (GitHub + Auth0) - - GitHub OAuth (Flask-Dance) for local Windows development - - Auth0 OAuth for Codespaces and Render production + +- GitHub OAuth (Flask-Dance) for local Windows development +- Auth0 OAuth for Codespaces and Render production ### Render & Github Actions + - Ready for Render deployment - GitHub Actions CI/CD @@ -42,12 +47,14 @@ ### Clone the Repository **Using Git Command Line:** + ```bash git clone https://github.com/stretchyboy/python-todo.git cd python-todo ``` **Using GitHub Desktop:** + 1. Open GitHub Desktop 2. Click `File` → `Clone repository` 3. Select the `URL` tab @@ -71,12 +78,11 @@ cp .env.example .env Open `.env.example` and save as `.env` - ## Environment Configuration (.env) Create a `.env` file in the root directory with the following variables: -``` +```bash APP_SECRET_KEY=your-secret-key-here GITHUB_CLIENT_ID=your-github-client-id GITHUB_CLIENT_SECRET=your-github-client-secret @@ -129,7 +135,7 @@ For local Windows development with GitHub Desktop: Start the Flask development server: ```bash -python -m flask run +py -m flask run --host=localhost --port=5000 #it maybe python3 on your machine ``` The app will be available at [http://localhost:5000](http://localhost:5000) @@ -163,4 +169,3 @@ See [CODESPACES_SETUP.md](CODESPACES_SETUP.md) for complete GitHub Codespaces se ## Deployment on Render See [RENDER_SETUP.md](RENDER_SETUP.md) for complete Render deployment instructions, including setup, configuration, environment variables, and continuous deployment. - From 93a3817d022104376f3af827685fc7da78263a54 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Wed, 14 Jan 2026 14:03:15 +0000 Subject: [PATCH 17/25] Add flask_babel to requirements for internationalization support --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 45a1f4f..3c58234 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,6 @@ Flask-SQLAlchemy==3.1.1 Flask-Dance==7.0.0 gunicorn==21.2.0 python-dotenv==1.0.0 +flask_babel==3.1.0 flask-admin[sqlalchemy,s3,images,export,translation]==1.6.1 setuptools<81 \ No newline at end of file From 6007c9b10bf9f39ecd09224e5e08db4d4b06d3cb Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Wed, 14 Jan 2026 14:05:12 +0000 Subject: [PATCH 18/25] Fix formatting in README for clarity in Flask run command --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4b6191d..c7fc449 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ For local Windows development with GitHub Desktop: Start the Flask development server: ```bash -py -m flask run --host=localhost --port=5000 #it maybe python3 on your machine +py -m flask run --host=localhost --port=5000 # it maybe python3 on your machine ``` The app will be available at [http://localhost:5000](http://localhost:5000) From b88ab2c3b0dc8ebcc05739ae203401292b1a1364 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Wed, 14 Jan 2026 14:49:04 +0000 Subject: [PATCH 19/25] Adding catergories exercise --- .vscode/extensions.json | 3 +- ADDING_CATERGORIES.md | 300 ++++++++++++++++++++++++++++++++++++++++ README.md | 3 + 3 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 ADDING_CATERGORIES.md diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 8c9cbc8..d6ad130 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,6 +3,7 @@ "recommendations": [ "ms-python.python", "ms-python.vscode-pylance", - "qwtel.sqlite-viewer" + "qwtel.sqlite-viewer", + "mermaidchart.vscode-mermaid-chart" ] } diff --git a/ADDING_CATERGORIES.md b/ADDING_CATERGORIES.md new file mode 100644 index 0000000..aca93f6 --- /dev/null +++ b/ADDING_CATERGORIES.md @@ -0,0 +1,300 @@ +# How to Add Categories to Your Todo App + +This guide will walk you through adding categories (like "Urgent" and "Non-urgent") to your todo app. Follow each step carefully and copy the code exactly as shown. + +## What We're Building + +We're adding a **category system** to organize todos. Each todo must belong to one category (like "Urgent" or "Non-urgent"). Users will select a category from a dropdown menu when creating a new todo. Administrators can add, edit, or delete categories through the admin interface at `/admin/`. + +The system uses two database tables with a **one-to-many relationship**: one category can have many todos, but each todo belongs to exactly one category. + +```mermaid +erDiagram + Category ||--o{ Todo : "has many" + + Category { + int id PK + string name UK + } + + Todo { + int id PK + string task + string user_id + int category_id FK + boolean done + } +``` + +--- + +## Step 1: Update `todo.py` - Add the Category Model + +### 1.1: Add ForeignKey import +Find this line near the top of `todo.py`: +```python +from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass, Mapped, mapped_column +``` + +Change it to: +```python +from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass, Mapped, mapped_column +from sqlalchemy import ForeignKey +``` + +### 1.2: Add the Category class +Find the line that says `todo_bp = Blueprint('todo', __name__)`. + +**Just BEFORE** that line, add this new class: +```python +class Category(db.Model): + __tablename__ = "categories" + + id: Mapped[int] = mapped_column(primary_key=True, init=False) + name: Mapped[str] = mapped_column(db.String(50), nullable=False, unique=True) + + def __repr__(self): + return self.name + + +``` + +**Important:** Make sure to leave a blank line after `pass` and before `todo_bp = Blueprint`. + +### 1.3: Update the Todo class +Find the `Todo` class. It should look like this: +```python +class Todo(db.Model): + __tablename__ = "todos" + + id: Mapped[int] = mapped_column(primary_key=True, init=False) + task: Mapped[str] = mapped_column(db.String(200), nullable=False) + user_id: Mapped[str] = mapped_column(db.String(100), nullable=False) + done: Mapped[bool] = mapped_column(db.Boolean, default=False) +``` + +Add a new line after `user_id` to add the category field: +```python +class Todo(db.Model): + __tablename__ = "todos" + + id: Mapped[int] = mapped_column(primary_key=True, init=False) + task: Mapped[str] = mapped_column(db.String(200), nullable=False) + user_id: Mapped[str] = mapped_column(db.String(100), nullable=False) + category_id: Mapped[int] = mapped_column(ForeignKey('categories.id'), nullable=False) + done: Mapped[bool] = mapped_column(db.Boolean, default=False) +``` + +--- + +## Step 2: Update Routes in `todo.py` + +### 2.1: Update the home() function +Find the `home()` function and change it to pass categories to the template: + +**Old code:** +```python +@todo_bp.route('/') +def home(): + user = get_current_user() + if not user: + return render_template('login.html') + session['user_id'] = user["id"] + todos = Todo.query.filter_by(user_id=session['user_id']).all() + return render_template('index.html', todos=todos, user=user) +``` + +**New code:** +```python +@todo_bp.route('/') +def home(): + user = get_current_user() + if not user: + return render_template('login.html') + session['user_id'] = user["id"] + todos = Todo.query.filter_by(user_id=session['user_id']).all() + categories = Category.query.all() + return render_template('index.html', todos=todos, categories=categories, user=user) +``` + +### 2.2: Update the add() function +Find the `add()` function and change it to capture the category: + +**Old code:** +```python +@todo_bp.route('/add', methods=['POST']) +def add(): + if 'user_id' not in session: + return redirect('/') + task_text = request.form['task'] + new_task = Todo(task=task_text, done=False, user_id=session['user_id']) + db.session.add(new_task) + db.session.commit() + return redirect('/') +``` + +**New code:** +```python +@todo_bp.route('/add', methods=['POST']) +def add(): + if 'user_id' not in session: + return redirect('/') + task_text = request.form['task'] + category_id = request.form.get('category_id', type=int) + if not category_id: + return redirect('/') + new_task = Todo(task=task_text, category_id=category_id, user_id=session['user_id']) + db.session.add(new_task) + db.session.commit() + return redirect('/') +``` + +### 2.3: Update the init_app() function +Find the `init_app()` function at the bottom of `todo.py`. Add code to seed the initial categories: + +**Old code:** +```python +def init_app(app): + db.init_app(app) + with app.app_context(): + db.create_all() +``` + +**New code:** +```python +def init_app(app): + db.init_app(app) + with app.app_context(): + db.create_all() + # Seed initial categories if they don't exist + if Category.query.count() == 0: + urgent = Category(name="Urgent") + non_urgent = Category(name="Non-urgent") + db.session.add(urgent) + db.session.add(non_urgent) + db.session.commit() +``` + +--- + +## Step 3: Update `templates/index.html` - Add Category Dropdown + +Find the form in `index.html`: + +**Old code:** +```html +
      + + +
      +``` + +**New code:** +```html +
      + + + +
      +``` + +--- + +## Step 4: Update `app.py` - Import Category + +Find this line near the top of `app.py`: +```python +from todo import todo_bp, init_app as init_todo +from todo import db, Todo +``` + +Change it to: +```python +from todo import todo_bp, init_app as init_todo +from todo import db, Todo, Category +``` + +Then find this line near the bottom: +```python +init_admin(app, db, Todo) +``` + +Change it to: +```python +init_admin(app, db, Todo, Category) +``` + +--- + +## Step 5: Update `admin.py` - Add Category Admin View + +Find the `init_admin()` function in `admin.py`: + +**Old code:** +```python +def init_admin(app, db, model): + """Attach Babel and register secured admin views for the given model.""" + Babel(app, locale_selector=lambda: 'en') + admin = Admin(app, name="Admin", template_mode="bootstrap4", + index_view=AuthenticatedAdminIndexView()) + admin.add_view(AuthenticatedModelView(model, db.session, + endpoint="todo_admin", + name="Todos")) + return admin +``` + +**New code:** +```python +def init_admin(app, db, todo_model, category_model): + """Attach Babel and register secured admin views for the given models.""" + Babel(app, locale_selector=lambda: 'en') + admin = Admin(app, name="Admin", template_mode="bootstrap4", + index_view=AuthenticatedAdminIndexView()) + admin.add_view(AuthenticatedModelView(todo_model, db.session, + endpoint="todo_admin", + name="Todos")) + admin.add_view(AuthenticatedModelView(category_model, db.session, + endpoint="category_admin", + name="Categories")) + return admin +``` + +--- + +## Step 6: Reset Your Database + +Because you've changed the database structure, you need to delete the old database: + +1. Stop your Flask app if it's running (press Ctrl+C in the terminal) +2. Delete the database file from teh instance folder. + +Restart your Flask app: +```bash +py -m flask run --host=localhost --port=5000 # it maybe python3 on your machine +``` + +The app will create a new database with the "Urgent" and "Non-urgent" categories automatically. + +--- + +## Testing Your Changes + +1. Go to the home page - you should see a dropdown to select a category when adding a task +2. Add a task with a category selected +3. Log in and go to `/admin/` to see the Categories section where you can add, edit, or delete categories + +--- + +## Summary of Changes + +- **Created** a new `Category` model +- **Added** a foreign key relationship from `Todo` to `Category` +- **Updated** the form to include a category dropdown +- **Modified** the add route to capture the selected category +- **Added** automatic seeding of initial categories +- **Enabled** category management in the admin interface \ No newline at end of file diff --git a/README.md b/README.md index c7fc449..dfa3861 100644 --- a/README.md +++ b/README.md @@ -158,8 +158,11 @@ The database file is stored in `/instance/todo.db` ## Your Development +Try [ADDING_CATERGORIES.md](ADDING_CATERGORIES.md) to add one-to-many relationship and Catergories for the tasks. +Then what could you make with the same ideas but different entities (things)? +Books and People could make a library etc .... ## Codespaces Setup From 247f7c9c6a754b2172552615bb8d2472453c71c0 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Thu, 15 Jan 2026 09:04:56 +0000 Subject: [PATCH 20/25] Add initial sample Todo item for new users and fix the userid creation for github only login --- auth/github.py | 2 +- todo.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/auth/github.py b/auth/github.py index dace956..2922f08 100644 --- a/auth/github.py +++ b/auth/github.py @@ -20,7 +20,7 @@ def get_github_user(): data = session["github"] # Prefix user id for compatibility user = { - "id": f"github:{data['id']}", + "id": f"github|{data['id']}", "name": data["login"], "email": data.get("email", "") } diff --git a/todo.py b/todo.py index e8f2e97..d9b460c 100644 --- a/todo.py +++ b/todo.py @@ -4,6 +4,7 @@ # models.py from flask_sqlalchemy import SQLAlchemy from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass, Mapped, mapped_column +from sqlalchemy import ForeignKey from auth import get_current_user @@ -68,3 +69,8 @@ def init_app(app): db.init_app(app) with app.app_context(): db.create_all() + + if Todo.query.count() == 0: + mreggleton = Todo(task="Mr Eggleton checking your Todo App!", done=False, user_id="github|5987806") + db.session.add(mreggleton) + db.session.commit() \ No newline at end of file From c5911503487561e447bdbc715786ac77a8f1fc31 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Thu, 15 Jan 2026 10:46:54 +0000 Subject: [PATCH 21/25] Improve the documention --- ADDING_CATERGORIES.md | 52 ++++++++++++++++++++------------- CODESPACES_SETUP.md | 2 +- README.md | 68 +++++++++++++++---------------------------- RENDER_SETUP.md | 2 +- 4 files changed, 57 insertions(+), 67 deletions(-) diff --git a/ADDING_CATERGORIES.md b/ADDING_CATERGORIES.md index aca93f6..863d4ce 100644 --- a/ADDING_CATERGORIES.md +++ b/ADDING_CATERGORIES.md @@ -30,22 +30,10 @@ erDiagram ## Step 1: Update `todo.py` - Add the Category Model -### 1.1: Add ForeignKey import -Find this line near the top of `todo.py`: -```python -from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass, Mapped, mapped_column -``` +### 1.1: Add the Category class +Find the line that says `db = SQLAlchemy(model_class=Base)`. -Change it to: -```python -from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass, Mapped, mapped_column -from sqlalchemy import ForeignKey -``` - -### 1.2: Add the Category class -Find the line that says `todo_bp = Blueprint('todo', __name__)`. - -**Just BEFORE** that line, add this new class: +**Just AFTER** that line, add this new class: ```python class Category(db.Model): __tablename__ = "categories" @@ -53,15 +41,13 @@ class Category(db.Model): id: Mapped[int] = mapped_column(primary_key=True, init=False) name: Mapped[str] = mapped_column(db.String(50), nullable=False, unique=True) - def __repr__(self): + def __repr__(self): # When you try to print or put this object in a template represent it as it's name return self.name ``` -**Important:** Make sure to leave a blank line after `pass` and before `todo_bp = Blueprint`. - -### 1.3: Update the Todo class +### 1.2: Update the Todo class Find the `Todo` class. It should look like this: ```python class Todo(db.Model): @@ -73,7 +59,7 @@ class Todo(db.Model): done: Mapped[bool] = mapped_column(db.Boolean, default=False) ``` -Add a new line after `user_id` to add the category field: +Add a new line after `user_id` to add the category field. And add a new function / method which will make todo.catergory return the Catergory object that is linked by the catergory_id Foreign Key: ```python class Todo(db.Model): __tablename__ = "todos" @@ -83,6 +69,10 @@ class Todo(db.Model): user_id: Mapped[str] = mapped_column(db.String(100), nullable=False) category_id: Mapped[int] = mapped_column(ForeignKey('categories.id'), nullable=False) done: Mapped[bool] = mapped_column(db.Boolean, default=False) + + @property # todo.category is a property (member variable) of the todo object + def category(self): # return the category object linked to this Todo by category_id + return Category.query.get(self.category_id) ``` --- @@ -158,6 +148,11 @@ def init_app(app): db.init_app(app) with app.app_context(): db.create_all() + + if Todo.query.count() == 0: + mreggleton = Todo(task="Mr Eggleton checking your Todo App!", done=False, user_id="github|5987806") + db.session.add(mreggleton) + db.session.commit() ``` **New code:** @@ -173,6 +168,11 @@ def init_app(app): db.session.add(urgent) db.session.add(non_urgent) db.session.commit() + + if Todo.query.count() == 0: + mreggleton_check = Todo(task="Mr Eggleton checking your Todo App!", done=False, user_id="github|5987806", category_id=non_urgent.id) + db.session.add(mreggleton_check) + db.session.commit() ``` --- @@ -203,6 +203,18 @@ Find the form in `index.html`: ``` +Find the task text being printed out and add the + +**Old code:** +```html + {{ todo.task }} +``` + +**New code:** +```html + {{ todo.task }} [{{ todo.category }}] +``` + --- ## Step 4: Update `app.py` - Import Category diff --git a/CODESPACES_SETUP.md b/CODESPACES_SETUP.md index 67b4632..cdc1fe7 100644 --- a/CODESPACES_SETUP.md +++ b/CODESPACES_SETUP.md @@ -7,7 +7,7 @@ GitHub Codespaces is a flexible cloud-based development environment. Your editor ### Create a New Codespace 1. **Go to the Repository** - - Navigate to [https://github.com/stretchyboy/python-todo](https://github.com/stretchyboy/python-todo) (or your fork) + - Navigate to [https://github.com/mr-eggleton/python-flask-todo](https://github.com/mr-eggleton/python-flask-todo) (or your fork) 2. **Create a Codespace** - Click the green **"Code"** button diff --git a/README.md b/README.md index dfa3861..da73eee 100644 --- a/README.md +++ b/README.md @@ -4,43 +4,37 @@ ![Flask](https://img.shields.io/badge/Flask-2.3-green) ![Render](https://img.shields.io/badge/Deploy-Render-purple) +A simple Python Todo Web App to do some improvments on and be a starting point for your own more apps. + + ## Features - ### Flask -- Webserver with routing (a function for each url endpoint) -- Jinja templates for looping though and outputting data. +- [Flask](https://flask.palletsprojects.com/en/stable/) based Python Webserver with routing (a function for each url endpoint users can visit) +- HTML / [Jinja templates](https://jinja.palletsprojects.com/en/stable/templates/) for looping though and outputting data. - todo.py contains the endpoints for the Todo app ### SQLAlchemy & SQLite / PostgreSQL -- SQL Database -- Managed by SQLAlchemy an Object Relationship Manager which allows you to write classes that define the data and provides the storage & CRUD for you. -- ORMs build the database for you from your classes, start with SQLite but you can move PostgreSQL or others when you are ready. -- todo.py includes the Todo class that provdes all you need for the building of the database and all the CRUD. +- SQL Databases the modern way +- Managed by [SQLAlchemy](https://www.sqlalchemy.org/) an ORM / [Object Relationship Mapper](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) which allows you to write classes that define the data and provides the storage & [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) for you. +- ORMs build the database for you from your classes so you define what you want to store how it connects together and any extras calculations / functions you need . +- Start with SQLite but you can move to proffesional systems like PostgreSQL or others when you are ready. +- todo.py includes the Todo class that provdes all you need for the building of the database and all the [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete). ### Authentication (GitHub + Auth0) +Authentication is the act of proving who you are, in this system we use external Authentication systems so we aren't storing usernames & passwords (reducing the DPA responsiblilties ) + - GitHub OAuth (Flask-Dance) for local Windows development - Auth0 OAuth for Codespaces and Render production ### Render & Github Actions -- Ready for Render deployment -- GitHub Actions CI/CD +- Ready for Render deployment so you can publish and use the site for free (there are some speed limitations) +- GitHub Actions CI/CD to build the site when you commit a working version +- Can be upgraded to use a free PostgreSQL daatbase server (but there are some other ) ## Setup @@ -49,8 +43,8 @@ **Using Git Command Line:** ```bash -git clone https://github.com/stretchyboy/python-todo.git -cd python-todo +git clone https://github.com/mr-eggleton/python-flask-todo.git +cd python-flask-todo ``` **Using GitHub Desktop:** @@ -58,7 +52,7 @@ cd python-todo 1. Open GitHub Desktop 2. Click `File` → `Clone repository` 3. Select the `URL` tab -4. Enter: `https://github.com/stretchyboy/python-todo.git` +4. Enter: `https://github.com/mr-eggleton/python-flask-todo.git` 5. Choose a local path and click `Clone` ### Install Dependencies @@ -74,30 +68,13 @@ py -m pip install -r requirements.txt cp .env.example .env ``` -### On Windows in VS Code +#### On Windows in VS Code Open `.env.example` and save as `.env` ## Environment Configuration (.env) -Create a `.env` file in the root directory with the following variables: - -```bash -APP_SECRET_KEY=your-secret-key-here -GITHUB_CLIENT_ID=your-github-client-id -GITHUB_CLIENT_SECRET=your-github-client-secret -AUTH0_DOMAIN=your-auth0-domain.auth0.com -AUTH0_CLIENT_ID=your-auth0-client-id -AUTH0_CLIENT_SECRET=your-auth0-client-secret -AUTH0_CALLBACK_URL=http://localhost:5000/callback -OAUTHLIB_INSECURE_TRANSPORT=1 -``` - -### Generate APP_SECRET_KEY - -```bash -python -c "import secrets; print(secrets.token_hex(32))" -``` +Edit the file to put the details you need in. But @ UTC Sheffield OLP, Mr Eggleton will give you a .env file that will work with github, and you don't need to do the "Authentication Setup" and you can skip to ['Running the Application'](#running-the-application) ## Authentication Setup @@ -152,13 +129,14 @@ The database file is stored in `/instance/todo.db` - Persistent records in a database. The current database will be destroyed each time you push to render, ( You can modify the code once it's on Render to move to PostgreSQL ). - Changing database structure SQLAlchemy Migrations. Currently we aren't handling changes to the database structure so you need to delete the local .db and start again (render wil do this anyway on a rebuild as mentioned above). They can be handled with Migrations -- Storing any user data in a database (other than an id from github ). To have users on this system to store any other PII refer to [https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy](https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy) and change the privacy statement. +- Minimal Autorisation all Authenticated users can do everything on the site. +- Storing any user data in a database (other than an id from github or Auth0 ). To have users on this system to store any other PII refer to [https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy](https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy) and change the privacy statement. - Adding extra security [https://flask-security.readthedocs.io/en/stable/quickstart.html#basic-flask-sqlalchemy-application](https://flask-security.readthedocs.io/en/stable/quickstart.html#basic-flask-sqlalchemy-application) - Testing. There are no tests in this code. ## Your Development -Try [ADDING_CATERGORIES.md](ADDING_CATERGORIES.md) to add one-to-many relationship and Catergories for the tasks. +Try [ADDING_CATERGORIES.md](ADDING_CATERGORIES.md) to add a one-to-many relationship and Categories for the tasks. Then what could you make with the same ideas but different entities (things)? diff --git a/RENDER_SETUP.md b/RENDER_SETUP.md index 9259767..fbf910a 100644 --- a/RENDER_SETUP.md +++ b/RENDER_SETUP.md @@ -74,7 +74,7 @@ Ensure your repository contains: **Important:** Do NOT set `RENDER_EXTERNAL_HOSTNAME` manually. Render sets this automatically, but it's only available at runtime, not during build. - **For Auth0 Configuration:** Use your actual Render app URL (e.g., `https://python-todo.onrender.com`) in Auth0 settings, not the variable name. + **For Auth0 Configuration:** Use your actual Render app URL (e.g., `https://python-flask-todo.onrender.com`) in Auth0 settings, not the variable name. 3. **Automatic Deployment** - Render will automatically build and deploy your application From 35a87858459852cabcc5bb2b342cc7c8b1fab27c Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Thu, 15 Jan 2026 15:12:37 +0000 Subject: [PATCH 22/25] Update .gitignore and improve README for use as a slide show --- .gitignore | 4 ++++ README.md | 68 ++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index b7faf40..0882edc 100644 --- a/.gitignore +++ b/.gitignore @@ -205,3 +205,7 @@ cython_debug/ marimo/_static/ marimo/_lsp/ __marimo__/ + + +# Obsidian-Vault +.obsidian/ \ No newline at end of file diff --git a/README.md b/README.md index da73eee..39d44d0 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,9 @@ ![Flask](https://img.shields.io/badge/Flask-2.3-green) ![Render](https://img.shields.io/badge/Deploy-Render-purple) -A simple Python Todo Web App to do some improvments on and be a starting point for your own more apps. +A simple Python Todo Web App to do some improvements on and be a starting point for your own simple web apps. +--- ## Features @@ -15,13 +16,21 @@ A simple Python Todo Web App to do some improvments on and be a starting point f - HTML / [Jinja templates](https://jinja.palletsprojects.com/en/stable/templates/) for looping though and outputting data. - todo.py contains the endpoints for the Todo app +--- + ### SQLAlchemy & SQLite / PostgreSQL -- SQL Databases the modern way +- SQL Databases the modern way - Managed by [SQLAlchemy](https://www.sqlalchemy.org/) an ORM / [Object Relationship Mapper](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) which allows you to write classes that define the data and provides the storage & [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) for you. + +-- +###  [Object Relationship Mapper](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) + - ORMs build the database for you from your classes so you define what you want to store how it connects together and any extras calculations / functions you need . - Start with SQLite but you can move to proffesional systems like PostgreSQL or others when you are ready. -- todo.py includes the Todo class that provdes all you need for the building of the database and all the [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete). +- todo.py includes the Todo class that provdes all you need for the building of the database and all the [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete). + +--- ### Authentication (GitHub + Auth0) @@ -30,22 +39,23 @@ Authentication is the act of proving who you are, in this system we use external - GitHub OAuth (Flask-Dance) for local Windows development - Auth0 OAuth for Codespaces and Render production +--- + ### Render & Github Actions -- Ready for Render deployment so you can publish and use the site for free (there are some speed limitations) +- Ready for [Render](https://render.com/) deployment so you can publish and use the site online for free (there are some speed limitations) - GitHub Actions CI/CD to build the site when you commit a working version - Can be upgraded to use a free PostgreSQL daatbase server (but there are some other ) +--- + ## Setup -### Clone the Repository +### Start from the Template -**Using Git Command Line:** +1. Go to the github repository: -```bash -git clone https://github.com/mr-eggleton/python-flask-todo.git -cd python-flask-todo -``` +### Clone the Repository **Using GitHub Desktop:** @@ -54,27 +64,34 @@ cd python-flask-todo 3. Select the `URL` tab 4. Enter: `https://github.com/mr-eggleton/python-flask-todo.git` 5. Choose a local path and click `Clone` +6. Click 'Open in Visual Studio Code' to open the project in VS Code -### Install Dependencies +--- + +**Using Git Command Line:** ```bash -py -m pip install -r requirements.txt +git clone https://github.com/mr-eggleton/python-flask-todo.git +cd python-flask-todo ``` -### Copy Example Environment File +--- + +### Install Dependencies ```bash -# On linux or codespaces -cp .env.example .env +py -m pip install -r requirements.txt # You'll need python3 ... in linux ``` -#### On Windows in VS Code +--- -Open `.env.example` and save as `.env` +### Environment Configuration (.env) -## Environment Configuration (.env) +In VS Code open `.env.example` and save it as `.env` -Edit the file to put the details you need in. But @ UTC Sheffield OLP, Mr Eggleton will give you a .env file that will work with github, and you don't need to do the "Authentication Setup" and you can skip to ['Running the Application'](#running-the-application) +Edit the file to put the details you need in. But @ UTC Sheffield OLP, Mr Eggleton will give you a .env file that will work with github, and you don't need to do the "Authentication Setup" as you are using his and you can skip to ['Running the Application'](#running-the-application) + +--- ## Authentication Setup @@ -88,6 +105,8 @@ This app automatically detects your environment and uses the appropriate authent The app checks for Codespaces environment variables (`CODESPACES`, `CODESPACE_NAME`) and routes accordingly. +--- + ### GitHub OAuth Setup (Local Development) For local Windows development with GitHub Desktop: @@ -107,6 +126,8 @@ For local Windows development with GitHub Desktop: 3. **Enable Insecure Transport for Local Dev** - Set `OAUTHLIB_INSECURE_TRANSPORT=1` in `.env` (only for local development) +--- + ## Running the Application Start the Flask development server: @@ -117,6 +138,8 @@ py -m flask run --host=localhost --port=5000 # it maybe python3 on your machine The app will be available at [http://localhost:5000](http://localhost:5000) +--- + ## The Database This code uses [SQLAlchemy](https://www.sqlalchemy.org/) to set up classes that have methods to talk to many [databases](https://docs.sqlalchemy.org/en/20/dialects/index.html). We use **SQLite for simplicity and easy local development**. @@ -125,6 +148,8 @@ This code uses [SQLAlchemy](https://www.sqlalchemy.org/) to set up classes that The database file is stored in `/instance/todo.db` +--- + ## Things we are ignoring - Persistent records in a database. The current database will be destroyed each time you push to render, ( You can modify the code once it's on Render to move to PostgreSQL ). @@ -132,7 +157,9 @@ The database file is stored in `/instance/todo.db` - Minimal Autorisation all Authenticated users can do everything on the site. - Storing any user data in a database (other than an id from github or Auth0 ). To have users on this system to store any other PII refer to [https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy](https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy) and change the privacy statement. - Adding extra security [https://flask-security.readthedocs.io/en/stable/quickstart.html#basic-flask-sqlalchemy-application](https://flask-security.readthedocs.io/en/stable/quickstart.html#basic-flask-sqlalchemy-application) -- Testing. There are no tests in this code. +- Testing. There are no tests in this code, although Flask, SQL Alchemy and the other libraries used are thouroughly tested and are checked for security issues. + +--- ## Your Development @@ -142,6 +169,7 @@ Then what could you make with the same ideas but different entities (things)? Books and People could make a library etc .... +--- ## Codespaces Setup From 871be2f96069ec05f2886c23ea34b9cd6b2a47e6 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Thu, 15 Jan 2026 15:26:00 +0000 Subject: [PATCH 23/25] Update setup documentation for clarity and consistency across files --- CODESPACES_SETUP.md | 4 ++-- README.md | 17 ++++++++++++++--- RENDER_SETUP.md | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/CODESPACES_SETUP.md b/CODESPACES_SETUP.md index cdc1fe7..b3c7d50 100644 --- a/CODESPACES_SETUP.md +++ b/CODESPACES_SETUP.md @@ -6,8 +6,8 @@ GitHub Codespaces is a flexible cloud-based development environment. Your editor ### Create a New Codespace -1. **Go to the Repository** - - Navigate to [https://github.com/mr-eggleton/python-flask-todo](https://github.com/mr-eggleton/python-flask-todo) (or your fork) +1. **Go to your Repository** + - Navigate to your **python-flask-todo** 2. **Create a Codespace** - Click the green **"Code"** button diff --git a/README.md b/README.md index 39d44d0..c9ecba8 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,18 @@ Authentication is the act of proving who you are, in this system we use external ### Start from the Template -1. Go to the github repository: +1. Go to the github repository [https://github.com/UTCSheffield/python-flask-todo](https://github.com/UTCSheffield/python-flask-todo) +2. Click the green "Use this template" button at the top of the page +3. Select "Create a new repository" +4. Fill in your new repository details: + - Choose a repository name (e.g., `python-flask-todo`) + - Add a description (optional) + - Choose Public or Private visibility +5. Click "Create repository from template" +6. Your new repository will be created with all the template files +7. Now clone your new repository using one of the methods below + +--- ### Clone the Repository @@ -62,7 +73,7 @@ Authentication is the act of proving who you are, in this system we use external 1. Open GitHub Desktop 2. Click `File` → `Clone repository` 3. Select the `URL` tab -4. Enter: `https://github.com/mr-eggleton/python-flask-todo.git` +4. Enter: `https://github.com/UTCSheffield/python-flask-todo.git` 5. Choose a local path and click `Clone` 6. Click 'Open in Visual Studio Code' to open the project in VS Code @@ -71,7 +82,7 @@ Authentication is the act of proving who you are, in this system we use external **Using Git Command Line:** ```bash -git clone https://github.com/mr-eggleton/python-flask-todo.git +git clone https://github.com/UTCSheffield/python-flask-todo.git cd python-flask-todo ``` diff --git a/RENDER_SETUP.md b/RENDER_SETUP.md index fbf910a..4f0f275 100644 --- a/RENDER_SETUP.md +++ b/RENDER_SETUP.md @@ -49,7 +49,7 @@ Ensure your repository contains: 3. **Connect Your GitHub Repository** - Click "Connect account" if this is your first time - Authorize Render to access your GitHub repositories - - Search for and select `mr-eggleton/python-flask-todo` (or your fork) + - Search for select your version of `python-flask-todo` - Click "Connect" 4. **Review Blueprint Configuration** From 3327cf9e7f425203bb2710010e691eee6a45a998 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Fri, 16 Jan 2026 13:08:14 +0000 Subject: [PATCH 24/25] Lesson plan --- .env.example | 8 +- ADDING_CATERGORIES.md | 40 +++- LESSON.md | 487 ++++++++++++++++++++++++++++++++++++++++++ README.md | 58 ++--- SaveAs.png | Bin 0 -> 2431 bytes 5 files changed, 560 insertions(+), 33 deletions(-) create mode 100644 LESSON.md create mode 100644 SaveAs.png diff --git a/.env.example b/.env.example index 043d9db..11505d0 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,13 @@ APP_SECRET_KEY=your_flask_secret -OAUTHLIB_INSECURE_TRANSPORT=0 DATABASE_URL=sqlite:///todo.db +# Example environment variables for GitHub OAuth for local development +GITHUB_CLIENT_ID=your_client_id +GITHUB_CLIENT_SECRET=your_client_secret +# Only needed for local/GitHub OAuth +# OAUTHLIB_INSECURE_TRANSPORT=1 + + # Example environment variables for Auth0 integration AUTH0_DOMAIN=your_auth0_domain AUTH0_CLIENT_ID=your_client_id diff --git a/ADDING_CATERGORIES.md b/ADDING_CATERGORIES.md index 863d4ce..a99eeea 100644 --- a/ADDING_CATERGORIES.md +++ b/ADDING_CATERGORIES.md @@ -8,6 +8,8 @@ We're adding a **category system** to organize todos. Each todo must belong to o The system uses two database tables with a **one-to-many relationship**: one category can have many todos, but each todo belongs to exactly one category. +--- + ```mermaid erDiagram Category ||--o{ Todo : "has many" @@ -31,9 +33,11 @@ erDiagram ## Step 1: Update `todo.py` - Add the Category Model ### 1.1: Add the Category class + Find the line that says `db = SQLAlchemy(model_class=Base)`. **Just AFTER** that line, add this new class: + ```python class Category(db.Model): __tablename__ = "categories" @@ -48,7 +52,9 @@ class Category(db.Model): ``` ### 1.2: Update the Todo class + Find the `Todo` class. It should look like this: + ```python class Todo(db.Model): __tablename__ = "todos" @@ -59,7 +65,8 @@ class Todo(db.Model): done: Mapped[bool] = mapped_column(db.Boolean, default=False) ``` -Add a new line after `user_id` to add the category field. And add a new function / method which will make todo.catergory return the Catergory object that is linked by the catergory_id Foreign Key: +Add a new line after `user_id` to add the category field. And add a new function / method which will make todo.category return the Category object that is linked by the category_id Foreign Key: + ```python class Todo(db.Model): __tablename__ = "todos" @@ -80,9 +87,11 @@ class Todo(db.Model): ## Step 2: Update Routes in `todo.py` ### 2.1: Update the home() function + Find the `home()` function and change it to pass categories to the template: **Old code:** + ```python @todo_bp.route('/') def home(): @@ -95,6 +104,7 @@ def home(): ``` **New code:** + ```python @todo_bp.route('/') def home(): @@ -108,9 +118,11 @@ def home(): ``` ### 2.2: Update the add() function + Find the `add()` function and change it to capture the category: **Old code:** + ```python @todo_bp.route('/add', methods=['POST']) def add(): @@ -124,6 +136,7 @@ def add(): ``` **New code:** + ```python @todo_bp.route('/add', methods=['POST']) def add(): @@ -140,9 +153,11 @@ def add(): ``` ### 2.3: Update the init_app() function + Find the `init_app()` function at the bottom of `todo.py`. Add code to seed the initial categories: **Old code:** + ```python def init_app(app): db.init_app(app) @@ -156,6 +171,7 @@ def init_app(app): ``` **New code:** + ```python def init_app(app): db.init_app(app) @@ -182,6 +198,7 @@ def init_app(app): Find the form in `index.html`: **Old code:** + ```html
      @@ -190,6 +207,7 @@ Find the form in `index.html`: ``` **New code:** + ```html @@ -203,14 +221,16 @@ Find the form in `index.html`:
      ``` -Find the task text being printed out and add the +Find the task text being printed out and add the category next to it: **Old code:** + ```html {{ todo.task }} ``` **New code:** + ```html {{ todo.task }} [{{ todo.category }}] ``` @@ -220,23 +240,27 @@ Find the task text being printed out and add the ## Step 4: Update `app.py` - Import Category Find this line near the top of `app.py`: + ```python from todo import todo_bp, init_app as init_todo from todo import db, Todo ``` Change it to: + ```python from todo import todo_bp, init_app as init_todo from todo import db, Todo, Category ``` Then find this line near the bottom: + ```python init_admin(app, db, Todo) ``` Change it to: + ```python init_admin(app, db, Todo, Category) ``` @@ -248,6 +272,7 @@ init_admin(app, db, Todo, Category) Find the `init_admin()` function in `admin.py`: **Old code:** + ```python def init_admin(app, db, model): """Attach Babel and register secured admin views for the given model.""" @@ -261,6 +286,7 @@ def init_admin(app, db, model): ``` **New code:** + ```python def init_admin(app, db, todo_model, category_model): """Attach Babel and register secured admin views for the given models.""" @@ -283,12 +309,12 @@ def init_admin(app, db, todo_model, category_model): Because you've changed the database structure, you need to delete the old database: 1. Stop your Flask app if it's running (press Ctrl+C in the terminal) -2. Delete the database file from teh instance folder. - +2. Delete the database file from the instance folder. + Restart your Flask app: + ```bash -py -m flask run --host=localhost --port=5000 # it maybe python3 on your machine -``` +python3 -m flask run --host=localhost --port=5000 The app will create a new database with the "Urgent" and "Non-urgent" categories automatically. @@ -309,4 +335,4 @@ The app will create a new database with the "Urgent" and "Non-urgent" categories - **Updated** the form to include a category dropdown - **Modified** the add route to capture the selected category - **Added** automatic seeding of initial categories -- **Enabled** category management in the admin interface \ No newline at end of file +- **Enabled** category management in the admin interface diff --git a/LESSON.md b/LESSON.md new file mode 100644 index 0000000..f7f2b61 --- /dev/null +++ b/LESSON.md @@ -0,0 +1,487 @@ + +# Python as Dynamic Webserver + +--- + +## Web Tech + +```mermaid +mindmap + Web Server + HTML #10003; + Assets + Images #10003; + CSS #10003; + Javascript #10003; + Data Sources + Text Files #10003; + API + Database + Authentication + Types + Hand Built #10003; + Static Built #10003; + Dynamic + +``` + +--- +## Flask Todo App Starter + +A simple Python Todo Web App to do some improvements on and be a starting point for your own simple web apps. + +## [https://github.com/UTCSheffield/python-flask-todo](https://github.com/UTCSheffield/python-flask-todo) + +--- + +## Features + +### Flask + +- [Flask](https://flask.palletsprojects.com/en/stable/) based Python Webserver with routing (a function for each url endpoint users can visit) +- HTML / [Jinja templates](https://jinja.palletsprojects.com/en/stable/templates/) for looping though and outputting data and keeping process and display seperate.. +- todo.py contains the endpoints for the Todo app + +--- + +### SQLAlchemy & SQLite / PostgreSQL + +- SQL Databases the modern way +- Managed by [SQLAlchemy](https://www.sqlalchemy.org/) an ORM / [Object Relationship Mapper](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) which allows you to write classes that define the data and provides the storage & [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) for you. + +--- + +###  [Object Relationship Mapper](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) + +- ORMs build the database for you from your classes so you define what you want to store how it connects together and any extras calculations / functions you need . +- Start with SQLite but you can move to professional systems like PostgreSQL or others when you are ready. +- todo.py includes the Todo class that provides all you need for the building of the database and all the [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete). + +--- + +### SQLAlchemy Snippet + +```python +class Todo(db.Model): +    __tablename__ = "todos" + +    id: Mapped[int] = mapped_column(primary_key=True, init=False) +    task: Mapped[str] = mapped_column(db.String(200), nullable=False) +    user_id: Mapped[str] = mapped_column(db.String(100), nullable=False) +    done: Mapped[bool] = mapped_column(db.Boolean, default=False) +``` + +--- +### Flask Snippet + +```python +@todo_bp.route('/') +def home(): +    user = get_current_user() +    if not user: +        return render_template('login.html') + +    session['user_id'] = user["id"] +    todos = Todo.query.filter_by(user_id=session['user_id']).all() +    return render_template('index.html', todos=todos, user=user) +``` +#### CRUD Admin Snippet + +```python +init_admin(app, db, Todo) +``` + +--- + +### Authentication (GitHub + Auth0) + +Authentication is the act of proving who you are, in this system we use external authentication systems so we aren't storing usernames & passwords (reducing the DPA responsiblilties ). There are still some so we provide a privacy policy. + +- GitHub OAuth (Flask-Dance) for local Windows development +- Auth0 OAuth for Codespaces and Render production + +--- + +### Render & Github Actions + +- Ready for [Render](https://render.com/) deployment so you can publish and use the site online for free (there are some speed limitations) +- GitHub Actions CI/CD to build the site when you commit a working version +- Can be upgraded to use a free PostgreSQL database server (but there are some other steps) + +--- + +## Setup + +### Start from the Template + +1. Login to [github.com](https://github.com/) +2. Go to the github repository [https://github.com/UTCSheffield/python-flask-todo](https://github.com/UTCSheffield/python-flask-todo) +3. Click the green "Use this template" button at the top of the page +4. Select "Create a new repository" +5. Fill in your new repository details: + - Choose a repository name (e.g., `python-flask-todo`) + - Add a description (optional) + - Choose Public or Private visibility +6. Click "Create repository from template" +7. Your new repository will be created with all the template files + +--- + +### Clone your Repository locally + +**Using GitHub Desktop:** + +1. On the GitHub page for your new repository +2. Click the green "Code" button +3. Click "Open with GitHub Desktop" +4. You may need to login to GitHub Desktop if you haven't already +5. You may be prompted to choose a local path to clone the repository to +6. Click 'Open in Visual Studio Code' to open the project in VS Code + +--- + +## Top Tip + +Split screen with the browser with README or LESSON open on one side and VS Code on the other. + +--- + +### Install Dependencies + +```bash +py -m pip install -r requirements.txt # You'll need python3 ... in linux +``` + +--- + +### Environment Configuration (.env) + +In VS Code open `.env.example` and save it as `.env` + +![[SaveAs.png]] + +You will need to set **Save as type** to "No Extension (*.)" which is at the bottom of the list + +@ UTC Sheffield OLP, Mr Eggleton will give you the contents for the `.env` file that will work with our github setup, + +--- + +## Running the Application + +Start the Flask development server: + +```bash +py -m flask run --host=localhost --port=5000 # it maybe python3 on your machine +``` + +The app will be available at [http://localhost:5000](http://localhost:5000) + +Try it, login and create a few tasks! + +--- + +## The Database + +This code uses [SQLAlchemy](https://www.sqlalchemy.org/) to set up classes that have methods to talk to many [databases](https://docs.sqlalchemy.org/en/20/dialects/index.html). We use **SQLite for simplicity and easy local development**. + +--- + +### Local Development (SQLite) + +The database file is stored in `/instance/todo.db` + +Hopefully Visual Code has promoted you to install the recommended extensions including the SQLite extension. and so it should appear in the left hand side explorer view with a red icon. + +Have a look, can you see the tables and data? + +--- + +## What We're Building Next + +Next your going to add a **category system** to organize todos. Each todo must belong to one category (like "Urgent" or "Non-urgent"). Users will select a category from a dropdown menu when creating a new todo. Administrators can add, edit, or delete categories through the admin interface at `/admin/`. + +--- + +The system uses two database tables with a **one-to-many relationship**: one category can have many todos, but each todo belongs to exactly one category. + +```mermaid +erDiagram + Category ||--o{ Todo : "has many" + + Category { + int id PK + string name UK + } + + Todo { + int id PK + string task + string user_id + int category_id FK + boolean done + } +``` + +--- + +## Step 1: Update `todo.py` - Add the Category Model + +### 1.1: Add the Category class + +Find the line that says `db = SQLAlchemy(model_class=Base)`. + +**Just AFTER** that line, add this new class: + +```python +class Category(db.Model): + __tablename__ = "categories" + + id: Mapped[int] = mapped_column(primary_key=True, init=False) + name: Mapped[str] = mapped_column(db.String(50), nullable=False, unique=True) + + def __repr__(self): # When you try to print or put this object in a template represent it as it's name + return self.name + + +``` + +--- + +### 1.2: Update the Todo class + +Find the `Todo` class. It should look like this: + +Add a new line after `user_id` to add the category field. And add a new function / method which will make todo.category return the Category object that is linked by the category_id Foreign Key: + +```python +class Todo(db.Model): + __tablename__ = "todos" + + id: Mapped[int] = mapped_column(primary_key=True, init=False) + task: Mapped[str] = mapped_column(db.String(200), nullable=False) + user_id: Mapped[str] = mapped_column(db.String(100), nullable=False) + category_id: Mapped[int] = mapped_column(ForeignKey('categories.id'), nullable=False) + done: Mapped[bool] = mapped_column(db.Boolean, default=False) + + @property # todo.category is a property (member variable) of the todo object + def category(self): # return the category object linked to this Todo by category_id + return Category.query.get(self.category_id) +``` + + +--- + + +## Step 2: Update Routes in `todo.py` + +### 2.1: Update the home() function + +Find the `home()` function and change it to pass categories to the template: + +**New code:** + +```python +@todo_bp.route('/') +def home(): + user = get_current_user() + if not user: + return render_template('login.html') + session['user_id'] = user["id"] + todos = Todo.query.filter_by(user_id=session['user_id']).all() + categories = Category.query.all() + return render_template('index.html', todos=todos, categories=categories, user=user) +``` + +--- + +### 2.2: Update the add() function + +Find the `add()` function and change it to capture the category: + +**New code:** + +```python +@todo_bp.route('/add', methods=['POST']) +def add(): + if 'user_id' not in session: + return redirect('/') + task_text = request.form['task'] + category_id = request.form.get('category_id', type=int) + if not category_id: + return redirect('/') + new_task = Todo(task=task_text, category_id=category_id, user_id=session['user_id']) + db.session.add(new_task) + db.session.commit() + return redirect('/') +``` + +--- + +### 2.3: Update the init_app() function + +Find the `init_app()` function at the bottom of `todo.py`. Add code to seed the initial categories: + +**New code:** + +```python +def init_app(app): + db.init_app(app) + with app.app_context(): + db.create_all() + # Seed initial categories if they don't exist + if Category.query.count() == 0: + urgent = Category(name="Urgent") + non_urgent = Category(name="Non-urgent") + db.session.add(urgent) + db.session.add(non_urgent) + db.session.commit() + + if Todo.query.count() == 0: + mreggleton_check = Todo(task="Mr Eggleton checking your Todo App!", done=False, user_id="github|5987806", category_id=non_urgent.id) + db.session.add(mreggleton_check) + db.session.commit() +``` + +--- + +## Step 3: Update `templates/index.html` - Add Category Dropdown + +Find the form in `index.html`: + +**New code:** + +```html +
      + + + +
      +``` + +--- + +Find the task text being printed out and add the category next to it: + +**New code:** + +```html + {{ todo.task }} [{{ todo.category }}] +``` + +--- + +## Step 4: Update `app.py` - Import Category + +Find this line near the top of `app.py`: + +```python +from todo import todo_bp, init_app as init_todo +from todo import db, Todo +``` + +Change it to: + +```python +from todo import todo_bp, init_app as init_todo +from todo import db, Todo, Category +``` + +--- + +Then find this line near the bottom: + +```python +init_admin(app, db, Todo) +``` + +Change it to: + +```python +init_admin(app, db, Todo, Category) +``` + +--- + +## Step 5: Update `admin.py` - Add Category Admin View + +Find the `init_admin()` function in `admin.py`: + +**New code:** + +```python +def init_admin(app, db, todo_model, category_model): + """Attach Babel and register secured admin views for the given models.""" + Babel(app, locale_selector=lambda: 'en') + admin = Admin(app, name="Admin", template_mode="bootstrap4", + index_view=AuthenticatedAdminIndexView()) + admin.add_view(AuthenticatedModelView(todo_model, db.session, + endpoint="todo_admin", + name="Todos")) + admin.add_view(AuthenticatedModelView(category_model, db.session, + endpoint="category_admin", + name="Categories")) + return admin +``` + +--- + +## Step 6: Reset Your Database + +Because you've changed the database structure, you need to delete the old database: + +1. Stop your Flask app if it's running (press Ctrl+C in the terminal) +2. Delete the database file from the instance folder. + +Restart your Flask app: + +```bash +py -m flask run --host=localhost --port=5000 # it maybe python3 on your machine +``` + +The app will create a new database with the "Urgent" and "Non-urgent" categories automatically. + +--- + +## Testing Your Changes + +1. Go to the home page - you should see a dropdown to select a category when adding a task +2. Add a task with a category selected +3. Log in and go to [http://localhost:5000/admin/](http://localhost:5000/admin/) to see the Categories section where you can add, edit, or delete categories + +--- + +## Summary of Changes + +- **Created** a new `Category` model +- **Added** a foreign key relationship from `Todo` to `Category` +- **Updated** the form to include a category dropdown +- **Modified** the add route to capture the selected category +- **Added** automatic seeding of initial categories +- **Enabled** category management in the admin interface + +--- + +## Things we are ignoring + +- Persistent records in a database. The current database will be destroyed each time you push to render, ( You can modify the code once it's on Render to move to PostgreSQL ). +- Changing database structure SQLAlchemy Migrations. Currently we aren't handling changes to the database structure so you need to delete the local .db and start again (render wil do this anyway on a rebuild as mentioned above). They can be handled with Migrations +- Minimal Autorisation all Authenticated users can do everything on the site. + +--- +## Things we are ignoring 2 + +- Storing any user data in a database (other than an id from github or Auth0 ). To have users on this system to store any other PII refer to [https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy](https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy) and change the privacy statement. +- Testing. There are no tests in this code, although Flask, SQL Alchemy and the other libraries used are thoroughly tested and are checked for security issues. + +--- + +## Your Development + +Then what could you make with the same ideas but different entities (things)? + +Books and People could make a library etc .... diff --git a/README.md b/README.md index c9ecba8..65cbf09 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ A simple Python Todo Web App to do some improvements on and be a starting point - SQL Databases the modern way - Managed by [SQLAlchemy](https://www.sqlalchemy.org/) an ORM / [Object Relationship Mapper](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) which allows you to write classes that define the data and provides the storage & [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) for you. --- +--- ###  [Object Relationship Mapper](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) - ORMs build the database for you from your classes so you define what you want to store how it connects together and any extras calculations / functions you need . @@ -34,7 +34,7 @@ A simple Python Todo Web App to do some improvements on and be a starting point ### Authentication (GitHub + Auth0) -Authentication is the act of proving who you are, in this system we use external Authentication systems so we aren't storing usernames & passwords (reducing the DPA responsiblilties ) +Authentication is the act of proving who you are, in this system we use external authentication systems so we aren't storing usernames & passwords (reducing the DPA responsiblilties ). There are still some so we provide a privacy policy. - GitHub OAuth (Flask-Dance) for local Windows development - Auth0 OAuth for Codespaces and Render production @@ -45,7 +45,7 @@ Authentication is the act of proving who you are, in this system we use external - Ready for [Render](https://render.com/) deployment so you can publish and use the site online for free (there are some speed limitations) - GitHub Actions CI/CD to build the site when you commit a working version -- Can be upgraded to use a free PostgreSQL daatbase server (but there are some other ) +- Can be upgraded to use a free PostgreSQL database server (but there are some other steps) --- @@ -53,28 +53,28 @@ Authentication is the act of proving who you are, in this system we use external ### Start from the Template -1. Go to the github repository [https://github.com/UTCSheffield/python-flask-todo](https://github.com/UTCSheffield/python-flask-todo) -2. Click the green "Use this template" button at the top of the page -3. Select "Create a new repository" -4. Fill in your new repository details: +1. Login to [github.com](https://github.com/) +2. Go to the github repository [https://github.com/UTCSheffield/python-flask-todo](https://github.com/UTCSheffield/python-flask-todo) +3. Click the green "Use this template" button at the top of the page +4. Select "Create a new repository" +5. Fill in your new repository details: - Choose a repository name (e.g., `python-flask-todo`) - Add a description (optional) - Choose Public or Private visibility -5. Click "Create repository from template" -6. Your new repository will be created with all the template files -7. Now clone your new repository using one of the methods below +6. Click "Create repository from template" +7. Your new repository will be created with all the template files --- -### Clone the Repository +### Clone your Repository locally **Using GitHub Desktop:** -1. Open GitHub Desktop -2. Click `File` → `Clone repository` -3. Select the `URL` tab -4. Enter: `https://github.com/UTCSheffield/python-flask-todo.git` -5. Choose a local path and click `Clone` +1. On the GitHub page for your new repository +2. Click the green "Code" button +3. Click "Open with GitHub Desktop" +4. You may need to login to GitHub Desktop if you haven't already +5. You may be prompted to choose a local path to clone the repository to 6. Click 'Open in Visual Studio Code' to open the project in VS Code --- @@ -91,16 +91,16 @@ cd python-flask-todo ### Install Dependencies ```bash -py -m pip install -r requirements.txt # You'll need python3 ... in linux +python3 -m pip install -r requirements.txt ``` --- ### Environment Configuration (.env) -In VS Code open `.env.example` and save it as `.env` - -Edit the file to put the details you need in. But @ UTC Sheffield OLP, Mr Eggleton will give you a .env file that will work with github, and you don't need to do the "Authentication Setup" as you are using his and you can skip to ['Running the Application'](#running-the-application) +```bash +cp .env.example .env +``` --- @@ -144,11 +144,13 @@ For local Windows development with GitHub Desktop: Start the Flask development server: ```bash -py -m flask run --host=localhost --port=5000 # it maybe python3 on your machine +python3 -m flask run --host=localhost --port=5000 ``` The app will be available at [http://localhost:5000](http://localhost:5000) +Try it, login and create a few tasks! + --- ## The Database @@ -159,6 +161,10 @@ This code uses [SQLAlchemy](https://www.sqlalchemy.org/) to set up classes that The database file is stored in `/instance/todo.db` +Hopefully Visual Code has promoted you to install the recommended extensions including the SQLite extension. and so todo.db should appear in the left hand side explorer view with a red icon. + +Have a look, can you see the tables and data? + --- ## Things we are ignoring @@ -168,7 +174,7 @@ The database file is stored in `/instance/todo.db` - Minimal Autorisation all Authenticated users can do everything on the site. - Storing any user data in a database (other than an id from github or Auth0 ). To have users on this system to store any other PII refer to [https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy](https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy) and change the privacy statement. - Adding extra security [https://flask-security.readthedocs.io/en/stable/quickstart.html#basic-flask-sqlalchemy-application](https://flask-security.readthedocs.io/en/stable/quickstart.html#basic-flask-sqlalchemy-application) -- Testing. There are no tests in this code, although Flask, SQL Alchemy and the other libraries used are thouroughly tested and are checked for security issues. +- Testing. There are no tests in this code, although Flask, SQL Alchemy and the other libraries used are thoroughly tested and are checked for security issues. --- @@ -182,10 +188,12 @@ Books and People could make a library etc .... --- -## Codespaces Setup - -See [CODESPACES_SETUP.md](CODESPACES_SETUP.md) for complete GitHub Codespaces setup instructions. ## Deployment on Render See [RENDER_SETUP.md](RENDER_SETUP.md) for complete Render deployment instructions, including setup, configuration, environment variables, and continuous deployment. + + +## Codespaces Setup + +See [CODESPACES_SETUP.md](CODESPACES_SETUP.md) for complete GitHub Codespaces setup instructions. \ No newline at end of file diff --git a/SaveAs.png b/SaveAs.png new file mode 100644 index 0000000000000000000000000000000000000000..857fbdd1afb252fb6c3dfc1e60e62c0c3c630d78 GIT binary patch literal 2431 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 Gm-II@xPs&W literal 0 HcmV?d00001 From e8ca6d194743bc26d6f336418af72a333f7217f7 Mon Sep 17 00:00:00 2001 From: Mr Eggleton Date: Fri, 16 Jan 2026 15:22:12 +0000 Subject: [PATCH 25/25] Updated the LESSON --- LESSON.md | 35 ++++++++++++++++++++++------------- LESSON.pdf | Bin 0 -> 190889 bytes 2 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 LESSON.pdf diff --git a/LESSON.md b/LESSON.md index f7f2b61..5501d83 100644 --- a/LESSON.md +++ b/LESSON.md @@ -1,5 +1,5 @@ -# Python as Dynamic Webserver +# Python as Dynamic Web Server --- @@ -7,8 +7,22 @@ ```mermaid mindmap - Web Server - HTML #10003; + server)Web Server( + Program that responds to HTTP requests with HTML or Assets + Static Site + Hand Built #10003; + Coded one page at a time + Static Built #10003; + Build pages and layout into static pages + Dynamic + Build from templates and data on each request + Allows for the data to be changed + Authentication + Can be an API as well as HTML + SPA + Single Page Applications + Javascript heavy + Use APIs to get data Assets Images #10003; CSS #10003; @@ -17,12 +31,6 @@ mindmap Text Files #10003; API Database - Authentication - Types - Hand Built #10003; - Static Built #10003; - Dynamic - ``` --- @@ -59,7 +67,7 @@ A simple Python Todo Web App to do some improvements on and be a starting point --- -### SQLAlchemy Snippet +### SQLAlchemy Snippet ```python class Todo(db.Model): @@ -72,6 +80,7 @@ class Todo(db.Model): ``` --- + ### Flask Snippet ```python @@ -85,6 +94,7 @@ def home():     todos = Todo.query.filter_by(user_id=session['user_id']).all()     return render_template('index.html', todos=todos, user=user) ``` + #### CRUD Admin Snippet ```python @@ -196,7 +206,7 @@ Have a look, can you see the tables and data? --- -## What We're Building Next +## What We're Building Next Next your going to add a **category system** to organize todos. Each todo must belong to one category (like "Urgent" or "Non-urgent"). Users will select a category from a dropdown menu when creating a new todo. Administrators can add, edit, or delete categories through the admin interface at `/admin/`. @@ -268,10 +278,8 @@ class Todo(db.Model): return Category.query.get(self.category_id) ``` - --- - ## Step 2: Update Routes in `todo.py` ### 2.1: Update the home() function @@ -473,6 +481,7 @@ The app will create a new database with the "Urgent" and "Non-urgent" categories - Minimal Autorisation all Authenticated users can do everything on the site. --- + ## Things we are ignoring 2 - Storing any user data in a database (other than an id from github or Auth0 ). To have users on this system to store any other PII refer to [https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy](https://flask-dance.readthedocs.io/en/latest/storages.html#sqlalchemy) and change the privacy statement. diff --git a/LESSON.pdf b/LESSON.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b70ec8067000b5e0aca507a0a8108168b69e8f12 GIT binary patch literal 190889 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 literal 0 HcmV?d00001