├── .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 |
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 |
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 |
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 |
13 |
14 |
15 | {% for category in categories %}
16 |
17 |
18 |
19 | {{ category.category_name }}
20 |
21 |
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 |
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 |
13 |
14 |
15 | {% for category in categories %}
16 |
17 |
18 |
19 | {{ category.category_name }}
20 |
21 |
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 |
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 |
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 |
13 |
14 |
15 | {% for category in categories %}
16 |
17 |
18 |
19 | {{ category.category_name }}
20 |
21 |
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 |
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 |
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 |
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 |
13 |
14 |
15 | {% for category in categories %}
16 |
17 |
18 |
19 | {{ category.category_name }}
20 |
21 |
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 |
25 |
26 |
27 | {% endblock %}
28 |
--------------------------------------------------------------------------------
/08_adding_tasks/taskmanager/templates/tasks.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block content %}
3 |
4 | Tasks
5 |
6 |
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 |
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 |
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 |
13 |
14 |
15 | {% for category in categories %}
16 |
17 |
18 |
19 | {{ category.category_name }}
20 |
21 |
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 |
25 |
26 |
27 | {% endblock %}
28 |
--------------------------------------------------------------------------------
/09_viewing_tasks/taskmanager/templates/tasks.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block content %}
3 |
4 | Tasks
5 |
6 |
13 |
14 |
15 | {% for task in tasks|sort(attribute="due_date") %}
16 | -
17 |
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 |
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 |
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 |
13 |
14 |
15 | {% for category in categories %}
16 |
17 |
18 |
19 | {{ category.category_name }}
20 |
21 |
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 |
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 |
80 |
81 |
82 | {% endblock %}
83 |
--------------------------------------------------------------------------------
/10_updating_tasks/taskmanager/templates/tasks.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block content %}
3 |
4 | Tasks
5 |
6 |
13 |
14 |
15 | {% for task in tasks|sort(attribute="due_date") %}
16 | -
17 |
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 |
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 |
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 |
13 |
14 |
15 | {% for category in categories %}
16 |
17 |
18 |
19 | {{ category.category_name }}
20 |
21 |
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 |
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 |
80 |
81 |
82 | {% endblock %}
83 |
--------------------------------------------------------------------------------
/11_deleting_tasks/taskmanager/templates/tasks.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block content %}
3 |
4 | Tasks
5 |
6 |
13 |
14 |
15 | {% for task in tasks|sort(attribute="due_date") %}
16 | -
17 |
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 |
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 |
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 |
13 |
14 |
15 | {% for category in categories %}
16 |
17 |
18 |
19 | {{ category.category_name }}
20 |
21 |
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 |
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 |
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 |
13 |
14 |
15 | {% for task in tasks|sort(attribute="due_date") %}
16 | -
17 |
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 |
--------------------------------------------------------------------------------