Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
.vscode
.DS_Store

secrets.py

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
14 changes: 11 additions & 3 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,21 @@ def create_app(test_config=None):
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get(
"SQLALCHEMY_TEST_DATABASE_URI")

db.init_app(app)
migrate.init_app(app, db)

# Import models here for Alembic setup
from app.models.task import Task
from app.models.goal import Goal

db.init_app(app)
migrate.init_app(app, db)

# Register Blueprints here
#task
from app.routes import task_bp
app.register_blueprint(task_bp)
#goal
from app.goal_routes import goal_bp
app.register_blueprint(goal_bp)

return app


159 changes: 159 additions & 0 deletions app/goal_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
from flask import Blueprint
from app.models.goal import Goal
from app.models.task import Task
from app import db
from flask import request, Blueprint, make_response, Response, jsonify
from datetime import date
import requests
from secrets import slack_token

goal_bp = Blueprint("goals", __name__, url_prefix="/goals")

@goal_bp.route("", methods=["GET", "POST"])
def handle_tasks(): # NameError
if request.method == "GET":

goals = Goal.query.all()
goals_response = []

for goal in goals:
goals_response.append({
"id": goal.goal_id,
"title": goal.title
})
return jsonify(goals_response)


elif request.method == "POST": # CRUD CREATE
# check for request body title and description, plus ensure both are strings
request_body = request.get_json()

if "title" not in request_body:
return {
"details": "Invalid data"
}, 400

goal = Goal(
title=request_body["title"]
)

db.session.add(goal)
db.session.commit()

return {
"goal": {
"id": goal.goal_id,
"title": goal.title
}
}, 201

#get 1 goal
@goal_bp.route("/<goal_id>", methods=["GET", "PUT", "DELETE"])
def handle_goal(goal_id):
goal = Goal.query.get(goal_id)

if goal == None:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember, None is falsey:

Suggested change
if goal == None:
if not goal:

return make_response(f"Goal{goal_id} not found", 404)

if request.method == "GET":
return {
"goal": {
"id": goal.goal_id,
"title": goal.title
}
}
elif request.method == "PUT":
form_data = request.get_json()

goal.title = form_data["title"]

db.session.commit()
#past last test
return {
"goal": {
"id": goal.goal_id,
"title": "Updated Goal Title"
}
}

elif request.method == "DELETE":
db.session.delete(goal)
db.session.commit()

return {
"details": f"Goal {goal.goal_id} \"{goal.title}\" successfully deleted"
}

@goal_bp.route("/<goal__id>/mark_complete", methods=["PATCH"])
def mark_complete(goal_id):
goal = Goal.query.get(goal_id)

if goal == None:
return "",404

db.session.commit()

r = requests.post(f"https://slack.com/api/chat.postMessage?channel=goal-notifications&text=Someone just completed the goal {goal.title}", headers={"Authorization":slack_token})

return {
"goal": {
"id": goal.goal_id,
"title": "Updated Goal Title"
}
}

@goal_bp.route("/<goal_id>/mark_incomplete", methods=["PATCH"])
def mark_incomplete(goal_id):
goal = Goal.query.get(goal_id)

if goal == None:
return "",404

# goal.completed_at = None
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a minor thing but it's an industry best practice to remove commented in code before you submit a PR so is a good habit to get into. 😄


db.session.commit()

return {
"goal": {
"id": goal.goal_id,
"title": goal.title
}
}

@goal_bp.route("/<int:id>/tasks", methods=["GET", "POST"])
def tasks_and_goal(id):
if request.method == "GET":
goal = Goal.query.get(id)
if not goal:
return make_response("Goal does\'t exist", 404)
return {
"id": goal.goal_id,
"title": goal.title,
"tasks": [task.get_json() for task in goal.tasks]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List comprehension! 😄

}

elif request.method == "POST":
goal = Goal.query.get(id)
if not goal:
return make_response("Goal does\'t exist", 404)

if request.method == "POST":
task_ids = request.get_json()["task_ids"]
for task_id in task_ids:
task = Task.query.get(task_id)
if task not in goal.tasks:
goal.tasks.append(task)
response_body = {
"id" : goal.goal_id,
"task_ids" : [task.task_id for task in goal.tasks]
}
db.session.commit()
goal = Goal.query.get(id)

task_id_list = [_.task_id for _ in goal.tasks]

return make_response({
"id": goal.goal_id,
"task_ids" : task_id_list
}, 200)

3 changes: 3 additions & 0 deletions app/models/goal.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@


class Goal(db.Model):
__tablename__ = "goals"
goal_id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String)
tasks = db.relationship("Task",backref="goal", lazy=True)
34 changes: 34 additions & 0 deletions app/models/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,38 @@


class Task(db.Model):
__tablename__ = "tasks"

task_id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String)
description = db.Column(db.String)
completed_at = db.Column(db.DateTime, nullable=True) # nullable allow an empty cell

goal_id = db.Column(db.Integer,db.ForeignKey("goals.goal_id"), nullable=True)

def is_complete(self):
completed_at = self.completed_at
if completed_at == None:
is_complete = False
else:
is_complete = True
return is_complete
Comment on lines +16 to +21
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified to:

Suggested change
completed_at = self.completed_at
if completed_at == None:
is_complete = False
else:
is_complete = True
return is_complete
return self.completed_at != None


def get_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()
}


Loading