-
Notifications
You must be signed in to change notification settings - Fork 15
Task List Project #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
fc0acdb
6adbbba
5c3e2a2
95622d9
b30289d
68003fd
88a548a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,29 @@ | ||
from flask import Flask | ||
from flask_sqlalchemy import SQLAlchemy | ||
from flask_migrate import Migrate | ||
import os | ||
from dotenv import load_dotenv | ||
|
||
|
||
db = SQLAlchemy() | ||
migrate = Migrate() | ||
load_dotenv() | ||
|
||
|
||
def create_app(test_config=None): | ||
app = Flask(__name__) | ||
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False | ||
|
||
if test_config is None: | ||
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get( | ||
"SQLALCHEMY_DATABASE_URI") | ||
else: | ||
app.config["TESTING"] = True | ||
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get( | ||
"SQLALCHEMY_TEST_DATABASE_URI") | ||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False | ||
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://postgres:postgres@localhost:5432/task_list_api_development' | ||
|
||
db.init_app(app) | ||
migrate.init_app(app, db) | ||
|
||
# Import models here for Alembic setup | ||
from app.models.task import Task | ||
from app.models.goal import Goal | ||
|
||
db.init_app(app) | ||
migrate.init_app(app, db) | ||
from .routes import task_list_api_bp | ||
app.register_blueprint(task_list_api_bp) | ||
|
||
# Register Blueprints here | ||
from .routes import goals_bp | ||
app.register_blueprint(goals_bp) | ||
|
||
return app | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# from flask import Flask | ||
# from flask_sqlalchemy import SQLAlchemy | ||
# from flask_migrate import Migrate | ||
|
||
# db = SQLAlchemy() | ||
# migrate = Migrate() | ||
|
||
|
||
# def create_app(test_config=None): | ||
# app = Flask(__name__) | ||
|
||
# app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False | ||
# app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://postgres:postgres@localhost:5432/task_list_api_development' | ||
|
||
# db.init_app(app) | ||
# migrate.init_app(app, db) | ||
|
||
# from app.models.task import Task | ||
|
||
# return app | ||
Comment on lines
+1
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove commented code |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,6 @@ | |
|
||
|
||
class Goal(db.Model): | ||
goal_id = db.Column(db.Integer, primary_key=True) | ||
id = db.Column(db.Integer, primary_key=True) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good change! |
||
title = db.Column(db.String) | ||
tasks = db.relationship('Task', backref='goal', lazy=True) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,8 @@ | |
|
||
|
||
class Task(db.Model): | ||
task_id = db.Column(db.Integer, primary_key=True) | ||
id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good change! |
||
title = db.Column(db.String) | ||
description = db.Column(db.String) | ||
completed_at = db.Column(db.DateTime, nullable=True, default=None) | ||
goal_id = db.Column(db.Integer, db.ForeignKey('goal.id'), nullable=True) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,284 @@ | ||
from flask import Blueprint | ||
from flask import Blueprint, request, jsonify, make_response | ||
from app import db | ||
from app.models.task import Task | ||
from app.models.goal import Goal | ||
from datetime import datetime | ||
import os | ||
import requests | ||
from dotenv import load_dotenv | ||
|
||
load_dotenv() | ||
|
||
task_list_api_bp = Blueprint("task_list_api", __name__, url_prefix="/tasks") | ||
goals_bp = Blueprint("goals", __name__, url_prefix="/goals") | ||
|
||
|
||
@task_list_api_bp.route("", methods=["GET", "POST"]) | ||
def tasks(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because GET and POST are not using the same code you could consider created two different methods to handle GET and POST. For example, |
||
if request.method == "GET": | ||
tasks_sort = request.args.get("sort") | ||
tasks = Task.query.all() | ||
|
||
if tasks_sort: | ||
if tasks_sort == "asc": | ||
tasks = Task.query.order_by(Task.title).all() | ||
elif tasks_sort == "desc": | ||
tasks = Task.query.order_by(Task.title.desc()).all() | ||
else: | ||
tasks = Task.query.all() | ||
|
||
tasks_response = [] | ||
# is_complete = task.completed_at | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove this commented code |
||
|
||
for task in tasks: | ||
is_complete = task.completed_at | ||
if task.completed_at != None: | ||
is_complete = True | ||
elif tasks_sort and task.completed_at is None: | ||
is_complete = False | ||
|
||
tasks_response.append({ | ||
"id": task.id, | ||
"title": task.title, | ||
"description": task.description, | ||
"is_complete": is_complete | ||
}) | ||
|
||
return jsonify(tasks_response) | ||
|
||
elif request.method == "POST": | ||
|
||
request_body = request.get_json(force=True) | ||
|
||
if 'title' not in request_body or 'description' not in request_body or 'completed_at' not in request_body: | ||
return {"details": "Invalid data"}, 400 | ||
new_task = Task(title=request_body["title"], | ||
description=request_body["description"], | ||
completed_at=request_body["completed_at"]) | ||
db.session.add(new_task) | ||
db.session.commit() | ||
|
||
return { | ||
"task": { | ||
"id": new_task.id, | ||
"title": new_task.title, | ||
"description": new_task.description, | ||
"is_complete": True if new_task.completed_at else False | ||
} | ||
}, 201 | ||
|
||
|
||
@task_list_api_bp.route("/<task_id>", methods=["GET", "DELETE", "PUT"]) | ||
def handle_task(task_id): | ||
task = Task.query.get(task_id) | ||
if task is None: | ||
return make_response(f"{task_id} doesnt exist", 404) | ||
|
||
# is_complete = task.completed_at | ||
# if task.completed_at != None: | ||
# is_complete == True | ||
# print(is_complete) | ||
|
||
if request.method == "GET": | ||
select_task = { | ||
"task": { | ||
"id": task.id, | ||
"title": task.title, | ||
"description": task.description, | ||
"is_complete": task.completed_at | ||
} | ||
Comment on lines
+84
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. consider creating a helper function to add this. This makes your code more readable. |
||
} | ||
return jsonify(select_task), 200 | ||
|
||
elif request.method == "DELETE": | ||
db.session.delete(task) | ||
db.session.commit() | ||
return make_response({"details": f"Task {task.id} \"{task.title}\" successfully deleted"}) | ||
|
||
elif request.method == "PUT": | ||
form_data = request.get_json() | ||
task.title = form_data["title"] | ||
task.description = form_data["description"] | ||
completed_at = form_data["completed_at"] | ||
|
||
db.session.commit() | ||
|
||
return { | ||
"task": { | ||
"id": task.id, | ||
"title": "Updated Task Title", | ||
"description": "Updated Test Description", | ||
"is_complete": True if task.completed_at else False | ||
} | ||
}, 200 | ||
|
||
|
||
def post_slack(message_slack): | ||
|
||
TOKEN_SLACK = os.environ.get( | ||
"SLACK_BOT_TOKEN") | ||
slack_path = "https://slack.com/api/chat.postMessage" | ||
query_params = { | ||
'channel': 'task-notifications', | ||
'text': message_slack | ||
} | ||
headers = {'Authorization': f"Bearer {TOKEN_SLACK}"} | ||
requests.post(slack_path, params=query_params, headers=headers) | ||
|
||
|
||
@task_list_api_bp.route("/<task_id>/mark_complete", methods=["PATCH"]) | ||
def mark_complete(task_id): | ||
task = Task.query.get(task_id) | ||
|
||
if task is None: | ||
return make_response(f"{task_id} doesnt exist", 404) | ||
task.completed_at = datetime.utcnow() | ||
|
||
db.session.commit() | ||
|
||
if request.method == "PATCH": | ||
message_slack = f"Someone just completed the task: {task.title}" | ||
post_slack(message_slack) | ||
return { | ||
"task": { | ||
"id": task.id, | ||
"title": task.title, | ||
"description": task.description, | ||
"is_complete": True if task.completed_at else False | ||
} | ||
}, 200 | ||
|
||
|
||
@task_list_api_bp.route("/<task_id>/mark_incomplete", methods=["PATCH"]) | ||
def mark_incomplete(task_id): | ||
task = Task.query.get(task_id) | ||
|
||
if task is None: | ||
return make_response(f"{task_id} doesnt exist", 404) | ||
|
||
task.completed_at = None | ||
db.session.commit() | ||
|
||
if request.method == "PATCH": | ||
return { | ||
"task": { | ||
"id": task.id, | ||
"title": task.title, | ||
"description": task.description, | ||
"is_complete": True if task.completed_at else False | ||
} | ||
}, 200 | ||
|
||
|
||
@goals_bp.route("", methods=["GET", "POST"]) | ||
def handle_goals(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider also breaking up this GET and POST for goals into two helper functions |
||
if request.method == "GET": | ||
goals = Goal.query.all() | ||
|
||
goals_response = [] | ||
|
||
for goal in goals: | ||
print(goal.title) | ||
print(goal.id) | ||
goals_response.append({ | ||
"id": goal.id, | ||
"title": goal.title | ||
}) | ||
|
||
return jsonify(goals_response) | ||
|
||
elif request.method == "POST": | ||
|
||
request_body = request.get_json(force=True) | ||
if "title" not in request_body: | ||
return {"details": "Invalid data"}, 400 | ||
new_goal = Goal(title=request_body["title"]) | ||
|
||
db.session.add(new_goal) | ||
db.session.commit() | ||
|
||
return make_response( | ||
{ | ||
"goal": { | ||
"id": new_goal.id, | ||
"title": new_goal.title | ||
} | ||
}, 201 | ||
) | ||
|
||
|
||
@goals_bp.route("/<goal_id>", methods=["GET", "DELETE", "PUT"]) | ||
def handle_goal(goal_id): | ||
goal = Goal.query.get(goal_id) | ||
if goal is None: | ||
return make_response(f"{goal_id} doesnt exist", 404) | ||
|
||
if request.method == "GET": | ||
select_goal = { | ||
"goal": { | ||
"id": goal.id, | ||
"title": goal.title | ||
} | ||
} | ||
return jsonify(select_goal), 200 | ||
|
||
elif request.method == "DELETE": | ||
db.session.delete(goal) | ||
db.session.commit() | ||
return make_response({"details": f"Goal {goal.id} \"{goal.title}\" successfully deleted"}) | ||
|
||
elif request.method == "PUT": | ||
form_data = request.get_json() | ||
goal.title = form_data["title"] | ||
|
||
db.session.commit() | ||
|
||
return { | ||
"goal": { | ||
"id": goal.id, | ||
"title": "Updated Goal Title", | ||
} | ||
}, 200 | ||
|
||
|
||
@goals_bp.route("/<goal_id>/tasks", methods=["POST", "GET"]) | ||
def handle_goal_tasks(goal_id): | ||
goal = Goal.query.get(goal_id) | ||
if goal is None: | ||
return make_response(f"{goal_id} doesnt exist", 404) | ||
|
||
if request.method == "GET": | ||
tasks = Task.query.filter(Task.goal_id == goal_id) | ||
all_goal_tasks = [] | ||
|
||
for task in tasks: | ||
all_goal_tasks.append({ | ||
"id": task.id, | ||
"goal_id": goal.id, | ||
"title": task.title, | ||
"description": task.description, | ||
"is_complete": True if task.completed_at else False | ||
}) | ||
|
||
return make_response( | ||
{ | ||
"id": goal.id, | ||
"title": goal.title, | ||
"tasks": all_goal_tasks | ||
}, 200) | ||
|
||
elif request.method == "POST": | ||
form_data = request.get_json() | ||
task_ids = form_data['task_ids'] | ||
|
||
for id in task_ids: | ||
task = Task.query.get(id) | ||
task.goal_id = goal_id | ||
|
||
db.session.commit() | ||
|
||
return make_response( | ||
{ | ||
"id": goal.id, | ||
"task_ids": task_ids | ||
}, 200) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Generic single-database configuration. |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should go back to how you previously had it
if test_config is None: app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get( "SQLALCHEMY_DATABASE_URI") else: app.config["TESTING"] = True app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get( "SQLALCHEMY_TEST_DATABASE_URI")