-
Notifications
You must be signed in to change notification settings - Fork 71
Scissors_Gloria #73
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?
Scissors_Gloria #73
Changes from all commits
bdc7465
79280af
1f2f443
4166b81
98c7524
fd6f35a
62ecac4
827ade9
efabc3e
3630670
7ab413e
65fe2d3
661a0f9
8e41386
4eb44d4
7ea7661
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,53 @@ | ||
from flask import current_app | ||
from requests.models import parse_header_links | ||
from app import db | ||
import requests | ||
import os | ||
|
||
|
||
class Task(db.Model): | ||
task_id = db.Column(db.Integer, primary_key=True) | ||
task_id = db.Column(db.Integer, autoincrement=True, primary_key=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 serialize(self): | ||
result = { | ||
'id': self.task_id, | ||
'title': self.title, | ||
'description': self.description, | ||
'is_complete': self.completed_at != None | ||
} | ||
if self.goal_id: | ||
result['goal_id'] = self.goal_id | ||
return result | ||
|
||
# def serialize_two(self): | ||
# result = { | ||
# 'id': self.task_id, | ||
# 'goal_id': self.goal_id, | ||
# 'title': self.title, | ||
# 'description': self.description, | ||
# 'is_complete': self.completed_at != None | ||
# } | ||
# return result | ||
|
||
def notify_slack(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. Great work encapsulating this functionality in a instance method. |
||
message = f"Someone just completed the task {self.title}" | ||
url = "https://slack.com/api/chat.postMessage" | ||
params = { | ||
|
||
"channel":"task-notifications", | ||
"text": message | ||
} | ||
headers = { | ||
"Authorization": os.environ.get('SLACK_API') | ||
} | ||
r = requests.post(url, data = params, headers = headers) | ||
r.status_code | ||
|
||
|
||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,266 @@ | ||
from flask_sqlalchemy.model import camel_to_snake_case | ||
from tests.test_wave_01 import test_create_task_must_contain_description | ||
from flask import Blueprint | ||
from app import db | ||
from app.models.task import Task | ||
from app.models.goal import Goal | ||
from flask import request, Blueprint, make_response, jsonify | ||
from datetime import datetime | ||
import requests | ||
|
||
|
||
def order_by_title(task_response): | ||
return task_response["title"] | ||
|
||
goal_list_bp = Blueprint("goal_list", __name__, url_prefix = '/goals') | ||
|
||
@goal_list_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(goal.serialize()) | ||
return jsonify(goal_response) | ||
|
||
elif request.method == 'POST': | ||
request_body = request.get_json() | ||
if "title" in request_body: | ||
new_goal = Goal( | ||
title = request_body['title'] | ||
) | ||
db.session.add(new_goal) | ||
db.session.commit() | ||
return{ | ||
'goal': | ||
new_goal.serialize() | ||
},201 | ||
else: | ||
return({ | ||
"details": f'Invalid data' | ||
},400) | ||
|
||
@goal_list_bp.route('/<goal_id>', methods = ['GET','PUT', 'DELETE']) | ||
def handle_goal(goal_id): | ||
goal = Goal.query.get(goal_id) | ||
if not goal: | ||
return "", 404 | ||
|
||
if request.method == 'GET': | ||
#check expected output in test | ||
return({ | ||
'goal': | ||
goal.serialize() | ||
|
||
}) | ||
elif request.method == 'PUT': | ||
request_body = request.get_json() | ||
if 'title' in request_body: | ||
goal.title = request_body['title'] | ||
db.session.commit() | ||
return({ | ||
'goal': goal.serialize() | ||
},200) | ||
|
||
elif request.method =='DELETE': | ||
db.session.delete(goal) | ||
db.session.commit() | ||
return({ | ||
"details": f'Goal {goal_id} "{goal.title}" successfully deleted' | ||
},200) | ||
|
||
@goal_list_bp.route('/<goal_id>/tasks', methods = ['GET']) | ||
def get_tasks_for_goal(goal_id): | ||
goal = Goal.query.get(goal_id) | ||
if not goal: | ||
return "", 404 | ||
|
||
tasks = goal.tasks | ||
json_tasks = [] | ||
for task in tasks: | ||
serializeds_task = task.serialize() # dict | ||
serializeds_task['goal_id'] = int(goal_id) | ||
json_tasks.append(serializeds_task) | ||
|
||
|
||
return { | ||
"id": goal.goal_id, | ||
"title": goal.title, | ||
"tasks": json_tasks | ||
}, 200 | ||
|
||
@goal_list_bp.route('/<goal_id>/tasks', methods = ['POST']) | ||
def add_task_to_goal(goal_id): | ||
goal = Goal.query.get(goal_id) | ||
tasks = request.json | ||
tasks = tasks["task_ids"] | ||
if not goal: | ||
return "", 404 | ||
# task = db.session.query(Task.id) | ||
query = db.session.query(Task).filter(Task.task_id.in_(tasks)) | ||
|
||
results = query.all() | ||
for task in results: | ||
task.goal_id = goal.goal_id | ||
db.session.commit() | ||
|
||
return{ | ||
'id': goal.goal_id, | ||
'task_ids': tasks | ||
},200 | ||
|
||
|
||
|
||
|
||
|
||
task_list_bp = Blueprint("task_list", __name__, url_prefix='/tasks') | ||
@task_list_bp.route('', methods=['GET', 'POST']) | ||
def handle_tasks(): | ||
if request.method == 'GET': | ||
#return full list of tasks | ||
|
||
# allows access to keys - sort | ||
arg = request.args # better name | ||
if "sort" in arg: | ||
if arg['sort'] == "asc": | ||
tasks = Task.query.order_by(Task.title.asc()) | ||
elif arg['sort'] == "desc": | ||
tasks = Task.query.order_by(Task.title.desc()) | ||
else: | ||
tasks = Task.query.all() | ||
task_response = [] | ||
for task in tasks: | ||
task_response.append(task.serialize()) | ||
|
||
return jsonify(task_response) | ||
|
||
elif request.method == 'POST': | ||
request_body = request.get_json() | ||
if "title" not in request_body: | ||
return { | ||
"details": "Invalid data" | ||
}, 400 | ||
elif "description" not in request_body: | ||
return { | ||
"details": "Invalid data" | ||
}, 400 | ||
elif "completed_at" not in request_body: | ||
return { | ||
"details": "Invalid data" | ||
}, 400 | ||
Comment on lines
+139
to
+150
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 combine this in a compound conditional statement to DRY up the code:
|
||
stringify_format = "%a, %d %b %Y %H:%M:%S %Z" | ||
if request_body["completed_at"]: | ||
|
||
new_task = Task( | ||
title = request_body['title'], | ||
description = request_body['description'], | ||
completed_at = datetime.strptime(request_body["completed_at"], stringify_format) | ||
) | ||
else: | ||
new_task = Task( | ||
title = request_body['title'], | ||
description = request_body['description'], | ||
) | ||
db.session.add(new_task) | ||
db.session.commit() | ||
return{ | ||
'task':{ | ||
'id': new_task.task_id, | ||
'title': new_task.title, | ||
'description': new_task.description, | ||
'is_complete': new_task.completed_at != None | ||
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 the logic to convert completed_at to a |
||
} | ||
},201 | ||
|
||
|
||
@task_list_bp.route('/<task_id>', methods=['GET','PUT', 'DELETE']) | ||
def handle_task(task_id): # same name as parameter route | ||
task = Task.query.get(task_id) | ||
if not task: | ||
return "", 404 | ||
|
||
if request.method == 'GET': | ||
return({ | ||
'task': task.serialize() | ||
}) | ||
elif request.method == 'DELETE': | ||
db.session.delete(task) | ||
db.session.commit() | ||
return({ | ||
"details": f'Task {task_id} "{task.title}" successfully deleted' | ||
},200) | ||
|
||
|
||
elif request.method =='PUT': | ||
request_body = request.get_json() | ||
if 'title' in request_body: | ||
task.title = request_body['title'] | ||
if 'description' in request_body: | ||
task.description = request_body['description'] | ||
if 'completed_at' in request_body: | ||
task.completed = request_body['completed_at'] | ||
if 'goal_id' in request_body: | ||
task.goal_id= request_body['goal_id'] | ||
db.session.commit() | ||
return({ | ||
'task': task.serialize() | ||
},200) | ||
|
||
@task_list_bp.route('/<task_id>/mark_complete',methods = ['PATCH']) | ||
def mark_complete_task(task_id): | ||
task = Task.query.get(task_id) | ||
if not task: | ||
return "Task not found", 404 | ||
task.completed_at = datetime.utcnow() | ||
task.notify_slack() | ||
db.session.commit() | ||
return{ | ||
'task':{ | ||
'id': task.task_id, | ||
'title': task.title, | ||
'description': task.description, | ||
'is_complete': task.completed_at != None | ||
} | ||
Comment on lines
+218
to
+223
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. Notice that this code is repeated below. This is a great place to use an instance method. |
||
},200 | ||
@task_list_bp.route('/<task_id>/mark_incomplete',methods = ['PATCH']) | ||
def mark_incomplete_task(task_id): | ||
task = Task.query.get(task_id) | ||
if not task: | ||
return "Task Not Found", 404 | ||
task.completed_at = None | ||
db.session.commit() | ||
return{ | ||
'task':{ | ||
'id': task.task_id, | ||
'title': task.title, | ||
'description': task.description, | ||
'is_complete': task.completed_at != None | ||
} | ||
},200 | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"folders": [ | ||
{ | ||
"path": ".." | ||
}, | ||
{ | ||
"path": "../../api/solar-system-api" | ||
} | ||
], | ||
"settings": {} | ||
} |
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.
You're on the right track with this alternative helper instance method! What we need is to use
serialize
whengoal_id is None
(the task doesn't belong to a goal), andserialize_two
when goal_id is a truthy value (the task does belong to a goal)