-
Notifications
You must be signed in to change notification settings - Fork 71
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
Rock - Abigail C #51
base: master
Are you sure you want to change the base?
Rock - Abigail C #51
Changes from all commits
01624ad
7e50740
1b60f35
9d781be
27b5296
1e13696
41c738c
1ba97ef
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,6 +1,18 @@ | ||
from flask import current_app | ||
from sqlalchemy.orm import backref | ||
from app import db | ||
|
||
|
||
class Goal(db.Model): | ||
goal_id = db.Column(db.Integer, primary_key=True) | ||
__tablename__ = 'goal' | ||
goal_id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
title = db.Column(db.String) | ||
tasks = db.relationship('Task', backref='goal', lazy=True) | ||
|
||
def to_json_goal(self): | ||
# This method was created so that we do not have to write out the dictionary many times in the routes.py file. | ||
return { | ||
"id": self.goal_id, | ||
"title": self.title, | ||
} | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,6 +1,39 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
from flask import current_app | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
from app import db | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
import datetime | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
class Task(db.Model): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
task_id = db.Column(db.Integer, primary_key=True) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
__tablename__ = 'task' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
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) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+7
to
+12
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. 👍 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
def to_json(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. 👍 glad you put all your logic in the helper method instead of in the route! |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
if self.completed_at != None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
result = self.completed_at | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
result = True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
elif self.completed_at == None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
result = self.completed_at | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
result = False | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
# This method was created so that we do not have to write out the dictionary many times in the routes.py file. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
if self.goal_id == None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"id": self.task_id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"title": self.title, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"description": self.description, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"is_complete": result | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"id": self.task_id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"title": self.title, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"description": self.description, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"is_complete": result, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
"goal_id": self.goal_id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+24
to
+39
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. one thing we could do to shorten this is create the data structure first, then change out the key-value pair you need to.
Suggested change
|
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,2 +1,202 @@ | ||||||||||||
from flask import Blueprint | ||||||||||||
from werkzeug.datastructures import Authorization | ||||||||||||
from app import db | ||||||||||||
from app.models.task import Task | ||||||||||||
from flask import Blueprint, request, jsonify, make_response | ||||||||||||
from datetime import datetime | ||||||||||||
import os | ||||||||||||
import requests | ||||||||||||
|
||||||||||||
tasks_bp = Blueprint("tasks", __name__, url_prefix="/tasks") | ||||||||||||
|
||||||||||||
@tasks_bp.route("/<task_id>", methods=["GET","PUT", "DELETE"]) | ||||||||||||
def get_single_task(task_id): | ||||||||||||
|
||||||||||||
task = Task.query.get(task_id) | ||||||||||||
# With the GET, POST and DELETE request if there is nothing we output this | ||||||||||||
if request == None or task == None: | ||||||||||||
return jsonify(None), 404 | ||||||||||||
Comment on lines
+14
to
+17
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 works great! One thing we could do to shorten this is:
Suggested change
this will do your 404 check for you! |
||||||||||||
# This portion is the GET request for only one task | ||||||||||||
elif request.method == "GET": | ||||||||||||
return {"task": task.to_json()}, 200 | ||||||||||||
elif request.method == "PUT": | ||||||||||||
# This portion is the PUT request for only one task | ||||||||||||
request_body = request.get_json() | ||||||||||||
task.title = request_body["title"] | ||||||||||||
task.description = request_body["description"] | ||||||||||||
db.session.commit() | ||||||||||||
return {"task": task.to_json()}, 200 | ||||||||||||
elif request.method == "DELETE": | ||||||||||||
db.session.delete(task) | ||||||||||||
db.session.commit() | ||||||||||||
return { | ||||||||||||
"details": f"Task {task.task_id} \"{task.title}\" successfully deleted" | ||||||||||||
}, 200 | ||||||||||||
|
||||||||||||
@tasks_bp.route("", methods=["GET"]) | ||||||||||||
def tasks_index(): | ||||||||||||
|
||||||||||||
query_sorted = request.args.get("sort") | ||||||||||||
if query_sorted == "asc": | ||||||||||||
# Found in SQLALchemy documentation. | ||||||||||||
# The order_by method takes the data in the user table (Task) | ||||||||||||
# and filters by title in ascending order | ||||||||||||
tasks = Task.query.order_by(Task.title.asc()) | ||||||||||||
elif query_sorted == "desc": | ||||||||||||
# Found in SQLALchemy documentation. | ||||||||||||
# The order_by method takes the data in the user table (Task) | ||||||||||||
# and filters by title in descending order | ||||||||||||
tasks = Task.query.order_by(Task.title.desc()) | ||||||||||||
else: | ||||||||||||
tasks = Task.query.all() | ||||||||||||
# This portion is just a GET request | ||||||||||||
if tasks == None: | ||||||||||||
return [] | ||||||||||||
Comment on lines
+50
to
+53
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 check, but |
||||||||||||
else: | ||||||||||||
tasks_response = [] | ||||||||||||
for task in tasks: | ||||||||||||
tasks_response.append(task.to_json()) | ||||||||||||
return jsonify(tasks_response), 200 | ||||||||||||
|
||||||||||||
|
||||||||||||
@tasks_bp.route("", methods=["POST"]) | ||||||||||||
def tasks(): | ||||||||||||
try: | ||||||||||||
# This portion is the POST request | ||||||||||||
request_body = request.get_json() | ||||||||||||
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": new_task.to_json()}, 201 | ||||||||||||
except KeyError: | ||||||||||||
return { | ||||||||||||
"details": "Invalid data"}, 400 | ||||||||||||
Comment on lines
+74
to
+76
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 error checking |
||||||||||||
|
||||||||||||
@tasks_bp.route("/<task_id>/mark_complete", methods=["PATCH"]) | ||||||||||||
def mark_complete(task_id): | ||||||||||||
patch_task = Task.query.get(task_id) | ||||||||||||
date = datetime.utcnow() | ||||||||||||
if patch_task == None: | ||||||||||||
return jsonify(None), 404 | ||||||||||||
Comment on lines
+80
to
+83
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. we could also use the |
||||||||||||
# Mark Complete on an Incompleted Task | ||||||||||||
patch_task.completed_at = date | ||||||||||||
bot_notification(patch_task) | ||||||||||||
db.session.commit() | ||||||||||||
|
||||||||||||
return {"task":patch_task.to_json()}, 200 | ||||||||||||
|
||||||||||||
|
||||||||||||
def bot_notification(patch_task): | ||||||||||||
PATH = "https://slack.com/api/chat.postMessage" | ||||||||||||
API_TOKEN = os.environ.get("API_KEY") | ||||||||||||
|
||||||||||||
query_params = { | ||||||||||||
"channel": "task-notifications", | ||||||||||||
"text": f"Someone just completed the task {patch_task.title}" | ||||||||||||
} | ||||||||||||
|
||||||||||||
header = { | ||||||||||||
"Authorization": f"Bearer {API_TOKEN}" | ||||||||||||
|
||||||||||||
} | ||||||||||||
result = requests.get(PATH, params=query_params,headers=header) | ||||||||||||
|
||||||||||||
return result | ||||||||||||
Comment on lines
+92
to
+107
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. 👍 glad you turned this into a helper function! |
||||||||||||
|
||||||||||||
@tasks_bp.route("/<task_id>/mark_incomplete", methods=["PATCH"]) | ||||||||||||
def mark_incomplete(task_id): | ||||||||||||
patch_task = Task.query.get(task_id) | ||||||||||||
if patch_task == None: | ||||||||||||
return jsonify(None), 404 | ||||||||||||
Comment on lines
+111
to
+113
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. here we could also use the |
||||||||||||
patch_task.completed_at = None | ||||||||||||
db.session.commit() | ||||||||||||
|
||||||||||||
return {"task":patch_task.to_json()}, 200 | ||||||||||||
|
||||||||||||
|
||||||||||||
# ============================Goals========================================= | ||||||||||||
|
||||||||||||
from app.models.goal import Goal | ||||||||||||
from flask import Blueprint, request, jsonify | ||||||||||||
|
||||||||||||
goals_bp = Blueprint("goals", __name__, url_prefix="/goals") | ||||||||||||
Comment on lines
+122
to
+125
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. we could add Goal import to the top. also, we've already imported Blueprint, request, and jsonify, so we don't need to do it again. |
||||||||||||
|
||||||||||||
@goals_bp.route("",methods=["POST"]) | ||||||||||||
def create_goal(): | ||||||||||||
try: | ||||||||||||
# This portion is the POST request | ||||||||||||
request_body = request.get_json() | ||||||||||||
new_goal = Goal(title=request_body["title"]) | ||||||||||||
|
||||||||||||
db.session.add(new_goal) | ||||||||||||
db.session.commit() | ||||||||||||
return {"goal": new_goal.to_json_goal()}, 201 | ||||||||||||
except KeyError: | ||||||||||||
return { | ||||||||||||
"details": "Invalid data"}, 400 | ||||||||||||
Comment on lines
+129
to
+139
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. cool! good job experimenting with a try-except statement |
||||||||||||
@goals_bp.route("", methods=["GET"]) | ||||||||||||
def goals_index(): | ||||||||||||
# This portion is the just a GET request | ||||||||||||
goals = Goal.query.all() | ||||||||||||
if goals == None: | ||||||||||||
return [] | ||||||||||||
Comment on lines
+143
to
+145
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. we can let |
||||||||||||
else: | ||||||||||||
goals_response = [] | ||||||||||||
for goal in goals: | ||||||||||||
goals_response.append(goal.to_json_goal()) | ||||||||||||
return jsonify(goals_response), 200 | ||||||||||||
|
||||||||||||
@goals_bp.route("/<goal_id>", methods=["GET","PUT", "DELETE"]) | ||||||||||||
def get_single_goal(goal_id): | ||||||||||||
|
||||||||||||
goal = Goal.query.get(goal_id) | ||||||||||||
# With the GET, POST and DELETE request if there is nothing we output this | ||||||||||||
if request == None or goal == None: | ||||||||||||
return jsonify(None), 404 | ||||||||||||
Comment on lines
+155
to
+158
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. we could also use the |
||||||||||||
# This portion is the GET request for only one goal | ||||||||||||
elif request.method == "GET": | ||||||||||||
return {"goal": goal.to_json_goal()}, 200 | ||||||||||||
elif request.method == "PUT": | ||||||||||||
# This portion is the PUT request for only one goal | ||||||||||||
request_body = request.get_json() | ||||||||||||
goal.title = request_body["title"] | ||||||||||||
db.session.commit() | ||||||||||||
return {"goal": goal.to_json_goal()}, 200 | ||||||||||||
elif request.method == "DELETE": | ||||||||||||
db.session.delete(goal) | ||||||||||||
db.session.commit() | ||||||||||||
return { | ||||||||||||
"details": f"Goal {goal.goal_id} \"{goal.title}\" successfully deleted" | ||||||||||||
}, 200 | ||||||||||||
|
||||||||||||
|
||||||||||||
# # ===============Establishing One to Many Realtionship================================= | ||||||||||||
|
||||||||||||
|
||||||||||||
@goals_bp.route("<goal_id>/tasks", methods=["POST"]) | ||||||||||||
def post_tasks_ids_to_goal(goal_id): | ||||||||||||
goal = Goal.query.get(goal_id) | ||||||||||||
request_body = request.get_json() | ||||||||||||
|
||||||||||||
for task_id in request_body["task_ids"]: | ||||||||||||
task = Task.query.get(task_id) | ||||||||||||
goal.tasks.append(task) | ||||||||||||
db.session.commit() | ||||||||||||
return make_response({"id": goal.goal_id, "task_ids": request_body["task_ids"]}, 200) | ||||||||||||
|
||||||||||||
@goals_bp.route("<goal_id>/tasks", methods=["GET"]) | ||||||||||||
def getting_tasks_of_one_goal(goal_id): | ||||||||||||
goal = Goal.query.get(goal_id) | ||||||||||||
if goal == None: | ||||||||||||
return jsonify(None), 404 | ||||||||||||
Comment on lines
+192
to
+194
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. we could also use the |
||||||||||||
else: | ||||||||||||
tasks_from_goal = goal.tasks | ||||||||||||
|
||||||||||||
tasks_response = [] | ||||||||||||
for task in tasks_from_goal: | ||||||||||||
tasks_response.append(task.to_json()) | ||||||||||||
|
||||||||||||
return {"id":goal.goal_id,"title": goal.title, "tasks": tasks_response}, 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.
👍 nice helper method