-
Notifications
You must be signed in to change notification settings - Fork 127
Amethyst-PhalesaPatton- #122
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: main
Are you sure you want to change the base?
Changes from all commits
0988f2c
6f43e3b
13ee10b
a6c7cb6
aed5940
f1fcccc
e033321
7f7e2b7
ed07414
b147ba2
82fb79a
512d0e0
c411221
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 +1,274 @@ | ||
from flask import Blueprint | ||
from os import abort | ||
from app import db | ||
from app.models.task import Task | ||
from flask import Blueprint, jsonify, abort, make_response, request | ||
from sqlalchemy import asc, desc | ||
from datetime import datetime | ||
# from slack_sdk import WebClient | ||
# from slack_sdk.errors import SlackApiError | ||
import os | ||
import requests | ||
from app.models.goal import Goal | ||
import json | ||
|
||
|
||
|
||
|
||
tasks_bp = Blueprint("tasks", __name__, url_prefix="/tasks") | ||
goals_bp = Blueprint("goals", __name__, url_prefix="/goals") | ||
|
||
def validate_model(cls, model_id): | ||
try: | ||
model_id = int(model_id) | ||
except: | ||
abort(make_response({"message":f"task {model_id} invalid"}, 400)) | ||
|
||
model = cls.query.get(model_id) | ||
|
||
if not model: | ||
abort(make_response({"message":f"{cls.__name__} {model_id} not found"}, 404)) | ||
|
||
return model | ||
|
||
|
||
@tasks_bp.route("", methods=["POST"]) | ||
def create_task(): | ||
request_body = request.get_json() | ||
try: | ||
new_task = Task.from_dict(request_body) | ||
|
||
except: | ||
Comment on lines
+37
to
+40
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. Love how you implemented a def validate_request_body(request_body, keys):
for key in keys:
if not request_body.get(key):
abort(make_response({
'Invalid Data': f'missing key: {key}'
}, 400))
return True We can pass in the |
||
abort(make_response({"details": "Invalid data"}, 400)) | ||
|
||
db.session.add(new_task) | ||
db.session.commit() | ||
|
||
|
||
return make_response(jsonify({"task": new_task.to_dict()}),201) | ||
|
||
@tasks_bp.route("", methods=["GET"]) | ||
|
||
def read_all_tasks(): | ||
title_query = request.args.get("title") | ||
sort_filter = request.args.get("sort") | ||
|
||
if title_query: | ||
tasks = Task.query.filter_by(title=title_query) | ||
else: | ||
tasks = Task.query.all() | ||
|
||
if sort_filter: | ||
if sort_filter == "asc": | ||
tasks = Task.query.order_by(Task.title.asc()) | ||
elif sort_filter == "desc": | ||
tasks = Task.query.order_by(Task.title.desc()) | ||
else: | ||
tasks = Task.query.all() | ||
Comment on lines
+60
to
+66
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. Love this implementation! You did well with making the database do the heavy lifting when it came to sorting the tasks! |
||
|
||
tasks_response = [] | ||
for task in tasks: | ||
tasks_response.append(task.to_dict()) | ||
|
||
return jsonify(tasks_response) | ||
|
||
@tasks_bp.route("/<task_id>", methods=["GET"]) | ||
|
||
def read_one_task(task_id): | ||
task = validate_model(Task, task_id) | ||
if task.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. ⭐️ |
||
return {"task": task.to_dict_with_goal()} | ||
else: | ||
return {"task": task.to_dict()} | ||
|
||
@tasks_bp.route("/<task_id>", methods=["PUT"]) | ||
def update_task(task_id): | ||
task = validate_model(Task, task_id) | ||
|
||
request_body = request.get_json() | ||
|
||
task.title = request_body["title"] | ||
task.description = request_body["description"] | ||
Comment on lines
+89
to
+90
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. Right now, if a user sends a request without the keys title or description your server would crash. There's a couple of ways to handle this, you could call the |
||
|
||
db.session.commit() | ||
|
||
return {"task": task.to_dict()} | ||
|
||
@tasks_bp.route("/<task_id>", methods=["DELETE"]) | ||
def delete_task(task_id): | ||
task = validate_model(Task, task_id) | ||
|
||
|
||
db.session.delete(task) | ||
db.session.commit() | ||
|
||
return make_response({"details":f'Task {task.task_id} "{task.title}" successfully deleted'}) | ||
|
||
def slack_notification(task): | ||
token = os.environ.get("slack_token") | ||
slack_url = "https://slack.com/api/chat.postMessage" | ||
headers = {"Authorization":token} | ||
body = { | ||
"channel": "task-notifications", | ||
"text": f"Someone just completed the task {task.title}", | ||
} | ||
|
||
requests.post(slack_url, headers=headers, json=body) | ||
return | ||
Comment on lines
+106
to
+116
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. Love how you made this into a helper function! Make sure you are putting them a place that is easy to find, I typically put mine a separate folder or at the top of the file. |
||
|
||
|
||
@tasks_bp.route("/<task_id>/mark_complete", methods=["PATCH"]) | ||
def mark_task_complete(task_id): | ||
|
||
task = validate_model(Task, task_id) | ||
|
||
task.completed_at = datetime.utcnow() | ||
|
||
|
||
|
||
#use requests instead of WebClient and add bearer... add token to .env look up requests.post | ||
# client = WebClient(token=os.environ.get("slack_token")) | ||
# client.chat_postMessage(channel="C0570RZGHDL", text=f"Someone just completed the task {task.title}") | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
db.session.commit() | ||
|
||
slack_notification(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. Nice work on having your Slack post sent after the logic of marking a task complete! We don't want to send out any false positive alerts just in case our logic fails during the update! |
||
|
||
|
||
return {"task": task.to_dict()} | ||
|
||
|
||
|
||
@tasks_bp.route("/<task_id>/mark_incomplete", methods=["PATCH"]) | ||
def mark_task_incomplete(task_id): | ||
|
||
task = validate_model(Task, task_id) | ||
|
||
if task.completed_at: | ||
task.completed_at = None | ||
|
||
|
||
db.session.commit() | ||
|
||
return {"task": task.to_dict()} | ||
|
||
|
||
@goals_bp.route("", methods=["POST"]) | ||
def create_goal(): | ||
request_body = request.get_json() | ||
try: | ||
new_goal = Goal.from_dict_goals(request_body) | ||
|
||
except: | ||
abort(make_response({"details": "Invalid data"}, 400)) | ||
|
||
db.session.add(new_goal) | ||
db.session.commit() | ||
|
||
|
||
return make_response(jsonify({"goal": new_goal.to_dict_goals()}),201) | ||
|
||
@goals_bp.route("", methods=["GET"]) | ||
|
||
def read_all_goals(): | ||
title_query = request.args.get("title") | ||
sort_filter = request.args.get("sort") | ||
|
||
if title_query: | ||
goals = Goal.query.filter_by(title=title_query) | ||
else: | ||
goals = Goal.query.all() | ||
|
||
if sort_filter: | ||
if sort_filter == "asc": | ||
goals = Goal.query.order_by(Goal.title.asc()) | ||
elif sort_filter == "desc": | ||
goals = Goal.query.order_by(Goal.title.desc()) | ||
else: | ||
goals = Goal.query.all() | ||
|
||
goals_response = [] | ||
for goal in goals: | ||
goals_response.append(goal.to_dict_goals()) | ||
|
||
return jsonify(goals_response) | ||
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. 💫 |
||
|
||
@goals_bp.route("/<goal_id>", methods=["GET"]) | ||
|
||
def read_one_goal(goal_id): | ||
goal = validate_model(Goal, goal_id) | ||
return {"goal": goal.to_dict_goals()} | ||
|
||
@goals_bp.route("/<goal_id>", methods=["PUT"]) | ||
def update_goal(goal_id): | ||
goal = validate_model(Goal, goal_id) | ||
|
||
request_body = request.get_json() | ||
|
||
goal.title = request_body["title"] | ||
|
||
|
||
db.session.commit() | ||
|
||
return {"goal": goal.to_dict_goals()} | ||
|
||
@goals_bp.route("/<goal_id>", methods=["DELETE"]) | ||
def delete_goal(goal_id): | ||
goal = validate_model(Goal, goal_id) | ||
|
||
|
||
db.session.delete(goal) | ||
db.session.commit() | ||
|
||
return make_response({"details":f'Goal {goal.goal_id} "{goal.title}" successfully deleted'}) | ||
|
||
@goals_bp.route("/<goal_id>/tasks", methods=["POST"]) | ||
def create_goal_by_id(goal_id): | ||
goal = validate_model(Goal, goal_id) | ||
request_body = request.get_json() | ||
|
||
for task in request_body["task_ids"]: | ||
task = validate_model(Task, task) | ||
goal.tasks.append(task) | ||
|
||
db.session.commit() | ||
return { | ||
"id": goal.goal_id, | ||
"task_ids": request_body["task_ids"] | ||
} | ||
|
||
|
||
@goals_bp.route("/<goal_id>/tasks", methods=["GET"]) | ||
def get_all_tasks_with_id(goal_id): | ||
goal = validate_model(Goal, goal_id) | ||
|
||
# return {"goal": goal.to_dict_goals_tasks()} | ||
|
||
goals_tasks = { | ||
"id": goal.goal_id, | ||
"title": goal.title, | ||
"tasks": [] | ||
|
||
} | ||
|
||
for task in goal.tasks: | ||
goals_tasks["tasks"].append(task.to_dict_with_goal | ||
()) | ||
|
||
return jsonify(goals_tasks), 200 | ||
|
||
|
||
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. Well done on this project Phalesa, I didn't have much to comment on and that is a good thing! Keep up the good work! Really looking forward to what you create in the frontend! Please feel free to reach out if you have any questions about the feedback that I left! ✨💫🤭 |
||
|
||
|
||
|
||
|
||
|
||
|
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.
Love how you used the boolean constructor here!