-
Notifications
You must be signed in to change notification settings - Fork 128
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
Task List API - Jasmine S. #134
base: main
Are you sure you want to change the base?
Changes from all commits
51cb40d
58da86a
7cefaaf
5c0a5ce
18debd5
5d008bc
6f5b118
24b88d3
1864a82
78869fe
50afbaa
68aaafc
4d14057
6431a71
25e60bb
831be22
155b47d
18d5384
d104f96
5d0eec9
4a17547
1f04c31
a77f727
2bfd36c
ec6fc1b
3a05c13
2d41043
c8205f9
84778a5
25662a6
4f44702
0d7eaad
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 |
---|---|---|
|
@@ -3,3 +3,12 @@ | |
|
||
class Goal(db.Model): | ||
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. Excellent! |
||
goal_id = db.Column(db.Integer, primary_key=True) | ||
title = db.Column(db.String) | ||
tasks = db.relationship("Task", back_populates="goal", lazy=True) | ||
|
||
def to_dict(self): | ||
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. Yay, helper function! |
||
goal = { | ||
"id": self.goal_id, | ||
"title": self.title | ||
} | ||
return goal |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,4 +2,28 @@ | |
|
||
|
||
class Task(db.Model): | ||
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. Excellent! |
||
task_id = db.Column(db.Integer, primary_key=True) | ||
task_id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
title = db.Column(db.String) | ||
description = db.Column(db.Text) | ||
completed_at = db.Column(db.DateTime, nullable=True, default=None) | ||
goal_id = db.Column(db.Integer, db.ForeignKey('goal.goal_id'), nullable=True) | ||
goal = db.relationship("Goal", back_populates="tasks") | ||
|
||
def to_dict(self): | ||
task = { | ||
"id": self.task_id, | ||
"title": self.title, | ||
"description": self.description, | ||
"is_complete": False, | ||
} | ||
if self.completed_at is not None: | ||
task["is_complete"] = True | ||
if self.goal_id is not None: | ||
task["goal_id"] = self.goal_id | ||
return task | ||
|
||
@classmethod | ||
def from_dict(cls, task_data): | ||
new_task = Task(title=task_data["title"], | ||
description=task_data["description"]) | ||
return new_task | ||
Comment on lines
+12
to
+29
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. Yay, helper functions! |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
from flask import Blueprint, jsonify, request | ||
from sqlalchemy import desc, asc | ||
from app import db | ||
from app.models.goal import Goal | ||
|
||
|
||
goal_bp = Blueprint("goal", __name__, url_prefix="/goals") | ||
|
||
|
||
@goal_bp.route("", methods=["POST"]) | ||
def create_new_goal(): | ||
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. Excellent! |
||
request_body = request.get_json() | ||
try: | ||
new_goal = Goal( | ||
title=request_body["title"], | ||
) | ||
except KeyError: | ||
return {"details": "Invalid data"}, 400 | ||
|
||
db.session.add(new_goal) | ||
db.session.commit() | ||
|
||
return {"goal": new_goal.to_dict()}, 201 | ||
|
||
|
||
@goal_bp.route("", methods=["GET"]) | ||
def get_all_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. Excellent! |
||
sort_query = request.args.get("sort") | ||
if sort_query == "asc": | ||
goals = Goal.query.order_by(asc(Goal.title)) | ||
elif sort_query == "desc": | ||
goals = Goal.query.order_by(desc(Goal.title)) | ||
else: | ||
goals = Goal.query.all() | ||
|
||
response = [] | ||
for goal in goals: | ||
response.append(goal.to_dict()) | ||
|
||
return jsonify(response), 200 | ||
|
||
|
||
@goal_bp.route("/<goal_id>", methods=["GET"]) | ||
def get_one_goal(goal_id): | ||
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. Excellent! |
||
goal = Goal.query.get_or_404(goal_id) | ||
return {"goal": goal.to_dict()}, 200 | ||
|
||
|
||
@goal_bp.route("/<goal_id>", methods=["PUT"]) | ||
def update_one_goal(goal_id): | ||
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. Excellent! |
||
goal = Goal.query.get_or_404(goal_id) | ||
request_body = request.get_json() | ||
|
||
goal.title = request_body["title"] | ||
|
||
db.session.commit() | ||
|
||
return {"goal": goal.to_dict()}, 200 | ||
|
||
|
||
@goal_bp.route("/<goal_id>", methods=["DELETE"]) | ||
def delete_one_goal(goal_id): | ||
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. Excellent! |
||
goal = Goal.query.get_or_404(goal_id) | ||
|
||
db.session.delete(goal) | ||
db.session.commit() | ||
|
||
return {"details": (f'Goal {goal.goal_id} "{goal.title}" ' | ||
'successfully deleted')}, 200 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from flask import Blueprint, jsonify, request | ||
from app import db | ||
from app.models.goal import Goal | ||
from app.models.task import Task | ||
|
||
|
||
goal_task_bp = Blueprint("goal_task", __name__, url_prefix="/goals") | ||
|
||
|
||
@goal_task_bp.route("/<goal_id>/tasks", methods=["POST"]) | ||
def post_task_ids_to_goal(goal_id): | ||
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. Excellent! |
||
request_body = request.get_json() | ||
goal = Goal.query.get_or_404(goal_id) | ||
|
||
for id in request_body["task_ids"]: | ||
task = Task.query.get_or_404(id) | ||
task.goal = goal | ||
|
||
db.session.commit() | ||
|
||
return {"id": int(goal_id), "task_ids": request_body["task_ids"]}, 200 | ||
|
||
|
||
@goal_task_bp.route("/<goal_id>/tasks", methods=["GET"]) | ||
def get_tasks_for_goal(goal_id): | ||
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. Great job! |
||
request_body = request.get_json() | ||
goal = Goal.query.get_or_404(goal_id) | ||
|
||
response = goal.to_dict() | ||
response["tasks"] = [] | ||
for task in goal.tasks: | ||
response["tasks"].append(task.to_dict()) | ||
|
||
db.session.commit() | ||
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. Since this is a GET request and we are not making any changes to the goal or the tasks, there is no need to commit anything to the db. |
||
|
||
return jsonify(response), 200 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
from flask import Blueprint, jsonify, request | ||
from sqlalchemy import desc, asc | ||
from app import db | ||
from app.models.task import Task | ||
from datetime import datetime, timezone | ||
import requests | ||
import os | ||
|
||
|
||
task_bp = Blueprint("task", __name__, url_prefix="/tasks") | ||
|
||
|
||
@task_bp.route("", methods=["GET"]) | ||
def get_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. Excellent! |
||
sort_query = request.args.get("sort") | ||
if sort_query == "asc": | ||
tasks = Task.query.order_by(asc(Task.title)) | ||
elif sort_query == "desc": | ||
tasks = Task.query.order_by(desc(Task.title)) | ||
else: | ||
tasks = Task.query.all() | ||
|
||
response = [] | ||
for task in tasks: | ||
response.append(task.to_dict()) | ||
|
||
return jsonify(response), 200 | ||
|
||
|
||
@task_bp.route("/<task_id>", methods=["GET"]) | ||
def get_task(task_id): | ||
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. Excellent! |
||
task = Task.query.get_or_404(task_id) | ||
return {"task": task.to_dict()}, 200 | ||
|
||
|
||
@task_bp.route("", methods=["POST"]) | ||
def create_task(): | ||
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. Excellent! |
||
request_body = request.get_json() | ||
try: | ||
new_task = Task.from_dict(request_body) | ||
except KeyError: | ||
return {"details": "Invalid data"}, 400 | ||
|
||
db.session.add(new_task) | ||
db.session.commit() | ||
|
||
return {"task": new_task.to_dict()}, 201 | ||
|
||
|
||
@task_bp.route("/<task_id>", methods=["PUT"]) | ||
def update_task(task_id): | ||
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. Excellent! |
||
task = Task.query.get_or_404(task_id) | ||
request_body = request.get_json() | ||
|
||
task.title = request_body["title"] | ||
task.description = request_body["description"] | ||
|
||
db.session.commit() | ||
|
||
return {"task": task.to_dict()}, 200 | ||
|
||
|
||
@task_bp.route("/<task_id>/mark_complete", methods=["PATCH"]) | ||
def mark_complete(task_id): | ||
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. Excellent! |
||
task = Task.query.get_or_404(task_id) | ||
|
||
task.completed_at = str(datetime.now(timezone.utc)) | ||
|
||
slack_bot = requests.post('https://slack.com/api/chat.postMessage', | ||
data={ | ||
'channel': 'C05N61M2JHG', | ||
'text': f'Task "{task.title}" was marked complete!'}, | ||
headers={'Authorization': os.environ.get("SLACK_API_TOKEN")}) | ||
|
||
db.session.commit() | ||
|
||
return {"task": task.to_dict()}, 200 | ||
|
||
|
||
@task_bp.route("/<task_id>/mark_incomplete", methods=["PATCH"]) | ||
def mark_incomplete(task_id): | ||
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. Excellent! |
||
task = Task.query.get_or_404(task_id) | ||
|
||
task.completed_at = None | ||
|
||
db.session.commit() | ||
|
||
return {"task": task.to_dict()}, 200 | ||
|
||
|
||
@task_bp.route("/<task_id>", methods=["DELETE"]) | ||
def delete_task(task_id): | ||
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. Excellent! |
||
task = Task.query.get_or_404(task_id) | ||
|
||
db.session.delete(task) | ||
db.session.commit() | ||
|
||
return {"details": (f'Task {task.task_id} "{task.title}" ' | ||
'successfully deleted')}, 200 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Generic single-database configuration. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# A generic, single database configuration. | ||
|
||
[alembic] | ||
# template used to generate migration files | ||
# file_template = %%(rev)s_%%(slug)s | ||
|
||
# set to 'true' to run the environment during | ||
# the 'revision' command, regardless of autogenerate | ||
# revision_environment = false | ||
|
||
|
||
# Logging configuration | ||
[loggers] | ||
keys = root,sqlalchemy,alembic | ||
|
||
[handlers] | ||
keys = console | ||
|
||
[formatters] | ||
keys = generic | ||
|
||
[logger_root] | ||
level = WARN | ||
handlers = console | ||
qualname = | ||
|
||
[logger_sqlalchemy] | ||
level = WARN | ||
handlers = | ||
qualname = sqlalchemy.engine | ||
|
||
[logger_alembic] | ||
level = INFO | ||
handlers = | ||
qualname = alembic | ||
|
||
[handler_console] | ||
class = StreamHandler | ||
args = (sys.stderr,) | ||
level = NOTSET | ||
formatter = generic | ||
|
||
[formatter_generic] | ||
format = %(levelname)-5.5s [%(name)s] %(message)s | ||
datefmt = %H:%M:%S |
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.
Excellent!