-
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
Scissors- Marisa M #70
base: master
Are you sure you want to change the base?
Changes from all commits
73dee56
11be115
f2bce91
e4bd23e
e5573a1
a3ad899
40c8eac
89c64c1
f2699a1
691b557
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 |
---|---|---|
@@ -0,0 +1 @@ | ||
web: gunicorn 'app:create_app()' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,28 @@ | ||
from flask import current_app | ||
from app import db | ||
|
||
|
||
class Goal(db.Model): | ||
goal_id = db.Column(db.Integer, primary_key=True) | ||
title = db.Column(db.String) | ||
tasks = db.relationship("Task", backref="goal", lazy=True) | ||
|
||
def create_response(self): | ||
return{ | ||
"id": self.goal_id, | ||
"title": self.title, | ||
} | ||
|
||
def return_tasks(self): | ||
return { | ||
"id": self.goal_id, | ||
"task_ids": self.tasks | ||
} | ||
def return_goal_tasks(self): | ||
tasks_list = [] | ||
for task in self.tasks: | ||
tasks_list.append(task.make_json()) | ||
return{ | ||
"id": self.goal_id, | ||
"title": self.title, | ||
"tasks": tasks_list | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,30 @@ | ||
from flask import current_app | ||
from app import db | ||
|
||
|
||
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): | ||
return self.completed_at != None | ||
|
||
|
||
def make_json(self): | ||
if self.goal_id == None: | ||
return { | ||
"id": self.task_id, | ||
"title": self.title, | ||
"description": self.description, | ||
"is_complete": self.is_complete() | ||
} | ||
else: | ||
return { | ||
"id": self.task_id, | ||
"goal_id": self.goal_id, | ||
"title": self.title, | ||
"description": self.description, | ||
"is_complete": self.is_complete() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,184 @@ | ||
from flask import Blueprint | ||
from werkzeug.wrappers import ETagRequestMixin | ||
from app.models.goal import Goal | ||
from flask import Blueprint, request, make_response, jsonify | ||
from app import db | ||
from app.models.task import Task | ||
from sqlalchemy import asc, desc | ||
from datetime import datetime | ||
import requests | ||
import os | ||
|
||
tasks_bp = Blueprint("tasks", __name__, url_prefix="/tasks") | ||
|
||
@tasks_bp.route("", methods=["GET","POST"]) | ||
def handle_tasks(): | ||
if request.method == "GET": | ||
sort = request.args.get("sort") | ||
|
||
if sort == "asc": | ||
tasks = Task.query.order_by(asc("title")) | ||
|
||
elif sort == "desc": | ||
tasks = Task.query.order_by(desc("title")) | ||
|
||
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
+33
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 use the task instance method here |
||
}) | ||
return jsonify(tasks_response) | ||
|
||
elif request.method == "POST": | ||
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. With regards to the point in separating out the functions for each route (that you noted in Learn), this way of organizing your code can increase readability by reducing indentation and making meaningful function names. For instance, if we separate out GET and POST, we might call one function |
||
request_body = request.get_json() | ||
|
||
if "title" not in request_body.keys() or "description" not in request_body.keys() or "completed_at" not in request_body.keys(): | ||
return make_response({"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": new_task.make_json()}, 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) | ||
Comment on lines
+53
to
+56
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 use |
||
|
||
elif request.method == "GET": | ||
return make_response({"task": task.make_json()}) | ||
|
||
elif request.method == "PUT": | ||
request_body = request.get_json() | ||
|
||
task.title = request_body["title"] | ||
task.description = request_body["description"] | ||
task.completed_at = request_body["completed_at"] | ||
|
||
db.session.commit() | ||
|
||
return make_response({"task": task.make_json()}) | ||
|
||
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_complete", methods= ["PATCH"]) | ||
def mark_complete(task_id): | ||
task = Task.query.get(task_id) | ||
|
||
if task == None: | ||
return make_response("", 404) | ||
|
||
API_KEY = os.environ.get("API_KEY") | ||
PATH = "https://slack.com/api/chat.postMessage" | ||
query_params = { | ||
"channel": "task-notifications", | ||
"text": f"Someone just completed the task {task.title}." | ||
} | ||
task.completed_at = datetime.utcnow() | ||
db.session.commit() | ||
requests.post(PATH, data=query_params, headers={"Authorization":API_KEY}) | ||
Comment on lines
+87
to
+95
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 moving this functionality into a helper function increase readability and changeability. |
||
return make_response({"task": task.make_json()}) | ||
|
||
@tasks_bp.route("/<task_id>/mark_incomplete", methods= ["PATCH"]) | ||
def mark_incomplete(task_id): | ||
task = Task.query.get(task_id) | ||
|
||
if task == None: | ||
return make_response("", 404) | ||
|
||
task.completed_at = None | ||
db.session.commit() | ||
return make_response({"task": task.make_json()}) | ||
|
||
goals_bp = Blueprint("goals", __name__, url_prefix="/goals") | ||
|
||
@goals_bp.route("", methods=["GET","POST"]) | ||
def handle_goals(): | ||
if request.method == "GET": | ||
goals = Goal.query.all() | ||
|
||
goal_response = [] | ||
for goal in goals: | ||
goal_response.append({ | ||
"id": goal.goal_id, | ||
"title": goal.title, | ||
}) | ||
return jsonify(goal_response) | ||
|
||
elif request.method == "POST": | ||
request_body = request.get_json() | ||
|
||
if "title" not in request_body.keys(): | ||
return make_response({"details": "Invalid data"}, 400) | ||
|
||
else: | ||
new_goal = Goal(title=request_body["title"]) | ||
|
||
db.session.add(new_goal) | ||
db.session.commit() | ||
|
||
return make_response({"goal": new_goal.create_response()}, 201) | ||
|
||
@goals_bp.route("/<goal_id>", methods=["GET", "PUT", "DELETE"]) | ||
def handle_goal(goal_id): | ||
goal = Goal.query.get(goal_id) | ||
|
||
if goal == None: | ||
return make_response("", 404) | ||
|
||
elif request.method == "GET": | ||
return make_response({"goal": goal.create_response()}) | ||
|
||
elif request.method == "PUT": | ||
request_body = request.get_json() | ||
|
||
goal.title = request_body["title"] | ||
|
||
db.session.commit() | ||
|
||
return make_response({"goal": goal.create_response()}) | ||
|
||
elif request.method == "DELETE": | ||
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", "POST"]) | ||
def handle_goal_tasks(goal_id): | ||
goal = Goal.query.get(goal_id) | ||
|
||
if goal == None: | ||
return make_response("", 404) | ||
|
||
elif request.method == "GET": | ||
return make_response(goal.return_goal_tasks()) | ||
|
||
elif request.method == "POST": | ||
request_body = request.get_json() | ||
task_ids = request_body["task_ids"] | ||
|
||
for id in task_ids: | ||
task = Task.query.get(id) | ||
task.goal_id = goal.goal_id | ||
|
||
db.session.commit() | ||
|
||
return make_response({"id": goal.goal_id, "task_ids": task_ids}) |
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.
Good use of a helper method. Consider DRYing up your code by building the dictionary
and conditionally adding the
goal_id
like this:and then returning
{"task": json}