-
Notifications
You must be signed in to change notification settings - Fork 124
Kunzite - Aisha M. #106
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: main
Are you sure you want to change the base?
Kunzite - Aisha M. #106
Changes from all commits
5106489
eab781d
eb21778
4989274
3147193
0c0cb35
1915780
448ee87
9a752c9
f448dc2
3ceee95
652d0d4
1ef265e
693a39f
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,5 +1,14 @@ | ||
| from app import db | ||
|
|
||
|
|
||
| class Goal(db.Model): | ||
| goal_id = db.Column(db.Integer, primary_key=True) | ||
| id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
| title = db.Column(db.String, nullable=False) | ||
| tasks = db.relationship("Task", back_populates="goal", lazy=True) | ||
|
|
||
| def to_dict(self): | ||
| return (dict( | ||
| id=self.id, | ||
| title=self.title | ||
| )) | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,37 @@ | ||
| from app import db | ||
|
|
||
|
|
||
| class Task(db.Model): | ||
| task_id = db.Column(db.Integer, primary_key=True) | ||
| id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
| title = db.Column(db.String, nullable=False) | ||
| description = db.Column(db.String, nullable=False) | ||
| completed_at = db.Column(db.DateTime, nullable=True) | ||
| goal = db.relationship("Goal", back_populates="tasks") | ||
| goal_id = db.Column(db.Integer, db.ForeignKey("goal.id")) | ||
|
|
||
| def to_dict_with_goal(self): | ||
| if not self.completed_at: | ||
| self.is_complete = False | ||
| return (dict( | ||
| id=self.id, | ||
| title=self.title, | ||
| description=self.description, | ||
| is_complete=self.is_complete, | ||
| goal_id=self.goal_id | ||
| )) | ||
| def to_dict(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. Rather than have two functions that do nearly the same thing, why not adopt the same approach of using conditional logic to set the |
||
| if not self.completed_at: | ||
| self.is_complete = False | ||
| return (dict( | ||
| id=self.id, | ||
| title=self.title, | ||
| description=self.description, | ||
| is_complete=self.is_complete, | ||
| )) | ||
|
|
||
| @classmethod | ||
| def from_dict(cls, data_dict): | ||
| return cls( | ||
| title = data_dict["title"], | ||
| description = data_dict["description"], | ||
| is_complete = data_dict["completed_at"] | ||
| ) | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| from flask import Blueprint, make_response, jsonify, request, abort | ||
| from app.models.task import Task | ||
| from app.models.goal import Goal | ||
| from app import db | ||
| from .route_helpers import validate_model | ||
|
|
||
| bp = Blueprint("goals", __name__, url_prefix="/goals") | ||
|
|
||
|
|
||
| @bp.route("", methods=["GET"]) | ||
| def get_all_goals(): | ||
| goals = Goal.query.all() | ||
| goals_list = [goal.to_dict() for goal in goals] | ||
|
|
||
| return jsonify(goals_list), 200 | ||
|
|
||
|
|
||
| @bp.route("", methods=["POST"]) | ||
| def create_a_goal(): | ||
| request_body = request.get_json() | ||
| if "title" not in request_body or not request_body["title"]: | ||
|
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. Thorough! |
||
| abort(make_response({"details": "Invalid data"}, 400)) | ||
| new_goal = Goal( | ||
| title=request_body["title"] | ||
| ) | ||
| db.session.add(new_goal) | ||
| db.session.commit() | ||
|
|
||
| return {"goal": new_goal.to_dict()}, 201 | ||
|
|
||
|
|
||
| @bp.route("/<id>", methods=["GET"]) | ||
| def get_one_goal(id): | ||
| goal = validate_model(Goal, id) | ||
|
|
||
| return {"goal": goal.to_dict()}, 200 | ||
|
|
||
|
|
||
| @bp.route("/<id>", methods=["PUT"]) | ||
| def update_a_goal(id): | ||
| goal = validate_model(Goal, id) | ||
| request_body = request.get_json() | ||
| goal.title = request_body["title"] | ||
|
|
||
| db.session.commit() | ||
|
|
||
| return {"goal": goal.to_dict()}, 200 | ||
|
|
||
|
|
||
| @bp.route("/<id>", methods=["DELETE"]) | ||
| def delete_a_goal(id): | ||
| goal = validate_model(Goal, id) | ||
| db.session.delete(goal) | ||
| db.session.commit() | ||
|
|
||
| return make_response({'details': f'Goal {goal.id} "{goal.title}" successfully deleted'}), 200 | ||
|
|
||
|
|
||
| @bp.route("/<id>/tasks", methods=["GET"]) | ||
| def get_all_tasks_for_one_goal(id): | ||
| goal = validate_model(Goal, id) | ||
| tasks_list = [(dict(id=task.id, title=task.title, description=task.description, | ||
| is_complete=False if task.completed_at is None else True, goal_id=goal.id)) for task in goal.tasks] | ||
|
|
||
| return {"id": goal.id, "title": goal.title, "tasks": tasks_list}, 200 | ||
|
|
||
|
|
||
| @bp.route("/<id>/tasks", methods=["POST"]) | ||
| def post_task_ids_to_goal(id): | ||
| goal = validate_model(Goal, id) | ||
| request_body = request.get_json() | ||
| if "task_ids" not in request_body: | ||
| abort(make_response({"details": "Invalid data"}, 400)) | ||
|
|
||
| task_ids = request_body["task_ids"] | ||
| tasks_list = [Task.query.get(task_id) for task_id in task_ids] | ||
| goal.tasks = tasks_list | ||
|
|
||
| db.session.commit() | ||
|
|
||
| return {"id": goal.id, "task_ids": task_ids}, 200 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| from flask import abort, make_response | ||
|
|
||
|
|
||
| def validate_model(cls, id): | ||
| try: | ||
| id = int(id) | ||
| except: | ||
| abort(make_response( | ||
| {"details": f"{cls.__name__} number {id} not valid"}, 400)) | ||
|
|
||
| model = cls.query.get(id) | ||
|
|
||
| if not model: | ||
| abort(make_response( | ||
| {"details": f"{cls.__name__} number {id} was not found"}, 404)) | ||
|
|
||
| return model |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| from flask import Blueprint, make_response, jsonify, request, abort | ||
| from app.models.task import Task | ||
| from app import db | ||
| from datetime import datetime | ||
| import requests | ||
| from .route_helpers import validate_model | ||
| import os | ||
| from dotenv import load_dotenv | ||
|
|
||
| load_dotenv() | ||
|
|
||
| bp = Blueprint("tasks", __name__, url_prefix="/tasks") | ||
|
|
||
|
|
||
| @bp.route("", methods=["GET"]) | ||
| def get_all_tasks(): | ||
| sorted_query = request.args.get("sort") | ||
| if sorted_query == "asc": | ||
| tasks = Task.query.order_by("title") | ||
|
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. Assuming this |
||
| elif sorted_query == "desc": | ||
| tasks = Task.query.order_by(Task.title.desc()) | ||
| else: | ||
| tasks = Task.query.all() | ||
|
|
||
| tasks_list = [task.to_dict() for task in tasks] | ||
|
|
||
| return jsonify(tasks_list), 200 | ||
|
|
||
|
|
||
| @bp.route("", methods=["POST"]) | ||
| def create_task(): | ||
| request_body = request.get_json() | ||
| if "title" not in request_body or not request_body["title"] or "description" not in request_body or not request_body["description"]: | ||
| abort(make_response({"details": "Invalid data"}, 400)) | ||
|
|
||
| new_task = Task( | ||
| title=request_body["title"], | ||
| description=request_body["description"] | ||
| ) | ||
|
|
||
| db.session.add(new_task) | ||
| db.session.commit() | ||
|
|
||
| return {"task": new_task.to_dict()}, 201 | ||
|
|
||
|
|
||
| @bp.route("/<id>", methods=["GET"]) | ||
| def get_one_task(id): | ||
| task = validate_model(Task, id) | ||
| if task.goal_id: | ||
| return {"task": task.to_dict_with_goal()}, 200 | ||
| return {"task": task.to_dict()}, 200 | ||
|
|
||
|
|
||
| @bp.route("/<id>", methods=["PUT"]) | ||
| def update_task(id): | ||
| task = validate_model(Task, id) | ||
| request_body = request.get_json() | ||
| is_complete = request_body.get("is_complete", False) | ||
|
|
||
| task.title = request_body["title"] | ||
| task.description = request_body["description"] | ||
| task.is_complete = is_complete | ||
|
|
||
| db.session.commit() | ||
|
|
||
| return {"task": task.to_dict()}, 200 | ||
|
|
||
|
|
||
| @bp.route("/<id>", methods=["DELETE"]) | ||
| def delete_task(id): | ||
| task = validate_model(Task, id) | ||
|
|
||
| db.session.delete(task) | ||
| db.session.commit() | ||
|
|
||
| return {"details": f'Task {id} "{task.title}" successfully deleted'}, 200 | ||
|
|
||
|
|
||
| @bp.route("/<id>/mark_complete", methods=["PATCH"]) | ||
| def complete_task(id): | ||
| task = validate_model(Task, id) | ||
| if not task.completed_at: | ||
| task.completed_at = datetime.now() | ||
| task.is_complete = True | ||
|
|
||
| PATH = "https://slack.com/api/chat.postMessage" | ||
| Authorization = os.environ.get( | ||
| "Authorization") | ||
| text = f"Someone just completed the task {task.title}" | ||
|
|
||
| headers = { | ||
| "Authorization": Authorization, | ||
| "format": "json" | ||
| } | ||
|
|
||
| body = { | ||
| "channel": "task-notifications", | ||
| "text": text, | ||
| } | ||
| requests.post(PATH, headers=headers, json=body) | ||
|
|
||
| db.session.commit() | ||
|
|
||
| return {"task": task.to_dict()}, 200 | ||
|
|
||
|
|
||
| @bp.route("/<id>/mark_incomplete", methods=["PATCH"]) | ||
| def incomplete_task(id): | ||
| task = validate_model(Task, id) | ||
|
|
||
| if task.completed_at: | ||
| task.completed_at = None | ||
| task.is_complete = False | ||
|
|
||
| db.session.commit() | ||
|
|
||
| return {"task": task.to_dict()}, 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 👍🏽