-
Notifications
You must be signed in to change notification settings - Fork 71
Lin - Rocks! #63
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?
Lin - Rocks! #63
Changes from all commits
59ba3dc
434d450
a642146
21049ca
eddd265
a5c93fe
c5c5ea4
5d10d1f
353a7d8
7b6b8c8
4f7f4ac
f091fba
afdc0be
b353a90
b2cf8e1
5e11913
23788ea
78c4837
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,37 @@ | ||||
from flask import current_app | ||||
from app import db | ||||
from flask import current_app | ||||
from sqlalchemy import DateTime | ||||
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. since we are already importing db, we don't need to import DateTime separately. It already comes in db, like
Suggested change
|
||||
|
||||
|
||||
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) | ||||
|
||||
# lowercase 'goal.id' looks at a table in your db | ||||
goal_id = db.Column(db.Integer, db.ForeignKey( | ||||
'goal.goal_id'), nullable=True) | ||||
|
||||
def is_complete(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. 👍 |
||||
if self.completed_at: | ||||
return True | ||||
else: | ||||
return False | ||||
|
||||
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. 👍 |
||||
return { | ||||
"id": self.task_id, | ||||
"title": self.title, | ||||
"description": self.description, | ||||
"is_complete": self.is_complete() | ||||
} | ||||
|
||||
def with_goal(self): | ||||
return { | ||||
"id": self.task_id, | ||||
"title": self.title, | ||||
"description": self.description, | ||||
"is_complete": self.is_complete(), | ||||
"goal_id": self.goal_id | ||||
} | ||||
Comment on lines
+30
to
+37
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 an if statement to combine |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -1,2 +1,217 @@ | ||||||||||
from flask import Blueprint | ||||||||||
from app import db | ||||||||||
from app.models.task import Task | ||||||||||
from datetime import datetime | ||||||||||
from flask import request, Blueprint, make_response, jsonify | ||||||||||
import requests | ||||||||||
import os | ||||||||||
# from slack_sdk import WebClient | ||||||||||
# from slack_sdk.errors import SlackApiError | ||||||||||
Comment on lines
+7
to
+8
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. since you aren't using these imports, remember to delete them from the final submission
Suggested change
|
||||||||||
from app.models.goal import Goal | ||||||||||
|
||||||||||
|
||||||||||
goals_bp = Blueprint( | ||||||||||
"goals", __name__, url_prefix="/goals") | ||||||||||
tasks_bp = Blueprint( | ||||||||||
"tasks", __name__, url_prefix="/tasks") | ||||||||||
|
||||||||||
|
||||||||||
# ------------------------- | ||||||||||
# WAVE 1 - TASK ENDPOINTS | ||||||||||
# ------------------------- | ||||||||||
@tasks_bp.route("", methods=["POST"], strict_slashes=False) | ||||||||||
def create_task(): | ||||||||||
request_body = request.get_json() | ||||||||||
if "title" in request_body and "description" in request_body and "completed_at" in request_body: | ||||||||||
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 jsonify({"task": new_task.to_json()}), 201 | ||||||||||
else: | ||||||||||
return make_response({"details": "Invalid data"}, 400) | ||||||||||
|
||||||||||
|
||||||||||
# WAVE 2 | ||||||||||
@tasks_bp.route("", methods=["GET"], strict_slashes=False) | ||||||||||
def task_index(): | ||||||||||
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 = [(task.to_json()) for task in tasks] | ||||||||||
return make_response(jsonify(tasks_response), 200) | ||||||||||
|
||||||||||
|
||||||||||
# WAVE 1 | ||||||||||
@tasks_bp.route("/<task_id>", methods=["GET"], strict_slashes=False) | ||||||||||
def get_one_task(task_id): | ||||||||||
task = Task.query.get(task_id) | ||||||||||
if task is None: | ||||||||||
return make_response("", 404) | ||||||||||
Comment on lines
+54
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 shorten this by using
Suggested change
|
||||||||||
# thank you audrey! | ||||||||||
elif task.goal_id is None: | ||||||||||
return jsonify({"task": task.to_json()}), 200 | ||||||||||
else: | ||||||||||
return jsonify({"task": task.with_goal()}), 200 | ||||||||||
Comment on lines
+58
to
+61
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. if we combined your two helper methods in Task, we could combine these lines into one return statement |
||||||||||
|
||||||||||
|
||||||||||
@tasks_bp.route("/<task_id>", methods=["PUT"], strict_slashes=False) | ||||||||||
def update_task(task_id): | ||||||||||
task = Task.query.get(task_id) | ||||||||||
if task is None: | ||||||||||
return make_response("", 404) | ||||||||||
Comment on lines
+66
to
+68
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 use |
||||||||||
else: | ||||||||||
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() | ||||||||||
return jsonify({"task": task.to_json()}), 200 | ||||||||||
|
||||||||||
|
||||||||||
@tasks_bp.route("/<task_id>", methods=["DELETE"], strict_slashes=False) | ||||||||||
def delete_task(task_id): | ||||||||||
task = Task.query.get(task_id) | ||||||||||
if task is None: | ||||||||||
return make_response("", 404) | ||||||||||
else: | ||||||||||
db.session.delete(task) | ||||||||||
db.session.commit() | ||||||||||
task_response = { | ||||||||||
"details": f'Task {task.task_id} "{task.title}" successfully deleted'} | ||||||||||
return make_response(task_response), 200 | ||||||||||
|
||||||||||
|
||||||||||
# WAVE 3 | ||||||||||
@tasks_bp.route("/<task_id>/mark_incomplete", methods=["PATCH"], strict_slashes=False) | ||||||||||
def handle_incomplete(task_id): | ||||||||||
task = Task.query.get(task_id) | ||||||||||
if task is None: | ||||||||||
return make_response("", 404) | ||||||||||
Comment on lines
+94
to
+96
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 use |
||||||||||
else: | ||||||||||
task.completed_at = None | ||||||||||
db.session.commit() | ||||||||||
return jsonify({"task": task.to_json()}), 200 | ||||||||||
|
||||||||||
|
||||||||||
@tasks_bp.route("/<task_id>/mark_complete", methods=["PATCH"], strict_slashes=False) | ||||||||||
def handle_complete(task_id): | ||||||||||
task = Task.query.get(task_id) | ||||||||||
if task is None: | ||||||||||
return make_response("", 404) | ||||||||||
Comment on lines
+105
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. here we could use |
||||||||||
else: | ||||||||||
task.completed_at = datetime.now() | ||||||||||
db.session.commit() | ||||||||||
call_slack_api(task) | ||||||||||
return jsonify({"task": task.to_json()}), 200 | ||||||||||
|
||||||||||
|
||||||||||
# WAVE 4 | ||||||||||
def call_slack_api(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. :+1 great job turning this into a helper function |
||||||||||
SLACK_TOKEN = os.environ.get("SLACK_BOT_TOKEN") | ||||||||||
url = "https://slack.com/api/chat.postMessage" | ||||||||||
payload = { | ||||||||||
"channel": "task-notifications", | ||||||||||
"text": f"Someone just completed the task {task.title}"} | ||||||||||
headers = { | ||||||||||
"Authorization": f"Bearer {SLACK_TOKEN}", | ||||||||||
} | ||||||||||
return requests.request("POST", url, headers=headers, data=payload) | ||||||||||
|
||||||||||
# IGNORE - WORKS BUT USES SLACK BOLT/PYTHON SDK (from slack API docs) instead of requests.package | ||||||||||
# def call_slack_api(task): | ||||||||||
# client = WebClient(token=os.environ.get("SLACK_BOT_TOKEN")) | ||||||||||
# channel_id = "task-notifications" | ||||||||||
# # try: | ||||||||||
# result = client.chat_postMessage( | ||||||||||
# channel=channel_id, | ||||||||||
# text=f"Someone just completed the task {task.title}") | ||||||||||
# return result | ||||||||||
Comment on lines
+127
to
+135
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 found an alternate way to send a Slack message! Remember, though, if it's unused code you should get rid of it before final submission |
||||||||||
|
||||||||||
|
||||||||||
# ------------------------- | ||||||||||
# WAVE 5 - GOAL ENDPOINTS | ||||||||||
# ------------------------- | ||||||||||
@goals_bp.route("", methods=["POST"], strict_slashes=False) | ||||||||||
def create_goal(): | ||||||||||
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 jsonify({"goal": new_goal.to_dict()}), 201 | ||||||||||
return make_response({"details": "Invalid data"}, 400) | ||||||||||
|
||||||||||
|
||||||||||
@goals_bp.route("", methods=["GET"], strict_slashes=False) | ||||||||||
def goal_index(): | ||||||||||
goals = Goal.query.all() | ||||||||||
goals_response = [(goal.to_dict()) for goal in goals] | ||||||||||
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 list comprehension |
||||||||||
return make_response(jsonify(goals_response), 200) | ||||||||||
|
||||||||||
|
||||||||||
@goals_bp.route("/<goal_id>", methods=["GET"], strict_slashes=False) | ||||||||||
def get_one_goal(goal_id): | ||||||||||
goal = Goal.query.get(goal_id) | ||||||||||
if goal is None: | ||||||||||
return make_response("", 404) | ||||||||||
Comment on lines
+162
to
+164
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 use |
||||||||||
return jsonify({"goal": goal.to_dict()}), 200 | ||||||||||
|
||||||||||
|
||||||||||
@goals_bp.route("/<goal_id>", methods=["PUT"], strict_slashes=False) | ||||||||||
def update_goal(goal_id): | ||||||||||
goal = Goal.query.get(goal_id) | ||||||||||
if goal is None: | ||||||||||
return make_response("", 404) | ||||||||||
Comment on lines
+170
to
+172
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 use |
||||||||||
else: | ||||||||||
form_data = request.get_json() | ||||||||||
goal.title = form_data["title"] | ||||||||||
db.session.commit() | ||||||||||
return jsonify({"goal": goal.to_dict()}), 200 | ||||||||||
|
||||||||||
|
||||||||||
@goals_bp.route("/<goal_id>", methods=["DELETE"], strict_slashes=False) | ||||||||||
def delete_goal(goal_id): | ||||||||||
goal = Goal.query.get(goal_id) | ||||||||||
if goal is None: | ||||||||||
return make_response("", 404) | ||||||||||
Comment on lines
+182
to
+184
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 use |
||||||||||
else: | ||||||||||
db.session.delete(goal) | ||||||||||
db.session.commit() | ||||||||||
goal_response = { | ||||||||||
"details": f'Goal {goal.goal_id} "{goal.title}" successfully deleted'} | ||||||||||
return make_response(goal_response), 200 | ||||||||||
|
||||||||||
|
||||||||||
# WAVE 6 | ||||||||||
@goals_bp.route("/<goal_id>/tasks", methods=["POST"], strict_slashes=False) | ||||||||||
def sending_list_tasks_to_goal(goal_id): | ||||||||||
request_body = request.get_json() | ||||||||||
tasks = request_body["task_ids"] | ||||||||||
# (db) | ||||||||||
goal = Goal.query.get(goal_id) | ||||||||||
for task_id in tasks: | ||||||||||
task_db_object = Task.query.get(task_id) | ||||||||||
goal.tasks.append(task_db_object) | ||||||||||
# task_db_object.goal_id = int(goal_id) | ||||||||||
db.session.commit() | ||||||||||
return {"id": goal.goal_id, | ||||||||||
"task_ids": tasks}, 200 | ||||||||||
|
||||||||||
|
||||||||||
@goals_bp.route("/<goal_id>/tasks", methods=["GET"], strict_slashes=False) | ||||||||||
def getting_tasks_of_one_goal(goal_id): | ||||||||||
goal = Goal.query.get(goal_id) | ||||||||||
if goal is None: | ||||||||||
return make_response("", 404) | ||||||||||
Comment on lines
+211
to
+213
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 use |
||||||||||
tasks = Task.query.join(Goal).filter(Task.goal_id == goal_id).all() | ||||||||||
# tasks_response = [] | ||||||||||
tasks_response = [(task.with_goal()) for task in tasks] | ||||||||||
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.
👍 yay helper method!!