-
Notifications
You must be signed in to change notification settings - Fork 69
YuliyaP_Rock_Task_List_Api #59
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
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 |
|---|---|---|
|
|
@@ -138,4 +138,6 @@ dmypy.json | |
| .pytype/ | ||
|
|
||
| # Cython debug symbols | ||
| cython_debug/ | ||
| cython_debug/ | ||
|
|
||
| venvsource/ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,4 +3,38 @@ | |
|
|
||
|
|
||
| class Task(db.Model): | ||
| 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.String) | ||
| completed_at = db.Column(db.DateTime, nullable=True) | ||
| goal_id = db.Column(db.Integer, db.ForeignKey('goal.goal_id'), nullable=True) | ||
|
|
||
|
|
||
| def is_complete(self): | ||
| if self.completed_at is None: | ||
| is_complete = False | ||
| else: | ||
| is_complete = True | ||
| return is_complete | ||
|
|
||
| def to_json(self): | ||
| if self.goal_id: | ||
| return { | ||
| "id": self.task_id, | ||
| "goal_id": self.goal_id, | ||
| "title": self.title, | ||
| "description": self.description, | ||
| "is_complete": self.is_complete() | ||
| } | ||
| else: | ||
| return { | ||
| "id": self.task_id, | ||
| "title": self.title, | ||
| "description": self.description, | ||
| "is_complete": self.is_complete() | ||
| } | ||
|
Comment on lines
+13
to
+35
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 helper method/functions here to return a dictionary. There's a way to refactor this part of the code that I'd love to show you during our 1:1. |
||
|
|
||
| def from_json(self, input_data): | ||
| return self(title=input_data["title"], | ||
| description=input_data["description"], | ||
| completed_at=input_data["completed_at"]) | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,2 +1,269 @@ | ||||||||||||||||||||||
| from flask import Blueprint | ||||||||||||||||||||||
| from app import db | ||||||||||||||||||||||
| from .models.task import Task | ||||||||||||||||||||||
| from .models.goal import Goal | ||||||||||||||||||||||
| from flask import request, Blueprint, make_response, jsonify | ||||||||||||||||||||||
| from sqlalchemy import desc, asc | ||||||||||||||||||||||
| import datetime | ||||||||||||||||||||||
| import os | ||||||||||||||||||||||
| import requests | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| tasks_bp = Blueprint("tasks", __name__, url_prefix="/tasks") | ||||||||||||||||||||||
| goals_bp = Blueprint("goals", __name__, url_prefix="/goals") | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @tasks_bp.route("", methods=["POST", "GET"]) | ||||||||||||||||||||||
| def handle_tasks(): | ||||||||||||||||||||||
| if request.method == "GET": | ||||||||||||||||||||||
| sort_query = request.args.get("sort") | ||||||||||||||||||||||
| if sort_query == "asc": | ||||||||||||||||||||||
| tasks = Task.query.order_by(Task.title) | ||||||||||||||||||||||
| elif sort_query == "desc": | ||||||||||||||||||||||
| tasks = Task.query.order_by(Task.title.desc()) | ||||||||||||||||||||||
| else: | ||||||||||||||||||||||
| tasks = Task.query.all() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| tasks_response = [] | ||||||||||||||||||||||
| for task in tasks: | ||||||||||||||||||||||
| tasks_response.append({ | ||||||||||||||||||||||
| "id": task.task_id, | ||||||||||||||||||||||
| "title": task.title, | ||||||||||||||||||||||
| "description": task.description, | ||||||||||||||||||||||
| "is_complete": task.is_complete() | ||||||||||||||||||||||
| }) | ||||||||||||||||||||||
|
Comment on lines
+30
to
+35
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. This would have been a good spot to use the helper method in your Task model |
||||||||||||||||||||||
| return jsonify(tasks_response) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| elif request.method == "POST": | ||||||||||||||||||||||
| request_body = request.get_json() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if "title" not in request_body or "description" not in request_body\ | ||||||||||||||||||||||
| or "completed_at" not in request_body: | ||||||||||||||||||||||
| return ({ | ||||||||||||||||||||||
| "details": "Invalid data" | ||||||||||||||||||||||
| }, 400) | ||||||||||||||||||||||
| else: | ||||||||||||||||||||||
| 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 make_response({ | ||||||||||||||||||||||
| "task": { | ||||||||||||||||||||||
| "id": new_task.task_id, | ||||||||||||||||||||||
| "title": new_task.title, | ||||||||||||||||||||||
| "description": new_task.description, | ||||||||||||||||||||||
| "is_complete": new_task.is_complete() | ||||||||||||||||||||||
|
Comment on lines
+55
to
+59
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. Another good spot to use the helper method as well |
||||||||||||||||||||||
| }}, 201) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @tasks_bp.route("/<task_id>", methods=["GET", "PUT", "DELETE"]) | ||||||||||||||||||||||
| def handle_task(task_id): | ||||||||||||||||||||||
| task = Task.query.get(task_id) | ||||||||||||||||||||||
| if task is None: | ||||||||||||||||||||||
| return make_response("", 404) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if request.method == "GET": | ||||||||||||||||||||||
| if task.goal_id is None: | ||||||||||||||||||||||
| return { | ||||||||||||||||||||||
| "task": { | ||||||||||||||||||||||
| "id": task.task_id, | ||||||||||||||||||||||
| "title": task.title, | ||||||||||||||||||||||
| "description": task.description, | ||||||||||||||||||||||
| "is_complete": task.is_complete() | ||||||||||||||||||||||
| }} | ||||||||||||||||||||||
| if task.task_id: | ||||||||||||||||||||||
| return { | ||||||||||||||||||||||
| "task": { | ||||||||||||||||||||||
| "id": task.task_id, | ||||||||||||||||||||||
| "goal_id": task.goal_id, | ||||||||||||||||||||||
| "title": task.title, | ||||||||||||||||||||||
| "description": task.description, | ||||||||||||||||||||||
| "is_complete": task.is_complete() | ||||||||||||||||||||||
| }} | ||||||||||||||||||||||
| else: | ||||||||||||||||||||||
| return { | ||||||||||||||||||||||
| "task": { | ||||||||||||||||||||||
| "id": task.task_id, | ||||||||||||||||||||||
| "title": task.title, | ||||||||||||||||||||||
| "description": task.description, | ||||||||||||||||||||||
| "is_complete": task.is_complete() | ||||||||||||||||||||||
| }} | ||||||||||||||||||||||
|
Comment on lines
+87
to
+93
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. You can refactor this section to use your code block like so
Suggested change
|
||||||||||||||||||||||
| elif request.method == "PUT": | ||||||||||||||||||||||
| form_data = request.get_json() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| task.title = form_data["title"] | ||||||||||||||||||||||
| task.description = form_data["description"] | ||||||||||||||||||||||
| task.completed_at = form_data["completed_at"] | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| db.session.commit() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| headers = {"Authorization": os.environ.get("SLACK_KEY")} | ||||||||||||||||||||||
| data = { | ||||||||||||||||||||||
| "channel": "C021BV8A5V0", | ||||||||||||||||||||||
| "text": f"Someone just completed the task {task.title}" | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| requests.patch('https://slack.com/api/chat.postMessage', | ||||||||||||||||||||||
| headers=headers, data=data) | ||||||||||||||||||||||
|
Comment on lines
+103
to
+110
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 setting up the slack bot! A future refactor can include putting this code into a helper function. |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return { | ||||||||||||||||||||||
| "task": { | ||||||||||||||||||||||
| "id": task.task_id, | ||||||||||||||||||||||
| "title": task.title, | ||||||||||||||||||||||
| "description": task.description, | ||||||||||||||||||||||
| "is_complete": task.is_complete() | ||||||||||||||||||||||
| }} | ||||||||||||||||||||||
| elif request.method == "DELETE": | ||||||||||||||||||||||
| db.session.delete(task) | ||||||||||||||||||||||
| db.session.commit() | ||||||||||||||||||||||
| return { | ||||||||||||||||||||||
| "details": (f'Task {task.task_id} "{task.title}" successfully deleted') | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @tasks_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("", 404) | ||||||||||||||||||||||
|
Comment on lines
+129
to
+131
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. Flask has a method called
Suggested change
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| task.completed_at = None | ||||||||||||||||||||||
| db.session.commit() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return { | ||||||||||||||||||||||
| "task": { | ||||||||||||||||||||||
| "id": task.task_id, | ||||||||||||||||||||||
| "title": task.title, | ||||||||||||||||||||||
| "description": task.description, | ||||||||||||||||||||||
| "is_complete": False | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @tasks_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("", 404) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| task.completed_at = datetime.datetime.now() | ||||||||||||||||||||||
| db.session.commit() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return { | ||||||||||||||||||||||
| "task": { | ||||||||||||||||||||||
| "id": task.task_id, | ||||||||||||||||||||||
| "title": task.title, | ||||||||||||||||||||||
| "description": task.description, | ||||||||||||||||||||||
| "is_complete": True | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @goals_bp.route("", methods=["GET"]) | ||||||||||||||||||||||
| def get_goals(): | ||||||||||||||||||||||
| goals = Goal.query.all() | ||||||||||||||||||||||
| goals_response = [] | ||||||||||||||||||||||
| for goal in goals: | ||||||||||||||||||||||
| goals_response.append(goal.to_json()) | ||||||||||||||||||||||
| return jsonify(goals_response) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @goals_bp.route("", methods=["POST"]) | ||||||||||||||||||||||
| def post_goal(): | ||||||||||||||||||||||
| request_body = request.get_json() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| 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 ({"goal": new_goal.to_json()}, 201) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @goals_bp.route("/<goal_id>", methods=["GET"]) | ||||||||||||||||||||||
| def get_task(goal_id): | ||||||||||||||||||||||
| goal = Goal.query.get(goal_id) | ||||||||||||||||||||||
| if goal is None: | ||||||||||||||||||||||
| return make_response("", 404) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return { | ||||||||||||||||||||||
| "goal": goal.to_json() | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @goals_bp.route("/<goal_id>", methods=["PUT"]) | ||||||||||||||||||||||
| def update_task(goal_id): | ||||||||||||||||||||||
| goal = Goal.query.get(goal_id) | ||||||||||||||||||||||
| if goal is None: | ||||||||||||||||||||||
| return make_response("", 404) | ||||||||||||||||||||||
|
Comment on lines
+203
to
+205
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. See comment about |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| form_data = request.get_json() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| goal.title = form_data["title"] | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| db.session.commit() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return { | ||||||||||||||||||||||
| "goal": goal.to_json() | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @goals_bp.route("/<goal_id>", methods=["DELETE"]) | ||||||||||||||||||||||
| def delete_task(goal_id): | ||||||||||||||||||||||
| goal = Goal.query.get(goal_id) | ||||||||||||||||||||||
| if goal is None: | ||||||||||||||||||||||
| return make_response("", 404) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| db.session.delete(goal) | ||||||||||||||||||||||
| db.session.commit() | ||||||||||||||||||||||
| return { | ||||||||||||||||||||||
| "details": (f'Goal {goal.goal_id} "{goal.title}" successfully deleted') | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @goals_bp.route("/<goal_id>/tasks", methods=["GET"]) | ||||||||||||||||||||||
| def get_goals_tasks(goal_id): | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| goal = Goal.query.get(goal_id) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if goal is None: | ||||||||||||||||||||||
| return make_response("", 404) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| tasks = Task.query.filter_by(goal_id=goal.goal_id) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| tasks_response = [] | ||||||||||||||||||||||
| for task in tasks: | ||||||||||||||||||||||
| tasks_dict = task.to_json() | ||||||||||||||||||||||
| tasks_response.append(tasks_dict) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return { | ||||||||||||||||||||||
| "id": goal.goal_id, | ||||||||||||||||||||||
| "title": goal.title, | ||||||||||||||||||||||
| "tasks": tasks_response | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @goals_bp.route("/<goal_id>/tasks", methods=["POST"]) | ||||||||||||||||||||||
| def post_goals_tasks(goal_id): | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| goal = Goal.query.get(goal_id) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if goal is None: | ||||||||||||||||||||||
| return make_response("", 404) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| request_body = request.get_json() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| for task_id in request_body["task_ids"]: | ||||||||||||||||||||||
| task = Task.query.get(task_id) | ||||||||||||||||||||||
| task.goal_id = 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. good job finding all the tasks for a specific goal id! |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| db.session.commit() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return { | ||||||||||||||||||||||
| "id": goal.goal_id, | ||||||||||||||||||||||
| "task_ids": request_body["task_ids"] | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Generic single-database configuration. |
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.
Nice helper method!