├── .gitignore ├── .gitpod.dockerfile ├── .gitpod.yml ├── .vscode ├── font_fix.py ├── heroku_config.sh ├── init_tasks.sh ├── launch.json ├── settings.json ├── since_update.sh └── snippets.json ├── 01_putting_the_basics_into_place ├── env_sample.py ├── run.py └── taskmanager │ ├── __init__.py │ ├── routes.py │ └── templates │ └── base.html ├── 02_creating_the_database ├── env_sample.py ├── run.py └── taskmanager │ ├── __init__.py │ ├── models.py │ ├── routes.py │ └── templates │ └── base.html ├── 03_template_inheritance ├── env_sample.py ├── run.py └── taskmanager │ ├── __init__.py │ ├── models.py │ ├── routes.py │ ├── static │ ├── css │ │ └── style.css │ └── js │ │ └── script.js │ └── templates │ ├── base.html │ └── tasks.html ├── 04_adding_categories ├── env_sample.py ├── run.py └── taskmanager │ ├── __init__.py │ ├── models.py │ ├── routes.py │ ├── static │ ├── css │ │ └── style.css │ └── js │ │ └── script.js │ └── templates │ ├── add_category.html │ ├── base.html │ ├── categories.html │ └── tasks.html ├── 05_viewing_categories ├── env_sample.py ├── run.py └── taskmanager │ ├── __init__.py │ ├── models.py │ ├── routes.py │ ├── static │ ├── css │ │ └── style.css │ └── js │ │ └── script.js │ └── templates │ ├── add_category.html │ ├── base.html │ ├── categories.html │ └── tasks.html ├── 06_updating_categories ├── env_sample.py ├── run.py └── taskmanager │ ├── __init__.py │ ├── models.py │ ├── routes.py │ ├── static │ ├── css │ │ └── style.css │ └── js │ │ └── script.js │ └── templates │ ├── add_category.html │ ├── base.html │ ├── categories.html │ ├── edit_category.html │ └── tasks.html ├── 07_deleting_categories ├── env_sample.py ├── run.py └── taskmanager │ ├── __init__.py │ ├── models.py │ ├── routes.py │ ├── static │ ├── css │ │ └── style.css │ └── js │ │ └── script.js │ └── templates │ ├── add_category.html │ ├── base.html │ ├── categories.html │ ├── edit_category.html │ └── tasks.html ├── 08_adding_tasks ├── env_sample.py ├── run.py └── taskmanager │ ├── __init__.py │ ├── models.py │ ├── routes.py │ ├── static │ ├── css │ │ └── style.css │ └── js │ │ └── script.js │ └── templates │ ├── add_category.html │ ├── add_task.html │ ├── base.html │ ├── categories.html │ ├── edit_category.html │ └── tasks.html ├── 09_viewing_tasks ├── env_sample.py ├── run.py └── taskmanager │ ├── __init__.py │ ├── models.py │ ├── routes.py │ ├── static │ ├── css │ │ └── style.css │ └── js │ │ └── script.js │ └── templates │ ├── add_category.html │ ├── add_task.html │ ├── base.html │ ├── categories.html │ ├── edit_category.html │ └── tasks.html ├── 10_updating_tasks ├── env_sample.py ├── run.py └── taskmanager │ ├── __init__.py │ ├── models.py │ ├── routes.py │ ├── static │ ├── css │ │ └── style.css │ └── js │ │ └── script.js │ └── templates │ ├── add_category.html │ ├── add_task.html │ ├── base.html │ ├── categories.html │ ├── edit_category.html │ ├── edit_task.html │ └── tasks.html ├── 11_deleting_tasks ├── env_sample.py ├── run.py └── taskmanager │ ├── __init__.py │ ├── models.py │ ├── routes.py │ ├── static │ ├── css │ │ └── style.css │ └── js │ │ └── script.js │ └── templates │ ├── add_category.html │ ├── add_task.html │ ├── base.html │ ├── categories.html │ ├── edit_category.html │ ├── edit_task.html │ └── tasks.html ├── 12_deploying_our_project_to_heroku ├── COMMANDS.md ├── Procfile ├── env_sample.py ├── requirements.txt ├── run.py └── taskmanager │ ├── __init__.py │ ├── models.py │ ├── routes.py │ ├── static │ ├── css │ │ └── style.css │ └── js │ │ └── script.js │ └── templates │ ├── add_category.html │ ├── add_task.html │ ├── base.html │ ├── categories.html │ ├── edit_category.html │ ├── edit_task.html │ └── tasks.html └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | core.Microsoft* 2 | core.mongo* 3 | core.python* 4 | env.py 5 | __pycache__/ 6 | *.py[cod] 7 | node_modules/ 8 | -------------------------------------------------------------------------------- /.gitpod.dockerfile: -------------------------------------------------------------------------------- 1 | FROM gitpod/workspace-postgres 2 | 3 | USER root 4 | # Setup Heroku CLI 5 | RUN curl https://cli-assets.heroku.com/install.sh | sh 6 | 7 | # Setup Python linters 8 | RUN pip3 install flake8 flake8-flask flake8-django 9 | 10 | USER gitpod 11 | 12 | # Upgrade Node 13 | 14 | ENV NODE_VERSION=14.15.4 15 | RUN bash -c ". .nvm/nvm.sh && \ 16 | nvm install ${NODE_VERSION} && \ 17 | nvm alias default ${NODE_VERSION} && \ 18 | npm install -g yarn" 19 | 20 | RUN echo 'alias heroku_config=". $GITPOD_REPO_ROOT/.vscode/heroku_config.sh"' >> ~/.bashrc 21 | RUN echo 'alias run="python3 $GITPOD_REPO_ROOT/manage.py runserver 0.0.0.0:8000"' >> ~/.bashrc 22 | RUN echo 'alias python=python3' >> ~/.bashrc 23 | RUN echo 'alias pip=pip3' >> ~/.bashrc 24 | RUN echo 'alias font_fix="python3 $GITPOD_REPO_ROOT/.vscode/font_fix.py"' >> ~/.bashrc 25 | ENV PATH=/home/gitpod/.nvm/versions/node/v${NODE_VERSION}/bin:$PATH 26 | 27 | # Local environment variables 28 | 29 | ENV PORT="8080" 30 | ENV IP="0.0.0.0" 31 | 32 | USER root 33 | # Switch back to root to allow IDE to load 34 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: 2 | file: .gitpod.dockerfile 3 | tasks: 4 | - init: . ${GITPOD_REPO_ROOT}/.vscode/init_tasks.sh 5 | vscode: 6 | extensions: 7 | - ms-python.python 8 | - formulahendry.auto-close-tag 9 | - mkaufman.HTMLHint 10 | - eventyret.bootstrap-4-cdn-snippet 11 | - kevinglasson.cornflakes-linter 12 | - hookyqr.beautify 13 | -------------------------------------------------------------------------------- /.vscode/font_fix.py: -------------------------------------------------------------------------------- 1 | # Fixes the font issue on Brave browser 2 | # Matt Rudge 3 | # June 2021 4 | 5 | import json 6 | import os 7 | 8 | BASE_PATH = os.environ.get("GITPOD_REPO_ROOT") 9 | 10 | with open(f"{BASE_PATH}/.vscode/settings.json", "r+") as f: 11 | content = json.loads(f.read()) 12 | 13 | if "terminal.integrated.fontFamily" not in content: 14 | print("Terminal Font Fix: adding Menlo font") 15 | content["terminal.integrated.fontFamily"] = "Menlo" 16 | else: 17 | print("Terminal Font Fix: removing Menlo font") 18 | content.pop("terminal.integrated.fontFamily") 19 | 20 | f.seek(0, os.SEEK_SET) 21 | f.write(json.dumps(content)) 22 | f.truncate() 23 | -------------------------------------------------------------------------------- /.vscode/heroku_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script to allow Heroku API key to be pasted 3 | # exported as an environment variable 4 | # 5 | # Matt Rudge, May 2021 6 | 7 | echo Heroku authentication configuration script 8 | echo Code Institute, 2021 9 | echo 10 | echo Get your Heroku API key by going to https://dashboard.heroku.com 11 | echo Go to Account Settings and click on Reveal to view your Heroku API key 12 | echo 13 | 14 | if [[ -z "${HEROKU_API_KEY}" ]]; then 15 | echo Paste your Heroku API key here or press Enter to quit: 16 | read apikey 17 | if [[ -z "${apikey}" ]]; then 18 | return 0 19 | fi 20 | echo export HEROKU_API_KEY=${apikey} >> ~/.bashrc 21 | echo Added the export. Refreshing the terminal. 22 | . ~/.bashrc > /dev/null 23 | echo Done! 24 | else 25 | echo API key is already set. Exiting 26 | fi 27 | -------------------------------------------------------------------------------- /.vscode/init_tasks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Gives a personalised greeting 4 | # Adds configuration options for SQLite 5 | # Creates run aliases 6 | # Author: Matt Rudge 7 | 8 | clear 9 | echo "Setting the greeting" 10 | sed -i "s/USER_NAME/$GITPOD_GIT_USER_NAME/g" ${GITPOD_REPO_ROOT}/README.md 11 | echo "Creating .sqliterc file" 12 | echo ".headers on" > ~/.sqliterc 13 | echo ".mode column" >> ~/.sqliterc 14 | echo "Your workspace is ready to use. Happy coding!" 15 | source ~/.bashrc 16 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | "version": "0.2.0", 5 | "configurations": [ 6 | { 7 | "name": "Python: Current File (Integrated Terminal)", 8 | "type": "python", 9 | "request": "launch", 10 | "program": "${file}", 11 | "console": "internalConsole" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.linting.pylintEnabled": true, 3 | "python.linting.enabled": true, 4 | "python.linting.pycodestyleEnabled": false, 5 | "python.linting.flake8Enabled": true, 6 | "python.terminal.activateEnvironment": false, 7 | "python.formatting.autopep8Path": "/home/gitpod/.pyenv/shims/autopep8", 8 | "python.linting.flake8Path": "/home/gitpod/.pyenv/shims/flake8", 9 | "cornflakes.linter.executablePath": "/home/gitpod/.pyenv/shims/flake8", 10 | "files.exclude": { 11 | "**/.DS_Store": true, 12 | "**/.git": true, 13 | "**/.github": true, 14 | "**/.gitp*": true, 15 | "**/.hg": true, 16 | "**/.svn": true, 17 | "**/.vscode": true, 18 | "**/core.Microsoft*": true, 19 | "**/core.python*": true, 20 | "**/CVS": true 21 | }, 22 | "files.autoSave": "off", 23 | "workbench.colorTheme": "Visual Studio Dark", 24 | "editor.defaultFormatter": "HookyQR.beautify" 25 | } 26 | -------------------------------------------------------------------------------- /.vscode/since_update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Post update script, add in changes to init_tasks.sh 3 | # that won't take effect in an upgraded workspace 4 | 5 | echo 'alias heroku_config=". $GITPOD_REPO_ROOT/.vscode/heroku_config.sh"' >> ~/.bashrc 6 | 7 | echo Post-upgrade changes applied 8 | -------------------------------------------------------------------------------- /.vscode/snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "html": { 3 | "snippets": { 4 | "form": "form>input>input:submit[value=\"Submit\"]" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /01_putting_the_basics_into_place/env_sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ.setdefault("IP", "0.0.0.0") 4 | os.environ.setdefault("PORT", "5000") 5 | os.environ.setdefault("SECRET_KEY", "any_secret_key") 6 | os.environ.setdefault("DEBUG", "True") 7 | os.environ.setdefault("DEVELOPMENT", "True") 8 | os.environ.setdefault("DB_URL", "postgresql://neondb_owner:password@hostlink.eu-central-1.aws.neon.tech/database_name") 9 | -------------------------------------------------------------------------------- /01_putting_the_basics_into_place/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from taskmanager import app 3 | 4 | 5 | if __name__ == "__main__": 6 | app.run( 7 | host=os.environ.get("IP"), 8 | port=int(os.environ.get("PORT")), 9 | debug=os.environ.get("DEBUG") 10 | ) 11 | -------------------------------------------------------------------------------- /01_putting_the_basics_into_place/taskmanager/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from flask_sqlalchemy import SQLAlchemy 4 | if os.path.exists("env.py"): 5 | import env # noqa 6 | 7 | 8 | app = Flask(__name__) 9 | app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") 10 | app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URL") 11 | 12 | db = SQLAlchemy(app) 13 | 14 | from taskmanager import routes # noqa 15 | -------------------------------------------------------------------------------- /01_putting_the_basics_into_place/taskmanager/routes.py: -------------------------------------------------------------------------------- 1 | from flask import render_template 2 | from taskmanager import app, db 3 | 4 | 5 | @app.route("/") 6 | def home(): 7 | return render_template("base.html") 8 | -------------------------------------------------------------------------------- /01_putting_the_basics_into_place/taskmanager/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Task Manager 8 | 9 | 10 | 11 | Hello World! 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /02_creating_the_database/env_sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ.setdefault("IP", "0.0.0.0") 4 | os.environ.setdefault("PORT", "5000") 5 | os.environ.setdefault("SECRET_KEY", "any_secret_key") 6 | os.environ.setdefault("DEBUG", "True") 7 | os.environ.setdefault("DEVELOPMENT", "True") 8 | os.environ.setdefault("DB_URL", "postgresql://neondb_owner:password@hostlink.eu-central-1.aws.neon.tech/database_name") 9 | -------------------------------------------------------------------------------- /02_creating_the_database/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from taskmanager import app 3 | 4 | 5 | if __name__ == "__main__": 6 | app.run( 7 | host=os.environ.get("IP"), 8 | port=int(os.environ.get("PORT")), 9 | debug=os.environ.get("DEBUG") 10 | ) 11 | -------------------------------------------------------------------------------- /02_creating_the_database/taskmanager/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from flask_sqlalchemy import SQLAlchemy 4 | if os.path.exists("env.py"): 5 | import env # noqa 6 | 7 | 8 | app = Flask(__name__) 9 | app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") 10 | app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URL") 11 | 12 | db = SQLAlchemy(app) 13 | 14 | from taskmanager import routes # noqa 15 | -------------------------------------------------------------------------------- /02_creating_the_database/taskmanager/models.py: -------------------------------------------------------------------------------- 1 | from taskmanager import db 2 | 3 | 4 | class Category(db.Model): 5 | # schema for the Category model 6 | id = db.Column(db.Integer, primary_key=True) 7 | category_name = db.Column(db.String(25), unique=True, nullable=False) 8 | tasks = db.relationship("Task", backref="category", cascade="all, delete", lazy=True) 9 | 10 | def __repr__(self): 11 | # __repr__ to represent itself in the form of a string 12 | return self.category_name 13 | 14 | 15 | class Task(db.Model): 16 | # schema for the Task model 17 | id = db.Column(db.Integer, primary_key=True) 18 | task_name = db.Column(db.String(50), unique=True, nullable=False) 19 | task_description = db.Column(db.Text, nullable=False) 20 | is_urgent = db.Column(db.Boolean, default=False, nullable=False) 21 | due_date = db.Column(db.Date, nullable=False) 22 | category_id = db.Column(db.Integer, db.ForeignKey("category.id", ondelete="CASCADE"), nullable=False) 23 | 24 | def __repr__(self): 25 | # __repr__ to represent itself in the form of a string 26 | return "#{0} - Task: {1} | Urgent: {2}".format( 27 | self.id, self.task_name, self.is_urgent 28 | ) 29 | -------------------------------------------------------------------------------- /02_creating_the_database/taskmanager/routes.py: -------------------------------------------------------------------------------- 1 | from flask import render_template 2 | from taskmanager import app, db 3 | from taskmanager.models import Category, Task 4 | 5 | 6 | @app.route("/") 7 | def home(): 8 | return render_template("base.html") 9 | -------------------------------------------------------------------------------- /02_creating_the_database/taskmanager/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Task Manager 8 | 9 | 10 | 11 | Hello World! 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /03_template_inheritance/env_sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ.setdefault("IP", "0.0.0.0") 4 | os.environ.setdefault("PORT", "5000") 5 | os.environ.setdefault("SECRET_KEY", "any_secret_key") 6 | os.environ.setdefault("DEBUG", "True") 7 | os.environ.setdefault("DEVELOPMENT", "True") 8 | os.environ.setdefault("DB_URL", "postgresql://neondb_owner:password@hostlink.eu-central-1.aws.neon.tech/database_name") 9 | -------------------------------------------------------------------------------- /03_template_inheritance/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from taskmanager import app 3 | 4 | 5 | if __name__ == "__main__": 6 | app.run( 7 | host=os.environ.get("IP"), 8 | port=int(os.environ.get("PORT")), 9 | debug=os.environ.get("DEBUG") 10 | ) 11 | -------------------------------------------------------------------------------- /03_template_inheritance/taskmanager/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from flask_sqlalchemy import SQLAlchemy 4 | if os.path.exists("env.py"): 5 | import env # noqa 6 | 7 | 8 | app = Flask(__name__) 9 | app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") 10 | app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URL") 11 | 12 | db = SQLAlchemy(app) 13 | 14 | from taskmanager import routes # noqa 15 | -------------------------------------------------------------------------------- /03_template_inheritance/taskmanager/models.py: -------------------------------------------------------------------------------- 1 | from taskmanager import db 2 | 3 | 4 | class Category(db.Model): 5 | # schema for the Category model 6 | id = db.Column(db.Integer, primary_key=True) 7 | category_name = db.Column(db.String(25), unique=True, nullable=False) 8 | tasks = db.relationship("Task", backref="category", cascade="all, delete", lazy=True) 9 | 10 | def __repr__(self): 11 | # __repr__ to represent itself in the form of a string 12 | return self.category_name 13 | 14 | 15 | class Task(db.Model): 16 | # schema for the Task model 17 | id = db.Column(db.Integer, primary_key=True) 18 | task_name = db.Column(db.String(50), unique=True, nullable=False) 19 | task_description = db.Column(db.Text, nullable=False) 20 | is_urgent = db.Column(db.Boolean, default=False, nullable=False) 21 | due_date = db.Column(db.Date, nullable=False) 22 | category_id = db.Column(db.Integer, db.ForeignKey("category.id", ondelete="CASCADE"), nullable=False) 23 | 24 | def __repr__(self): 25 | # __repr__ to represent itself in the form of a string 26 | return "#{0} - Task: {1} | Urgent: {2}".format( 27 | self.id, self.task_name, self.is_urgent 28 | ) 29 | -------------------------------------------------------------------------------- /03_template_inheritance/taskmanager/routes.py: -------------------------------------------------------------------------------- 1 | from flask import render_template 2 | from taskmanager import app, db 3 | from taskmanager.models import Category, Task 4 | 5 | 6 | @app.route("/") 7 | def home(): 8 | return render_template("tasks.html") 9 | -------------------------------------------------------------------------------- /03_template_inheritance/taskmanager/static/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | min-height: 100vh; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1 0 auto; 9 | } 10 | -------------------------------------------------------------------------------- /03_template_inheritance/taskmanager/static/js/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function() { 2 | // sidenav initialization 3 | let sidenav = document.querySelectorAll(".sidenav"); 4 | M.Sidenav.init(sidenav); 5 | }); 6 | -------------------------------------------------------------------------------- /03_template_inheritance/taskmanager/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 13 | 14 | Task Manager 15 | 16 | 17 | 18 | 19 |
20 | 21 | 32 | 33 | 34 | 39 |
40 | 41 |
42 | {% block content %} 43 | {% endblock %} 44 |
45 | 46 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /03_template_inheritance/taskmanager/templates/tasks.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Tasks

5 | 6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /04_adding_categories/env_sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ.setdefault("IP", "0.0.0.0") 4 | os.environ.setdefault("PORT", "5000") 5 | os.environ.setdefault("SECRET_KEY", "any_secret_key") 6 | os.environ.setdefault("DEBUG", "True") 7 | os.environ.setdefault("DEVELOPMENT", "True") 8 | os.environ.setdefault("DB_URL", "postgresql://neondb_owner:password@hostlink.eu-central-1.aws.neon.tech/database_name") 9 | -------------------------------------------------------------------------------- /04_adding_categories/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from taskmanager import app 3 | 4 | 5 | if __name__ == "__main__": 6 | app.run( 7 | host=os.environ.get("IP"), 8 | port=int(os.environ.get("PORT")), 9 | debug=os.environ.get("DEBUG") 10 | ) 11 | -------------------------------------------------------------------------------- /04_adding_categories/taskmanager/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from flask_sqlalchemy import SQLAlchemy 4 | if os.path.exists("env.py"): 5 | import env # noqa 6 | 7 | 8 | app = Flask(__name__) 9 | app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") 10 | app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URL") 11 | 12 | db = SQLAlchemy(app) 13 | 14 | from taskmanager import routes # noqa 15 | -------------------------------------------------------------------------------- /04_adding_categories/taskmanager/models.py: -------------------------------------------------------------------------------- 1 | from taskmanager import db 2 | 3 | 4 | class Category(db.Model): 5 | # schema for the Category model 6 | id = db.Column(db.Integer, primary_key=True) 7 | category_name = db.Column(db.String(25), unique=True, nullable=False) 8 | tasks = db.relationship("Task", backref="category", cascade="all, delete", lazy=True) 9 | 10 | def __repr__(self): 11 | # __repr__ to represent itself in the form of a string 12 | return self.category_name 13 | 14 | 15 | class Task(db.Model): 16 | # schema for the Task model 17 | id = db.Column(db.Integer, primary_key=True) 18 | task_name = db.Column(db.String(50), unique=True, nullable=False) 19 | task_description = db.Column(db.Text, nullable=False) 20 | is_urgent = db.Column(db.Boolean, default=False, nullable=False) 21 | due_date = db.Column(db.Date, nullable=False) 22 | category_id = db.Column(db.Integer, db.ForeignKey("category.id", ondelete="CASCADE"), nullable=False) 23 | 24 | def __repr__(self): 25 | # __repr__ to represent itself in the form of a string 26 | return "#{0} - Task: {1} | Urgent: {2}".format( 27 | self.id, self.task_name, self.is_urgent 28 | ) 29 | -------------------------------------------------------------------------------- /04_adding_categories/taskmanager/routes.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, request, redirect, url_for 2 | from taskmanager import app, db 3 | from taskmanager.models import Category, Task 4 | 5 | 6 | @app.route("/") 7 | def home(): 8 | return render_template("tasks.html") 9 | 10 | 11 | @app.route("/categories") 12 | def categories(): 13 | return render_template("categories.html") 14 | 15 | 16 | @app.route("/add_category", methods=["GET", "POST"]) 17 | def add_category(): 18 | if request.method == "POST": 19 | category = Category(category_name=request.form.get("category_name")) 20 | db.session.add(category) 21 | db.session.commit() 22 | return redirect(url_for("categories")) 23 | return render_template("add_category.html") 24 | -------------------------------------------------------------------------------- /04_adding_categories/taskmanager/static/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | min-height: 100vh; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1 0 auto; 9 | } 10 | -------------------------------------------------------------------------------- /04_adding_categories/taskmanager/static/js/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function() { 2 | // sidenav initialization 3 | let sidenav = document.querySelectorAll(".sidenav"); 4 | M.Sidenav.init(sidenav); 5 | }); 6 | -------------------------------------------------------------------------------- /04_adding_categories/taskmanager/templates/add_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /04_adding_categories/taskmanager/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 13 | 14 | Task Manager 15 | 16 | 17 | 18 | 19 |
20 | 21 | 32 | 33 | 34 | 39 |
40 | 41 |
42 | {% block content %} 43 | {% endblock %} 44 |
45 | 46 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /04_adding_categories/taskmanager/templates/categories.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Categories

5 | 6 |
7 |
8 | 9 | Add Category 10 | 11 |
12 |
13 | 14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /04_adding_categories/taskmanager/templates/tasks.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Tasks

5 | 6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /05_viewing_categories/env_sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ.setdefault("IP", "0.0.0.0") 4 | os.environ.setdefault("PORT", "5000") 5 | os.environ.setdefault("SECRET_KEY", "any_secret_key") 6 | os.environ.setdefault("DEBUG", "True") 7 | os.environ.setdefault("DEVELOPMENT", "True") 8 | os.environ.setdefault("DB_URL", "postgresql://neondb_owner:password@hostlink.eu-central-1.aws.neon.tech/database_name") 9 | -------------------------------------------------------------------------------- /05_viewing_categories/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from taskmanager import app 3 | 4 | 5 | if __name__ == "__main__": 6 | app.run( 7 | host=os.environ.get("IP"), 8 | port=int(os.environ.get("PORT")), 9 | debug=os.environ.get("DEBUG") 10 | ) 11 | -------------------------------------------------------------------------------- /05_viewing_categories/taskmanager/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from flask_sqlalchemy import SQLAlchemy 4 | if os.path.exists("env.py"): 5 | import env # noqa 6 | 7 | 8 | app = Flask(__name__) 9 | app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") 10 | app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URL") 11 | 12 | db = SQLAlchemy(app) 13 | 14 | from taskmanager import routes # noqa 15 | -------------------------------------------------------------------------------- /05_viewing_categories/taskmanager/models.py: -------------------------------------------------------------------------------- 1 | from taskmanager import db 2 | 3 | 4 | class Category(db.Model): 5 | # schema for the Category model 6 | id = db.Column(db.Integer, primary_key=True) 7 | category_name = db.Column(db.String(25), unique=True, nullable=False) 8 | tasks = db.relationship("Task", backref="category", cascade="all, delete", lazy=True) 9 | 10 | def __repr__(self): 11 | # __repr__ to represent itself in the form of a string 12 | return self.category_name 13 | 14 | 15 | class Task(db.Model): 16 | # schema for the Task model 17 | id = db.Column(db.Integer, primary_key=True) 18 | task_name = db.Column(db.String(50), unique=True, nullable=False) 19 | task_description = db.Column(db.Text, nullable=False) 20 | is_urgent = db.Column(db.Boolean, default=False, nullable=False) 21 | due_date = db.Column(db.Date, nullable=False) 22 | category_id = db.Column(db.Integer, db.ForeignKey("category.id", ondelete="CASCADE"), nullable=False) 23 | 24 | def __repr__(self): 25 | # __repr__ to represent itself in the form of a string 26 | return "#{0} - Task: {1} | Urgent: {2}".format( 27 | self.id, self.task_name, self.is_urgent 28 | ) 29 | -------------------------------------------------------------------------------- /05_viewing_categories/taskmanager/routes.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, request, redirect, url_for 2 | from taskmanager import app, db 3 | from taskmanager.models import Category, Task 4 | 5 | 6 | @app.route("/") 7 | def home(): 8 | return render_template("tasks.html") 9 | 10 | 11 | @app.route("/categories") 12 | def categories(): 13 | categories = list(Category.query.order_by(Category.category_name).all()) 14 | return render_template("categories.html", categories=categories) 15 | 16 | 17 | @app.route("/add_category", methods=["GET", "POST"]) 18 | def add_category(): 19 | if request.method == "POST": 20 | category = Category(category_name=request.form.get("category_name")) 21 | db.session.add(category) 22 | db.session.commit() 23 | return redirect(url_for("categories")) 24 | return render_template("add_category.html") 25 | -------------------------------------------------------------------------------- /05_viewing_categories/taskmanager/static/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | min-height: 100vh; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1 0 auto; 9 | } 10 | -------------------------------------------------------------------------------- /05_viewing_categories/taskmanager/static/js/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function() { 2 | // sidenav initialization 3 | let sidenav = document.querySelectorAll(".sidenav"); 4 | M.Sidenav.init(sidenav); 5 | }); 6 | -------------------------------------------------------------------------------- /05_viewing_categories/taskmanager/templates/add_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /05_viewing_categories/taskmanager/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 13 | 14 | Task Manager 15 | 16 | 17 | 18 | 19 |
20 | 21 | 32 | 33 | 34 | 39 |
40 | 41 |
42 | {% block content %} 43 | {% endblock %} 44 |
45 | 46 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /05_viewing_categories/taskmanager/templates/categories.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Categories

5 | 6 |
7 |
8 | 9 | Add Category 10 | 11 |
12 |
13 | 14 |
15 | {% for category in categories %} 16 |
17 |
18 |
19 | {{ category.category_name }} 20 |
21 |
22 | Edit 23 | Delete 24 |
25 |
26 |
27 | {% endfor %} 28 |
29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /05_viewing_categories/taskmanager/templates/tasks.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Tasks

5 | 6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /06_updating_categories/env_sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ.setdefault("IP", "0.0.0.0") 4 | os.environ.setdefault("PORT", "5000") 5 | os.environ.setdefault("SECRET_KEY", "any_secret_key") 6 | os.environ.setdefault("DEBUG", "True") 7 | os.environ.setdefault("DEVELOPMENT", "True") 8 | os.environ.setdefault("DB_URL", "postgresql://neondb_owner:password@hostlink.eu-central-1.aws.neon.tech/database_name") 9 | -------------------------------------------------------------------------------- /06_updating_categories/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from taskmanager import app 3 | 4 | 5 | if __name__ == "__main__": 6 | app.run( 7 | host=os.environ.get("IP"), 8 | port=int(os.environ.get("PORT")), 9 | debug=os.environ.get("DEBUG") 10 | ) 11 | -------------------------------------------------------------------------------- /06_updating_categories/taskmanager/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from flask_sqlalchemy import SQLAlchemy 4 | if os.path.exists("env.py"): 5 | import env # noqa 6 | 7 | 8 | app = Flask(__name__) 9 | app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") 10 | app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URL") 11 | 12 | db = SQLAlchemy(app) 13 | 14 | from taskmanager import routes # noqa 15 | -------------------------------------------------------------------------------- /06_updating_categories/taskmanager/models.py: -------------------------------------------------------------------------------- 1 | from taskmanager import db 2 | 3 | 4 | class Category(db.Model): 5 | # schema for the Category model 6 | id = db.Column(db.Integer, primary_key=True) 7 | category_name = db.Column(db.String(25), unique=True, nullable=False) 8 | tasks = db.relationship("Task", backref="category", cascade="all, delete", lazy=True) 9 | 10 | def __repr__(self): 11 | # __repr__ to represent itself in the form of a string 12 | return self.category_name 13 | 14 | 15 | class Task(db.Model): 16 | # schema for the Task model 17 | id = db.Column(db.Integer, primary_key=True) 18 | task_name = db.Column(db.String(50), unique=True, nullable=False) 19 | task_description = db.Column(db.Text, nullable=False) 20 | is_urgent = db.Column(db.Boolean, default=False, nullable=False) 21 | due_date = db.Column(db.Date, nullable=False) 22 | category_id = db.Column(db.Integer, db.ForeignKey("category.id", ondelete="CASCADE"), nullable=False) 23 | 24 | def __repr__(self): 25 | # __repr__ to represent itself in the form of a string 26 | return "#{0} - Task: {1} | Urgent: {2}".format( 27 | self.id, self.task_name, self.is_urgent 28 | ) 29 | -------------------------------------------------------------------------------- /06_updating_categories/taskmanager/routes.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, request, redirect, url_for 2 | from taskmanager import app, db 3 | from taskmanager.models import Category, Task 4 | 5 | 6 | @app.route("/") 7 | def home(): 8 | return render_template("tasks.html") 9 | 10 | 11 | @app.route("/categories") 12 | def categories(): 13 | categories = list(Category.query.order_by(Category.category_name).all()) 14 | return render_template("categories.html", categories=categories) 15 | 16 | 17 | @app.route("/add_category", methods=["GET", "POST"]) 18 | def add_category(): 19 | if request.method == "POST": 20 | category = Category(category_name=request.form.get("category_name")) 21 | db.session.add(category) 22 | db.session.commit() 23 | return redirect(url_for("categories")) 24 | return render_template("add_category.html") 25 | 26 | 27 | @app.route("/edit_category/", methods=["GET", "POST"]) 28 | def edit_category(category_id): 29 | category = Category.query.get_or_404(category_id) 30 | if request.method == "POST": 31 | category.category_name = request.form.get("category_name") 32 | db.session.commit() 33 | return redirect(url_for("categories")) 34 | return render_template("edit_category.html", category=category) 35 | -------------------------------------------------------------------------------- /06_updating_categories/taskmanager/static/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | min-height: 100vh; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1 0 auto; 9 | } 10 | -------------------------------------------------------------------------------- /06_updating_categories/taskmanager/static/js/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function() { 2 | // sidenav initialization 3 | let sidenav = document.querySelectorAll(".sidenav"); 4 | M.Sidenav.init(sidenav); 5 | }); 6 | -------------------------------------------------------------------------------- /06_updating_categories/taskmanager/templates/add_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /06_updating_categories/taskmanager/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 13 | 14 | Task Manager 15 | 16 | 17 | 18 | 19 |
20 | 21 | 32 | 33 | 34 | 39 |
40 | 41 |
42 | {% block content %} 43 | {% endblock %} 44 |
45 | 46 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /06_updating_categories/taskmanager/templates/categories.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Categories

5 | 6 |
7 | 12 |
13 | 14 |
15 | {% for category in categories %} 16 |
17 |
18 |
19 | {{ category.category_name }} 20 |
21 |
22 | Edit 23 | Delete 24 |
25 |
26 |
27 | {% endfor %} 28 |
29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /06_updating_categories/taskmanager/templates/edit_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Edit Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /06_updating_categories/taskmanager/templates/tasks.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Tasks

5 | 6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /07_deleting_categories/env_sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ.setdefault("IP", "0.0.0.0") 4 | os.environ.setdefault("PORT", "5000") 5 | os.environ.setdefault("SECRET_KEY", "any_secret_key") 6 | os.environ.setdefault("DEBUG", "True") 7 | os.environ.setdefault("DEVELOPMENT", "True") 8 | os.environ.setdefault("DB_URL", "postgresql://neondb_owner:password@hostlink.eu-central-1.aws.neon.tech/database_name") 9 | -------------------------------------------------------------------------------- /07_deleting_categories/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from taskmanager import app 3 | 4 | 5 | if __name__ == "__main__": 6 | app.run( 7 | host=os.environ.get("IP"), 8 | port=int(os.environ.get("PORT")), 9 | debug=os.environ.get("DEBUG") 10 | ) 11 | -------------------------------------------------------------------------------- /07_deleting_categories/taskmanager/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from flask_sqlalchemy import SQLAlchemy 4 | if os.path.exists("env.py"): 5 | import env # noqa 6 | 7 | 8 | app = Flask(__name__) 9 | app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") 10 | app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URL") 11 | 12 | db = SQLAlchemy(app) 13 | 14 | from taskmanager import routes # noqa 15 | -------------------------------------------------------------------------------- /07_deleting_categories/taskmanager/models.py: -------------------------------------------------------------------------------- 1 | from taskmanager import db 2 | 3 | 4 | class Category(db.Model): 5 | # schema for the Category model 6 | id = db.Column(db.Integer, primary_key=True) 7 | category_name = db.Column(db.String(25), unique=True, nullable=False) 8 | tasks = db.relationship("Task", backref="category", cascade="all, delete", lazy=True) 9 | 10 | def __repr__(self): 11 | # __repr__ to represent itself in the form of a string 12 | return self.category_name 13 | 14 | 15 | class Task(db.Model): 16 | # schema for the Task model 17 | id = db.Column(db.Integer, primary_key=True) 18 | task_name = db.Column(db.String(50), unique=True, nullable=False) 19 | task_description = db.Column(db.Text, nullable=False) 20 | is_urgent = db.Column(db.Boolean, default=False, nullable=False) 21 | due_date = db.Column(db.Date, nullable=False) 22 | category_id = db.Column(db.Integer, db.ForeignKey("category.id", ondelete="CASCADE"), nullable=False) 23 | 24 | def __repr__(self): 25 | # __repr__ to represent itself in the form of a string 26 | return "#{0} - Task: {1} | Urgent: {2}".format( 27 | self.id, self.task_name, self.is_urgent 28 | ) 29 | -------------------------------------------------------------------------------- /07_deleting_categories/taskmanager/routes.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, request, redirect, url_for 2 | from taskmanager import app, db 3 | from taskmanager.models import Category, Task 4 | 5 | 6 | @app.route("/") 7 | def home(): 8 | return render_template("tasks.html") 9 | 10 | 11 | @app.route("/categories") 12 | def categories(): 13 | categories = list(Category.query.order_by(Category.category_name).all()) 14 | return render_template("categories.html", categories=categories) 15 | 16 | 17 | @app.route("/add_category", methods=["GET", "POST"]) 18 | def add_category(): 19 | if request.method == "POST": 20 | category = Category(category_name=request.form.get("category_name")) 21 | db.session.add(category) 22 | db.session.commit() 23 | return redirect(url_for("categories")) 24 | return render_template("add_category.html") 25 | 26 | 27 | @app.route("/edit_category/", methods=["GET", "POST"]) 28 | def edit_category(category_id): 29 | category = Category.query.get_or_404(category_id) 30 | if request.method == "POST": 31 | category.category_name = request.form.get("category_name") 32 | db.session.commit() 33 | return redirect(url_for("categories")) 34 | return render_template("edit_category.html", category=category) 35 | 36 | 37 | @app.route("/delete_category/") 38 | def delete_category(category_id): 39 | category = Category.query.get_or_404(category_id) 40 | db.session.delete(category) 41 | db.session.commit() 42 | return redirect(url_for("categories")) 43 | -------------------------------------------------------------------------------- /07_deleting_categories/taskmanager/static/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | min-height: 100vh; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1 0 auto; 9 | } 10 | -------------------------------------------------------------------------------- /07_deleting_categories/taskmanager/static/js/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function() { 2 | // sidenav initialization 3 | let sidenav = document.querySelectorAll(".sidenav"); 4 | M.Sidenav.init(sidenav); 5 | }); 6 | -------------------------------------------------------------------------------- /07_deleting_categories/taskmanager/templates/add_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /07_deleting_categories/taskmanager/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 13 | 14 | Task Manager 15 | 16 | 17 | 18 | 19 |
20 | 21 | 32 | 33 | 34 | 39 |
40 | 41 |
42 | {% block content %} 43 | {% endblock %} 44 |
45 | 46 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /07_deleting_categories/taskmanager/templates/categories.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Categories

5 | 6 |
7 | 12 |
13 | 14 |
15 | {% for category in categories %} 16 |
17 |
18 |
19 | {{ category.category_name }} 20 |
21 |
22 | Edit 23 | Delete 24 |
25 |
26 |
27 | {% endfor %} 28 |
29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /07_deleting_categories/taskmanager/templates/edit_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Edit Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /07_deleting_categories/taskmanager/templates/tasks.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Tasks

5 | 6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /08_adding_tasks/env_sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ.setdefault("IP", "0.0.0.0") 4 | os.environ.setdefault("PORT", "5000") 5 | os.environ.setdefault("SECRET_KEY", "any_secret_key") 6 | os.environ.setdefault("DEBUG", "True") 7 | os.environ.setdefault("DEVELOPMENT", "True") 8 | os.environ.setdefault("DB_URL", "postgresql://neondb_owner:password@hostlink.eu-central-1.aws.neon.tech/database_name") 9 | -------------------------------------------------------------------------------- /08_adding_tasks/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from taskmanager import app 3 | 4 | 5 | if __name__ == "__main__": 6 | app.run( 7 | host=os.environ.get("IP"), 8 | port=int(os.environ.get("PORT")), 9 | debug=os.environ.get("DEBUG") 10 | ) 11 | -------------------------------------------------------------------------------- /08_adding_tasks/taskmanager/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from flask_sqlalchemy import SQLAlchemy 4 | if os.path.exists("env.py"): 5 | import env # noqa 6 | 7 | 8 | app = Flask(__name__) 9 | app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") 10 | app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URL") 11 | 12 | db = SQLAlchemy(app) 13 | 14 | from taskmanager import routes # noqa 15 | -------------------------------------------------------------------------------- /08_adding_tasks/taskmanager/models.py: -------------------------------------------------------------------------------- 1 | from taskmanager import db 2 | 3 | 4 | class Category(db.Model): 5 | # schema for the Category model 6 | id = db.Column(db.Integer, primary_key=True) 7 | category_name = db.Column(db.String(25), unique=True, nullable=False) 8 | tasks = db.relationship("Task", backref="category", cascade="all, delete", lazy=True) 9 | 10 | def __repr__(self): 11 | # __repr__ to represent itself in the form of a string 12 | return self.category_name 13 | 14 | 15 | class Task(db.Model): 16 | # schema for the Task model 17 | id = db.Column(db.Integer, primary_key=True) 18 | task_name = db.Column(db.String(50), unique=True, nullable=False) 19 | task_description = db.Column(db.Text, nullable=False) 20 | is_urgent = db.Column(db.Boolean, default=False, nullable=False) 21 | due_date = db.Column(db.Date, nullable=False) 22 | category_id = db.Column(db.Integer, db.ForeignKey("category.id", ondelete="CASCADE"), nullable=False) 23 | 24 | def __repr__(self): 25 | # __repr__ to represent itself in the form of a string 26 | return "#{0} - Task: {1} | Urgent: {2}".format( 27 | self.id, self.task_name, self.is_urgent 28 | ) 29 | -------------------------------------------------------------------------------- /08_adding_tasks/taskmanager/routes.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, request, redirect, url_for 2 | from taskmanager import app, db 3 | from taskmanager.models import Category, Task 4 | 5 | 6 | @app.route("/") 7 | def home(): 8 | return render_template("tasks.html") 9 | 10 | 11 | @app.route("/categories") 12 | def categories(): 13 | categories = list(Category.query.order_by(Category.category_name).all()) 14 | return render_template("categories.html", categories=categories) 15 | 16 | 17 | @app.route("/add_category", methods=["GET", "POST"]) 18 | def add_category(): 19 | if request.method == "POST": 20 | category = Category(category_name=request.form.get("category_name")) 21 | db.session.add(category) 22 | db.session.commit() 23 | return redirect(url_for("categories")) 24 | return render_template("add_category.html") 25 | 26 | 27 | @app.route("/edit_category/", methods=["GET", "POST"]) 28 | def edit_category(category_id): 29 | category = Category.query.get_or_404(category_id) 30 | if request.method == "POST": 31 | category.category_name = request.form.get("category_name") 32 | db.session.commit() 33 | return redirect(url_for("categories")) 34 | return render_template("edit_category.html", category=category) 35 | 36 | 37 | @app.route("/delete_category/") 38 | def delete_category(category_id): 39 | category = Category.query.get_or_404(category_id) 40 | db.session.delete(category) 41 | db.session.commit() 42 | return redirect(url_for("categories")) 43 | 44 | 45 | @app.route("/add_task", methods=["GET", "POST"]) 46 | def add_task(): 47 | categories = list(Category.query.order_by(Category.category_name).all()) 48 | if request.method == "POST": 49 | task = Task( 50 | task_name=request.form.get("task_name"), 51 | task_description=request.form.get("task_description"), 52 | is_urgent=bool(True if request.form.get("is_urgent") else False), 53 | due_date=request.form.get("due_date"), 54 | category_id=request.form.get("category_id") 55 | ) 56 | db.session.add(task) 57 | db.session.commit() 58 | return redirect(url_for("home")) 59 | return render_template("add_task.html", categories=categories) 60 | -------------------------------------------------------------------------------- /08_adding_tasks/taskmanager/static/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | min-height: 100vh; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1 0 auto; 9 | } 10 | -------------------------------------------------------------------------------- /08_adding_tasks/taskmanager/static/js/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function() { 2 | // sidenav initialization 3 | let sidenav = document.querySelectorAll(".sidenav"); 4 | M.Sidenav.init(sidenav); 5 | 6 | // datepicker initialization 7 | let datepicker = document.querySelectorAll(".datepicker"); 8 | M.Datepicker.init(datepicker, { 9 | format: "dd mmmm, yyyy", 10 | i18n: {done: "Select"} 11 | }); 12 | 13 | // select initialization 14 | let selects = document.querySelectorAll("select"); 15 | M.FormSelect.init(selects); 16 | }); 17 | -------------------------------------------------------------------------------- /08_adding_tasks/taskmanager/templates/add_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /08_adding_tasks/taskmanager/templates/add_task.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Task

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 20 | 22 | 23 |
24 |
25 | 26 |
27 |
28 | 29 | 30 | 31 |
32 |
33 | 34 |
35 |
36 |
37 | 38 | 43 |
44 |
45 |
46 | 47 |
48 |
49 | 50 | 56 | 57 |
58 |
59 | 60 |
61 |
62 | 65 |
66 |
67 |
68 |
69 | 70 | {% endblock %} 71 | -------------------------------------------------------------------------------- /08_adding_tasks/taskmanager/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 13 | 14 | Task Manager 15 | 16 | 17 | 18 | 19 |
20 | 21 | 32 | 33 | 34 | 39 |
40 | 41 |
42 | {% block content %} 43 | {% endblock %} 44 |
45 | 46 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /08_adding_tasks/taskmanager/templates/categories.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Categories

5 | 6 |
7 | 12 |
13 | 14 |
15 | {% for category in categories %} 16 |
17 |
18 |
19 | {{ category.category_name }} 20 |
21 |
22 | Edit 23 | Delete 24 |
25 |
26 |
27 | {% endfor %} 28 |
29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /08_adding_tasks/taskmanager/templates/edit_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Edit Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /08_adding_tasks/taskmanager/templates/tasks.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Tasks

5 | 6 |
7 | 12 |
13 | 14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /09_viewing_tasks/env_sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ.setdefault("IP", "0.0.0.0") 4 | os.environ.setdefault("PORT", "5000") 5 | os.environ.setdefault("SECRET_KEY", "any_secret_key") 6 | os.environ.setdefault("DEBUG", "True") 7 | os.environ.setdefault("DEVELOPMENT", "True") 8 | os.environ.setdefault("DB_URL", "postgresql://neondb_owner:password@hostlink.eu-central-1.aws.neon.tech/database_name") 9 | -------------------------------------------------------------------------------- /09_viewing_tasks/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from taskmanager import app 3 | 4 | 5 | if __name__ == "__main__": 6 | app.run( 7 | host=os.environ.get("IP"), 8 | port=int(os.environ.get("PORT")), 9 | debug=os.environ.get("DEBUG") 10 | ) 11 | -------------------------------------------------------------------------------- /09_viewing_tasks/taskmanager/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from flask_sqlalchemy import SQLAlchemy 4 | if os.path.exists("env.py"): 5 | import env # noqa 6 | 7 | 8 | app = Flask(__name__) 9 | app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") 10 | app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URL") 11 | 12 | db = SQLAlchemy(app) 13 | 14 | from taskmanager import routes # noqa 15 | -------------------------------------------------------------------------------- /09_viewing_tasks/taskmanager/models.py: -------------------------------------------------------------------------------- 1 | from taskmanager import db 2 | 3 | 4 | class Category(db.Model): 5 | # schema for the Category model 6 | id = db.Column(db.Integer, primary_key=True) 7 | category_name = db.Column(db.String(25), unique=True, nullable=False) 8 | tasks = db.relationship("Task", backref="category", cascade="all, delete", lazy=True) 9 | 10 | def __repr__(self): 11 | # __repr__ to represent itself in the form of a string 12 | return self.category_name 13 | 14 | 15 | class Task(db.Model): 16 | # schema for the Task model 17 | id = db.Column(db.Integer, primary_key=True) 18 | task_name = db.Column(db.String(50), unique=True, nullable=False) 19 | task_description = db.Column(db.Text, nullable=False) 20 | is_urgent = db.Column(db.Boolean, default=False, nullable=False) 21 | due_date = db.Column(db.Date, nullable=False) 22 | category_id = db.Column(db.Integer, db.ForeignKey("category.id", ondelete="CASCADE"), nullable=False) 23 | 24 | def __repr__(self): 25 | # __repr__ to represent itself in the form of a string 26 | return "#{0} - Task: {1} | Urgent: {2}".format( 27 | self.id, self.task_name, self.is_urgent 28 | ) 29 | -------------------------------------------------------------------------------- /09_viewing_tasks/taskmanager/routes.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, request, redirect, url_for 2 | from taskmanager import app, db 3 | from taskmanager.models import Category, Task 4 | 5 | 6 | @app.route("/") 7 | def home(): 8 | tasks = list(Task.query.order_by(Task.id).all()) 9 | return render_template("tasks.html", tasks=tasks) 10 | 11 | 12 | @app.route("/categories") 13 | def categories(): 14 | categories = list(Category.query.order_by(Category.category_name).all()) 15 | return render_template("categories.html", categories=categories) 16 | 17 | 18 | @app.route("/add_category", methods=["GET", "POST"]) 19 | def add_category(): 20 | if request.method == "POST": 21 | category = Category(category_name=request.form.get("category_name")) 22 | db.session.add(category) 23 | db.session.commit() 24 | return redirect(url_for("categories")) 25 | return render_template("add_category.html") 26 | 27 | 28 | @app.route("/edit_category/", methods=["GET", "POST"]) 29 | def edit_category(category_id): 30 | category = Category.query.get_or_404(category_id) 31 | if request.method == "POST": 32 | category.category_name = request.form.get("category_name") 33 | db.session.commit() 34 | return redirect(url_for("categories")) 35 | return render_template("edit_category.html", category=category) 36 | 37 | 38 | @app.route("/delete_category/") 39 | def delete_category(category_id): 40 | category = Category.query.get_or_404(category_id) 41 | db.session.delete(category) 42 | db.session.commit() 43 | return redirect(url_for("categories")) 44 | 45 | 46 | @app.route("/add_task", methods=["GET", "POST"]) 47 | def add_task(): 48 | categories = list(Category.query.order_by(Category.category_name).all()) 49 | if request.method == "POST": 50 | task = Task( 51 | task_name=request.form.get("task_name"), 52 | task_description=request.form.get("task_description"), 53 | is_urgent=bool(True if request.form.get("is_urgent") else False), 54 | due_date=request.form.get("due_date"), 55 | category_id=request.form.get("category_id") 56 | ) 57 | db.session.add(task) 58 | db.session.commit() 59 | return redirect(url_for("home")) 60 | return render_template("add_task.html", categories=categories) 61 | -------------------------------------------------------------------------------- /09_viewing_tasks/taskmanager/static/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | min-height: 100vh; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1 0 auto; 9 | } 10 | -------------------------------------------------------------------------------- /09_viewing_tasks/taskmanager/static/js/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function() { 2 | // sidenav initialization 3 | let sidenav = document.querySelectorAll(".sidenav"); 4 | M.Sidenav.init(sidenav); 5 | 6 | // datepicker initialization 7 | let datepicker = document.querySelectorAll(".datepicker"); 8 | M.Datepicker.init(datepicker, { 9 | format: "dd mmmm, yyyy", 10 | i18n: {done: "Select"} 11 | }); 12 | 13 | // select initialization 14 | let selects = document.querySelectorAll("select"); 15 | M.FormSelect.init(selects); 16 | 17 | // collapsible initializataion 18 | let collapsibles = document.querySelectorAll(".collapsible"); 19 | M.Collapsible.init(collapsibles); 20 | }); 21 | -------------------------------------------------------------------------------- /09_viewing_tasks/taskmanager/templates/add_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /09_viewing_tasks/taskmanager/templates/add_task.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Task

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 20 | 22 | 23 |
24 |
25 | 26 |
27 |
28 | 29 | 30 | 31 |
32 |
33 | 34 |
35 |
36 |
37 | 38 | 43 |
44 |
45 |
46 | 47 |
48 |
49 | 50 | 56 | 57 |
58 |
59 | 60 |
61 |
62 | 65 |
66 |
67 |
68 |
69 | 70 | {% endblock %} 71 | -------------------------------------------------------------------------------- /09_viewing_tasks/taskmanager/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 13 | 14 | Task Manager 15 | 16 | 17 | 18 | 19 |
20 | 21 | 32 | 33 | 34 | 39 |
40 | 41 |
42 | {% block content %} 43 | {% endblock %} 44 |
45 | 46 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /09_viewing_tasks/taskmanager/templates/categories.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Categories

5 | 6 |
7 | 12 |
13 | 14 |
15 | {% for category in categories %} 16 |
17 |
18 |
19 | {{ category.category_name }} 20 |
21 |
22 | Edit 23 | Delete 24 |
25 |
26 |
27 | {% endfor %} 28 |
29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /09_viewing_tasks/taskmanager/templates/edit_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Edit Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /09_viewing_tasks/taskmanager/templates/tasks.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Tasks

5 | 6 |
7 | 12 |
13 | 14 |
    15 | {% for task in tasks|sort(attribute="due_date") %} 16 |
  • 17 |
    18 | 19 | {{ task.task_name }} : {{ task.due_date.strftime("%d %B, %Y") }} 20 | {% if task.is_urgent == True %} 21 | 22 | {% endif %} 23 |
    24 |
    25 | {{ task.category }} 26 |

    {{ task.task_description }}

    27 |
    28 |
  • 29 | {% endfor %} 30 |
31 | 32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /10_updating_tasks/env_sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ.setdefault("IP", "0.0.0.0") 4 | os.environ.setdefault("PORT", "5000") 5 | os.environ.setdefault("SECRET_KEY", "any_secret_key") 6 | os.environ.setdefault("DEBUG", "True") 7 | os.environ.setdefault("DEVELOPMENT", "True") 8 | os.environ.setdefault("DB_URL", "postgresql://neondb_owner:password@hostlink.eu-central-1.aws.neon.tech/database_name") 9 | -------------------------------------------------------------------------------- /10_updating_tasks/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from taskmanager import app 3 | 4 | 5 | if __name__ == "__main__": 6 | app.run( 7 | host=os.environ.get("IP"), 8 | port=int(os.environ.get("PORT")), 9 | debug=os.environ.get("DEBUG") 10 | ) 11 | -------------------------------------------------------------------------------- /10_updating_tasks/taskmanager/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from flask_sqlalchemy import SQLAlchemy 4 | if os.path.exists("env.py"): 5 | import env # noqa 6 | 7 | 8 | app = Flask(__name__) 9 | app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") 10 | app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URL") 11 | 12 | db = SQLAlchemy(app) 13 | 14 | from taskmanager import routes # noqa 15 | -------------------------------------------------------------------------------- /10_updating_tasks/taskmanager/models.py: -------------------------------------------------------------------------------- 1 | from taskmanager import db 2 | 3 | 4 | class Category(db.Model): 5 | # schema for the Category model 6 | id = db.Column(db.Integer, primary_key=True) 7 | category_name = db.Column(db.String(25), unique=True, nullable=False) 8 | tasks = db.relationship("Task", backref="category", cascade="all, delete", lazy=True) 9 | 10 | def __repr__(self): 11 | # __repr__ to represent itself in the form of a string 12 | return self.category_name 13 | 14 | 15 | class Task(db.Model): 16 | # schema for the Task model 17 | id = db.Column(db.Integer, primary_key=True) 18 | task_name = db.Column(db.String(50), unique=True, nullable=False) 19 | task_description = db.Column(db.Text, nullable=False) 20 | is_urgent = db.Column(db.Boolean, default=False, nullable=False) 21 | due_date = db.Column(db.Date, nullable=False) 22 | category_id = db.Column(db.Integer, db.ForeignKey("category.id", ondelete="CASCADE"), nullable=False) 23 | 24 | def __repr__(self): 25 | # __repr__ to represent itself in the form of a string 26 | return "#{0} - Task: {1} | Urgent: {2}".format( 27 | self.id, self.task_name, self.is_urgent 28 | ) 29 | -------------------------------------------------------------------------------- /10_updating_tasks/taskmanager/routes.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, request, redirect, url_for 2 | from taskmanager import app, db 3 | from taskmanager.models import Category, Task 4 | 5 | 6 | @app.route("/") 7 | def home(): 8 | tasks = list(Task.query.order_by(Task.id).all()) 9 | return render_template("tasks.html", tasks=tasks) 10 | 11 | 12 | @app.route("/categories") 13 | def categories(): 14 | categories = list(Category.query.order_by(Category.category_name).all()) 15 | return render_template("categories.html", categories=categories) 16 | 17 | 18 | @app.route("/add_category", methods=["GET", "POST"]) 19 | def add_category(): 20 | if request.method == "POST": 21 | category = Category(category_name=request.form.get("category_name")) 22 | db.session.add(category) 23 | db.session.commit() 24 | return redirect(url_for("categories")) 25 | return render_template("add_category.html") 26 | 27 | 28 | @app.route("/edit_category/", methods=["GET", "POST"]) 29 | def edit_category(category_id): 30 | category = Category.query.get_or_404(category_id) 31 | if request.method == "POST": 32 | category.category_name = request.form.get("category_name") 33 | db.session.commit() 34 | return redirect(url_for("categories")) 35 | return render_template("edit_category.html", category=category) 36 | 37 | 38 | @app.route("/delete_category/") 39 | def delete_category(category_id): 40 | category = Category.query.get_or_404(category_id) 41 | db.session.delete(category) 42 | db.session.commit() 43 | return redirect(url_for("categories")) 44 | 45 | 46 | @app.route("/add_task", methods=["GET", "POST"]) 47 | def add_task(): 48 | categories = list(Category.query.order_by(Category.category_name).all()) 49 | if request.method == "POST": 50 | task = Task( 51 | task_name=request.form.get("task_name"), 52 | task_description=request.form.get("task_description"), 53 | is_urgent=bool(True if request.form.get("is_urgent") else False), 54 | due_date=request.form.get("due_date"), 55 | category_id=request.form.get("category_id") 56 | ) 57 | db.session.add(task) 58 | db.session.commit() 59 | return redirect(url_for("home")) 60 | return render_template("add_task.html", categories=categories) 61 | 62 | 63 | @app.route("/edit_task/", methods=["GET", "POST"]) 64 | def edit_task(task_id): 65 | task = Task.query.get_or_404(task_id) 66 | categories = list(Category.query.order_by(Category.category_name).all()) 67 | if request.method == "POST": 68 | task.task_name = request.form.get("task_name") 69 | task.task_description = request.form.get("task_description") 70 | task.is_urgent = bool(True if request.form.get("is_urgent") else False) 71 | task.due_date = request.form.get("due_date") 72 | task.category_id = request.form.get("category_id") 73 | db.session.commit() 74 | return render_template("edit_task.html", task=task, categories=categories) 75 | -------------------------------------------------------------------------------- /10_updating_tasks/taskmanager/static/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | min-height: 100vh; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1 0 auto; 9 | } 10 | -------------------------------------------------------------------------------- /10_updating_tasks/taskmanager/static/js/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function() { 2 | // sidenav initialization 3 | let sidenav = document.querySelectorAll(".sidenav"); 4 | M.Sidenav.init(sidenav); 5 | 6 | // datepicker initialization 7 | let datepicker = document.querySelectorAll(".datepicker"); 8 | M.Datepicker.init(datepicker, { 9 | format: "dd mmmm, yyyy", 10 | i18n: {done: "Select"} 11 | }); 12 | 13 | // select initialization 14 | let selects = document.querySelectorAll("select"); 15 | M.FormSelect.init(selects); 16 | 17 | // collapsible initializataion 18 | let collapsibles = document.querySelectorAll(".collapsible"); 19 | M.Collapsible.init(collapsibles); 20 | }); 21 | -------------------------------------------------------------------------------- /10_updating_tasks/taskmanager/templates/add_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /10_updating_tasks/taskmanager/templates/add_task.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Task

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 20 | 22 | 23 |
24 |
25 | 26 |
27 |
28 | 29 | 30 | 31 |
32 |
33 | 34 |
35 |
36 |
37 | 38 | 43 |
44 |
45 |
46 | 47 |
48 |
49 | 50 | 56 | 57 |
58 |
59 | 60 |
61 |
62 | 65 |
66 |
67 |
68 |
69 | 70 | {% endblock %} 71 | -------------------------------------------------------------------------------- /10_updating_tasks/taskmanager/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 13 | 14 | Task Manager 15 | 16 | 17 | 18 | 19 |
20 | 21 | 32 | 33 | 34 | 39 |
40 | 41 |
42 | {% block content %} 43 | {% endblock %} 44 |
45 | 46 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /10_updating_tasks/taskmanager/templates/categories.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Categories

5 | 6 |
7 | 12 |
13 | 14 |
15 | {% for category in categories %} 16 |
17 |
18 |
19 | {{ category.category_name }} 20 |
21 |
22 | Edit 23 | Delete 24 |
25 |
26 |
27 | {% endfor %} 28 |
29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /10_updating_tasks/taskmanager/templates/edit_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Edit Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /10_updating_tasks/taskmanager/templates/edit_task.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Edit Task

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 14 | 15 |
16 |
17 | 18 |
19 |
20 | 21 | 25 | 26 |
27 |
28 | 29 |
30 |
31 | 32 | 34 | 35 |
36 |
37 | 38 |
39 |
40 |
41 | 42 | 51 |
52 |
53 |
54 | 55 |
56 |
57 | 58 | 68 | 69 |
70 |
71 | 72 |
73 |
74 | 77 |
78 |
79 |
80 |
81 | 82 | {% endblock %} 83 | -------------------------------------------------------------------------------- /10_updating_tasks/taskmanager/templates/tasks.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Tasks

5 | 6 |
7 | 12 |
13 | 14 |
    15 | {% for task in tasks|sort(attribute="due_date") %} 16 |
  • 17 |
    18 | 19 | {{ task.task_name }} : {{ task.due_date.strftime("%d %B, %Y") }} 20 | {% if task.is_urgent == True %} 21 | 22 | {% endif %} 23 |
    24 |
    25 | {{ task.category }} 26 |

    {{ task.task_description }}

    27 |

    28 | Edit 29 |

    30 |
    31 |
  • 32 | {% endfor %} 33 |
34 | 35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /11_deleting_tasks/env_sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ.setdefault("IP", "0.0.0.0") 4 | os.environ.setdefault("PORT", "5000") 5 | os.environ.setdefault("SECRET_KEY", "any_secret_key") 6 | os.environ.setdefault("DEBUG", "True") 7 | os.environ.setdefault("DEVELOPMENT", "True") 8 | os.environ.setdefault("DB_URL", "postgresql://neondb_owner:password@hostlink.eu-central-1.aws.neon.tech/database_name") 9 | -------------------------------------------------------------------------------- /11_deleting_tasks/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from taskmanager import app 3 | 4 | 5 | if __name__ == "__main__": 6 | app.run( 7 | host=os.environ.get("IP"), 8 | port=int(os.environ.get("PORT")), 9 | debug=os.environ.get("DEBUG") 10 | ) 11 | -------------------------------------------------------------------------------- /11_deleting_tasks/taskmanager/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from flask_sqlalchemy import SQLAlchemy 4 | if os.path.exists("env.py"): 5 | import env # noqa 6 | 7 | 8 | app = Flask(__name__) 9 | app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") 10 | app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URL") 11 | 12 | db = SQLAlchemy(app) 13 | 14 | from taskmanager import routes # noqa 15 | -------------------------------------------------------------------------------- /11_deleting_tasks/taskmanager/models.py: -------------------------------------------------------------------------------- 1 | from taskmanager import db 2 | 3 | 4 | class Category(db.Model): 5 | # schema for the Category model 6 | id = db.Column(db.Integer, primary_key=True) 7 | category_name = db.Column(db.String(25), unique=True, nullable=False) 8 | tasks = db.relationship("Task", backref="category", cascade="all, delete", lazy=True) 9 | 10 | def __repr__(self): 11 | # __repr__ to represent itself in the form of a string 12 | return self.category_name 13 | 14 | 15 | class Task(db.Model): 16 | # schema for the Task model 17 | id = db.Column(db.Integer, primary_key=True) 18 | task_name = db.Column(db.String(50), unique=True, nullable=False) 19 | task_description = db.Column(db.Text, nullable=False) 20 | is_urgent = db.Column(db.Boolean, default=False, nullable=False) 21 | due_date = db.Column(db.Date, nullable=False) 22 | category_id = db.Column(db.Integer, db.ForeignKey("category.id", ondelete="CASCADE"), nullable=False) 23 | 24 | def __repr__(self): 25 | # __repr__ to represent itself in the form of a string 26 | return "#{0} - Task: {1} | Urgent: {2}".format( 27 | self.id, self.task_name, self.is_urgent 28 | ) 29 | -------------------------------------------------------------------------------- /11_deleting_tasks/taskmanager/routes.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, request, redirect, url_for 2 | from taskmanager import app, db 3 | from taskmanager.models import Category, Task 4 | 5 | 6 | @app.route("/") 7 | def home(): 8 | tasks = list(Task.query.order_by(Task.id).all()) 9 | return render_template("tasks.html", tasks=tasks) 10 | 11 | 12 | @app.route("/categories") 13 | def categories(): 14 | categories = list(Category.query.order_by(Category.category_name).all()) 15 | return render_template("categories.html", categories=categories) 16 | 17 | 18 | @app.route("/add_category", methods=["GET", "POST"]) 19 | def add_category(): 20 | if request.method == "POST": 21 | category = Category(category_name=request.form.get("category_name")) 22 | db.session.add(category) 23 | db.session.commit() 24 | return redirect(url_for("categories")) 25 | return render_template("add_category.html") 26 | 27 | 28 | @app.route("/edit_category/", methods=["GET", "POST"]) 29 | def edit_category(category_id): 30 | category = Category.query.get_or_404(category_id) 31 | if request.method == "POST": 32 | category.category_name = request.form.get("category_name") 33 | db.session.commit() 34 | return redirect(url_for("categories")) 35 | return render_template("edit_category.html", category=category) 36 | 37 | 38 | @app.route("/delete_category/") 39 | def delete_category(category_id): 40 | category = Category.query.get_or_404(category_id) 41 | db.session.delete(category) 42 | db.session.commit() 43 | return redirect(url_for("categories")) 44 | 45 | 46 | @app.route("/add_task", methods=["GET", "POST"]) 47 | def add_task(): 48 | categories = list(Category.query.order_by(Category.category_name).all()) 49 | if request.method == "POST": 50 | task = Task( 51 | task_name=request.form.get("task_name"), 52 | task_description=request.form.get("task_description"), 53 | is_urgent=bool(True if request.form.get("is_urgent") else False), 54 | due_date=request.form.get("due_date"), 55 | category_id=request.form.get("category_id") 56 | ) 57 | db.session.add(task) 58 | db.session.commit() 59 | return redirect(url_for("home")) 60 | return render_template("add_task.html", categories=categories) 61 | 62 | 63 | @app.route("/edit_task/", methods=["GET", "POST"]) 64 | def edit_task(task_id): 65 | task = Task.query.get_or_404(task_id) 66 | categories = list(Category.query.order_by(Category.category_name).all()) 67 | if request.method == "POST": 68 | task.task_name = request.form.get("task_name") 69 | task.task_description = request.form.get("task_description") 70 | task.is_urgent = bool(True if request.form.get("is_urgent") else False) 71 | task.due_date = request.form.get("due_date") 72 | task.category_id = request.form.get("category_id") 73 | db.session.commit() 74 | return render_template("edit_task.html", task=task, categories=categories) 75 | 76 | 77 | @app.route("/delete_task/") 78 | def delete_task(task_id): 79 | task = Task.query.get_or_404(task_id) 80 | db.session.delete(task) 81 | db.session.commit() 82 | return redirect(url_for("home")) 83 | -------------------------------------------------------------------------------- /11_deleting_tasks/taskmanager/static/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | min-height: 100vh; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1 0 auto; 9 | } 10 | -------------------------------------------------------------------------------- /11_deleting_tasks/taskmanager/static/js/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function() { 2 | // sidenav initialization 3 | let sidenav = document.querySelectorAll(".sidenav"); 4 | M.Sidenav.init(sidenav); 5 | 6 | // datepicker initialization 7 | let datepicker = document.querySelectorAll(".datepicker"); 8 | M.Datepicker.init(datepicker, { 9 | format: "dd mmmm, yyyy", 10 | i18n: {done: "Select"} 11 | }); 12 | 13 | // select initialization 14 | let selects = document.querySelectorAll("select"); 15 | M.FormSelect.init(selects); 16 | 17 | // collapsible initializataion 18 | let collapsibles = document.querySelectorAll(".collapsible"); 19 | M.Collapsible.init(collapsibles); 20 | }); 21 | -------------------------------------------------------------------------------- /11_deleting_tasks/taskmanager/templates/add_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /11_deleting_tasks/taskmanager/templates/add_task.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Task

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 20 | 22 | 23 |
24 |
25 | 26 |
27 |
28 | 29 | 30 | 31 |
32 |
33 | 34 |
35 |
36 |
37 | 38 | 43 |
44 |
45 |
46 | 47 |
48 |
49 | 50 | 56 | 57 |
58 |
59 | 60 |
61 |
62 | 65 |
66 |
67 |
68 |
69 | 70 | {% endblock %} 71 | -------------------------------------------------------------------------------- /11_deleting_tasks/taskmanager/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 13 | 14 | Task Manager 15 | 16 | 17 | 18 | 19 |
20 | 21 | 32 | 33 | 34 | 39 |
40 | 41 |
42 | {% block content %} 43 | {% endblock %} 44 |
45 | 46 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /11_deleting_tasks/taskmanager/templates/categories.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Categories

5 | 6 |
7 | 12 |
13 | 14 |
15 | {% for category in categories %} 16 |
17 |
18 |
19 | {{ category.category_name }} 20 |
21 |
22 | Edit 23 | Delete 24 |
25 |
26 |
27 | {% endfor %} 28 |
29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /11_deleting_tasks/taskmanager/templates/edit_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Edit Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /11_deleting_tasks/taskmanager/templates/edit_task.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Edit Task

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 14 | 15 |
16 |
17 | 18 |
19 |
20 | 21 | 25 | 26 |
27 |
28 | 29 |
30 |
31 | 32 | 34 | 35 |
36 |
37 | 38 |
39 |
40 |
41 | 42 | 51 |
52 |
53 |
54 | 55 |
56 |
57 | 58 | 68 | 69 |
70 |
71 | 72 |
73 |
74 | 77 |
78 |
79 |
80 |
81 | 82 | {% endblock %} 83 | -------------------------------------------------------------------------------- /11_deleting_tasks/taskmanager/templates/tasks.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Tasks

5 | 6 |
7 | 12 |
13 | 14 |
    15 | {% for task in tasks|sort(attribute="due_date") %} 16 |
  • 17 |
    18 | 19 | {{ task.task_name }} : {{ task.due_date.strftime("%d %B, %Y") }} 20 | {% if task.is_urgent == True %} 21 | 22 | {% endif %} 23 |
    24 |
    25 | {{ task.category }} 26 |

    {{ task.task_description }}

    27 |

    28 | Edit 29 | Delete 30 |

    31 |
    32 |
  • 33 | {% endfor %} 34 |
35 | 36 | {% endblock %} 37 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/COMMANDS.md: -------------------------------------------------------------------------------- 1 | # 12 - Deploying Our Project to Heroku 2 | 3 | --- 4 | 5 | ### Check which Python packages are currently installed in our workspace 6 | - `pip3 list` 7 | 8 | ### Freeze the current Python packages into a `requirements.txt` file 9 | - `pip3 freeze --local > requirements.txt` 10 | 11 | ### Create the `Procfile` required for Heroku 12 | - `echo web: python run.py > Procfile` 13 | 14 | ### Heroku: Postgres Add-On 15 | - From the **Resources** tab on Heroku, search for `heroku postgres` within the **Add-Ons** section. 16 | - Select the `Hobby Dev - Free` option, and submit. 17 | - From the **Settings** tab on Heroku, and click "Reveal Conig Vars" 18 | - Add the remaining environment variables hidden within our `env.py` to the Heroku config vars: 19 | - `DATABASE_URL`: comes with the **postgres add-on** above 20 | - `IP`: `0.0.0.0` 21 | - `PORT`: `5000` 22 | - `SECRET_KEY`: `any_secret_key` 23 | - `DEBUG`: `True` (*only during development*) 24 | - ~~`DEVELOPMENT`~~: **DO NOT INCLUDE ON HEROKU** 25 | - ~~`DB_URL`~~: **DO NOT INCLUDE ON HEROKU** 26 | - From the **Deploy** tab on Heroku, these next steps are for Automatic Deploys using GitHub: 27 | - Select **GitHub** for the deployment method. 28 | - Ensure your GitHub profile name is listed, and then input your repository name. 29 | - Once Heroku sees your repository, click "Connect". 30 | - Select the appropriate branch to deploy from (usually `main` or `master`). 31 | - Click "Enable Automatic Deploys". 32 | - Click "Deploy Branch". (*can take a few minutes to build*) 33 | - Once the app successfully builds, go back to the **Settings** tab. 34 | - Click "Reveal Config Vars". 35 | - If the `DATABASE_URL` starts with `postgres://` instead of `postgresql://`, then follow these steps: 36 | - Open the `__init__.py` file. 37 | - `import re` at the top. 38 | - Within the `else:` statement, replace the code with the following: 39 | - ```python 40 | else: 41 | uri = os.environ.get("DATABASE_URL") 42 | if uri.startswith("postgres://"): 43 | uri = uri.replace("postgres://", "postgresql://", 1) 44 | app.config["SQLALCHEMY_DATABASE_URI"] = uri 45 | ``` 46 | - Commit all changes to GitHub. 47 | - From the **Activity** tab on Heroku, make sure the build completes with those changes. 48 | - Click the **More** dropdown in the top-right corner of Heroku. 49 | - Select "Run Console", and follow these steps in the console: 50 | - `python3` 51 | - `from taskmanager import db` 52 | - `db.create_all()` 53 | - `exit()` 54 | - Everything should be connected and working now, so click the **Open App** button. 55 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/Procfile: -------------------------------------------------------------------------------- 1 | web: python run.py -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/env_sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ.setdefault("IP", "0.0.0.0") 4 | os.environ.setdefault("PORT", "5000") 5 | os.environ.setdefault("SECRET_KEY", "any_secret_key") 6 | os.environ.setdefault("DEBUG", "True") 7 | os.environ.setdefault("DEVELOPMENT", "True") 8 | os.environ.setdefault("DB_URL", "postgresql://neondb_owner:password@hostlink.eu-central-1.aws.neon.tech/database_name") 9 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/requirements.txt: -------------------------------------------------------------------------------- 1 | click==8.0.1 2 | Flask==2.0.1 3 | Flask-SQLAlchemy==2.5.1 4 | greenlet==1.1.0 5 | itsdangerous==2.0.1 6 | Jinja2==3.0.1 7 | MarkupSafe==2.0.1 8 | psycopg2==2.9.1 9 | SQLAlchemy==1.4.18 10 | Werkzeug==2.0.1 11 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from taskmanager import app 3 | 4 | 5 | if __name__ == "__main__": 6 | app.run( 7 | host=os.environ.get("IP"), 8 | port=int(os.environ.get("PORT")), 9 | debug=os.environ.get("DEBUG") 10 | ) 11 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/taskmanager/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | from flask import Flask 4 | from flask_sqlalchemy import SQLAlchemy 5 | if os.path.exists("env.py"): 6 | import env # noqa 7 | 8 | 9 | app = Flask(__name__) 10 | app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") 11 | 12 | if os.environ.get("DEVELOPMENT") == "True": 13 | app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URL") # local 14 | else: 15 | uri = os.environ.get("DATABASE_URL") 16 | if uri.startswith("postgres://"): 17 | uri = uri.replace("postgres://", "postgresql://", 1) 18 | app.config["SQLALCHEMY_DATABASE_URI"] = uri # heroku 19 | 20 | db = SQLAlchemy(app) 21 | 22 | from taskmanager import routes # noqa 23 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/taskmanager/models.py: -------------------------------------------------------------------------------- 1 | from taskmanager import db 2 | 3 | 4 | class Category(db.Model): 5 | # schema for the Category model 6 | id = db.Column(db.Integer, primary_key=True) 7 | category_name = db.Column(db.String(25), unique=True, nullable=False) 8 | tasks = db.relationship("Task", backref="category", cascade="all, delete", lazy=True) 9 | 10 | def __repr__(self): 11 | # __repr__ to represent itself in the form of a string 12 | return self.category_name 13 | 14 | 15 | class Task(db.Model): 16 | # schema for the Task model 17 | id = db.Column(db.Integer, primary_key=True) 18 | task_name = db.Column(db.String(50), unique=True, nullable=False) 19 | task_description = db.Column(db.Text, nullable=False) 20 | is_urgent = db.Column(db.Boolean, default=False, nullable=False) 21 | due_date = db.Column(db.Date, nullable=False) 22 | category_id = db.Column(db.Integer, db.ForeignKey("category.id", ondelete="CASCADE"), nullable=False) 23 | 24 | def __repr__(self): 25 | # __repr__ to represent itself in the form of a string 26 | return "#{0} - Task: {1} | Urgent: {2}".format( 27 | self.id, self.task_name, self.is_urgent 28 | ) 29 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/taskmanager/routes.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, request, redirect, url_for 2 | from taskmanager import app, db 3 | from taskmanager.models import Category, Task 4 | 5 | 6 | @app.route("/") 7 | def home(): 8 | tasks = list(Task.query.order_by(Task.id).all()) 9 | return render_template("tasks.html", tasks=tasks) 10 | 11 | 12 | @app.route("/categories") 13 | def categories(): 14 | categories = list(Category.query.order_by(Category.category_name).all()) 15 | return render_template("categories.html", categories=categories) 16 | 17 | 18 | @app.route("/add_category", methods=["GET", "POST"]) 19 | def add_category(): 20 | if request.method == "POST": 21 | category = Category(category_name=request.form.get("category_name")) 22 | db.session.add(category) 23 | db.session.commit() 24 | return redirect(url_for("categories")) 25 | return render_template("add_category.html") 26 | 27 | 28 | @app.route("/edit_category/", methods=["GET", "POST"]) 29 | def edit_category(category_id): 30 | category = Category.query.get_or_404(category_id) 31 | if request.method == "POST": 32 | category.category_name = request.form.get("category_name") 33 | db.session.commit() 34 | return redirect(url_for("categories")) 35 | return render_template("edit_category.html", category=category) 36 | 37 | 38 | @app.route("/delete_category/") 39 | def delete_category(category_id): 40 | category = Category.query.get_or_404(category_id) 41 | db.session.delete(category) 42 | db.session.commit() 43 | return redirect(url_for("categories")) 44 | 45 | 46 | @app.route("/add_task", methods=["GET", "POST"]) 47 | def add_task(): 48 | categories = list(Category.query.order_by(Category.category_name).all()) 49 | if request.method == "POST": 50 | task = Task( 51 | task_name=request.form.get("task_name"), 52 | task_description=request.form.get("task_description"), 53 | is_urgent=bool(True if request.form.get("is_urgent") else False), 54 | due_date=request.form.get("due_date"), 55 | category_id=request.form.get("category_id") 56 | ) 57 | db.session.add(task) 58 | db.session.commit() 59 | return redirect(url_for("home")) 60 | return render_template("add_task.html", categories=categories) 61 | 62 | 63 | @app.route("/edit_task/", methods=["GET", "POST"]) 64 | def edit_task(task_id): 65 | task = Task.query.get_or_404(task_id) 66 | categories = list(Category.query.order_by(Category.category_name).all()) 67 | if request.method == "POST": 68 | task.task_name = request.form.get("task_name") 69 | task.task_description = request.form.get("task_description") 70 | task.is_urgent = bool(True if request.form.get("is_urgent") else False) 71 | task.due_date = request.form.get("due_date") 72 | task.category_id = request.form.get("category_id") 73 | db.session.commit() 74 | return render_template("edit_task.html", task=task, categories=categories) 75 | 76 | 77 | @app.route("/delete_task/") 78 | def delete_task(task_id): 79 | task = Task.query.get_or_404(task_id) 80 | db.session.delete(task) 81 | db.session.commit() 82 | return redirect(url_for("home")) 83 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/taskmanager/static/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | min-height: 100vh; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1 0 auto; 9 | } 10 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/taskmanager/static/js/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function() { 2 | // sidenav initialization 3 | let sidenav = document.querySelectorAll(".sidenav"); 4 | M.Sidenav.init(sidenav); 5 | 6 | // datepicker initialization 7 | let datepicker = document.querySelectorAll(".datepicker"); 8 | M.Datepicker.init(datepicker, { 9 | format: "dd mmmm, yyyy", 10 | i18n: {done: "Select"} 11 | }); 12 | 13 | // select initialization 14 | let selects = document.querySelectorAll("select"); 15 | M.FormSelect.init(selects); 16 | 17 | // collapsible initializataion 18 | let collapsibles = document.querySelectorAll(".collapsible"); 19 | M.Collapsible.init(collapsibles); 20 | }); 21 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/taskmanager/templates/add_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/taskmanager/templates/add_task.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Add Task

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 20 | 22 | 23 |
24 |
25 | 26 |
27 |
28 | 29 | 30 | 31 |
32 |
33 | 34 |
35 |
36 |
37 | 38 | 43 |
44 |
45 |
46 | 47 |
48 |
49 | 50 | 56 | 57 |
58 |
59 | 60 |
61 |
62 | 65 |
66 |
67 |
68 |
69 | 70 | {% endblock %} 71 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/taskmanager/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 13 | 14 | Task Manager 15 | 16 | 17 | 18 | 19 |
20 | 21 | 32 | 33 | 34 | 39 |
40 | 41 |
42 | {% block content %} 43 | {% endblock %} 44 |
45 | 46 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/taskmanager/templates/categories.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Categories

5 | 6 |
7 | 12 |
13 | 14 |
15 | {% for category in categories %} 16 |
17 |
18 |
19 | {{ category.category_name }} 20 |
21 |
22 | Edit 23 | Delete 24 |
25 |
26 |
27 | {% endfor %} 28 |
29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/taskmanager/templates/edit_category.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Edit Category

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 | 22 |
23 |
24 |
25 |
26 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/taskmanager/templates/edit_task.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Edit Task

5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 | 14 | 15 |
16 |
17 | 18 |
19 |
20 | 21 | 25 | 26 |
27 |
28 | 29 |
30 |
31 | 32 | 34 | 35 |
36 |
37 | 38 |
39 |
40 |
41 | 42 | 51 |
52 |
53 |
54 | 55 |
56 |
57 | 58 | 68 | 69 |
70 |
71 | 72 |
73 |
74 | 77 |
78 |
79 |
80 |
81 | 82 | {% endblock %} 83 | -------------------------------------------------------------------------------- /12_deploying_our_project_to_heroku/taskmanager/templates/tasks.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 |

Tasks

5 | 6 |
7 | 12 |
13 | 14 |
    15 | {% for task in tasks|sort(attribute="due_date") %} 16 |
  • 17 |
    18 | 19 | {{ task.task_name }} : {{ task.due_date.strftime("%d %B, %Y") }} 20 | {% if task.is_urgent == True %} 21 | 22 | {% endif %} 23 |
    24 |
    25 | {{ task.category }} 26 |

    {{ task.task_description }}

    27 |

    28 | Edit 29 | Delete 30 |

    31 |
    32 |
  • 33 | {% endfor %} 34 |
35 | 36 | {% endblock %} 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DBMS lessons - source code (task manager mini-project) 2 | 3 | ### [Lesson 01 - Putting the Basics Into Place](https://github.com/Code-Institute-Solutions/flask-sqlalchemy-task-manager/tree/main/01_putting_the_basics_into_place) 4 | 5 | ### [Lesson 02 - Creating the Database](https://github.com/Code-Institute-Solutions/flask-sqlalchemy-task-manager/tree/main/02_creating_the_database) 6 | 7 | ### [Lesson 03 - Template Inheritance](https://github.com/Code-Institute-Solutions/flask-sqlalchemy-task-manager/tree/main/03_template_inheritance) 8 | 9 | ### [Lesson 04 - Adding Categories](https://github.com/Code-Institute-Solutions/flask-sqlalchemy-task-manager/tree/main/04_adding_categories) 10 | 11 | ### [Lesson 05 - Viewing Categories](https://github.com/Code-Institute-Solutions/flask-sqlalchemy-task-manager/tree/main/05_viewing_categories) 12 | 13 | ### [Lesson 06 - Updating Categories](https://github.com/Code-Institute-Solutions/flask-sqlalchemy-task-manager/tree/main/06_updating_categories) 14 | 15 | ### [Lesson 07 - Deleting Categories](https://github.com/Code-Institute-Solutions/flask-sqlalchemy-task-manager/tree/main/07_deleting_categories) 16 | 17 | ### [Lesson 08 - Adding Tasks](https://github.com/Code-Institute-Solutions/flask-sqlalchemy-task-manager/tree/main/08_adding_tasks) 18 | 19 | ### [Lesson 09 - Viewing Tasks](https://github.com/Code-Institute-Solutions/flask-sqlalchemy-task-manager/tree/main/09_viewing_tasks) 20 | 21 | ### [Lesson 10 - Updating Tasks](https://github.com/Code-Institute-Solutions/flask-sqlalchemy-task-manager/tree/main/10_updating_tasks) 22 | 23 | ### [Lesson 11 - Deleting Tasks](https://github.com/Code-Institute-Solutions/flask-sqlalchemy-task-manager/tree/main/11_deleting_tasks) 24 | 25 | ### [Lesson 12 - Deploying Our Project to Heroku](https://github.com/Code-Institute-Solutions/flask-sqlalchemy-task-manager/tree/main/12_deploying_our_project_to_heroku) 26 | --------------------------------------------------------------------------------