Skip to content

Commit ce8edd8

Browse files
committed
added utilities folder which holds create_model, validate_model, delte_model, get_model_with_filters, added goals and goal descriptions, all of wave 5 tests have passed, added slack post api functionality to the mark complete function of tasks.
1 parent d3b9a42 commit ce8edd8

11 files changed

+340
-151
lines changed

app/__init__.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
from flask import Flask
1+
from flask import Flask, request, jsonify
2+
from slack_sdk import WebClient
3+
from slack_sdk.errors import SlackApiError
24
from .db import db, migrate
35
from .models import task, goal
46
from .routes.task_routes import tasks_bp
7+
from .routes.slack_routes import slack_bp
8+
from .routes.goal_routes import goals_bp
59
import os
610

711
def create_app(config=None):
@@ -20,5 +24,33 @@ def create_app(config=None):
2024

2125
# Register Blueprints here
2226
app.register_blueprint(tasks_bp)
27+
app.register_blueprint(slack_bp)
28+
app.register_blueprint(goals_bp)
2329

2430
return app
31+
32+
# from flask import Flask
33+
# from .db import db, migrate
34+
# from .models import task, goal
35+
# from .routes.task_routes import tasks_bp
36+
# import os
37+
38+
# def create_app(config=None):
39+
# app = Flask(__name__)
40+
41+
# app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
42+
# app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('SQLALCHEMY_DATABASE_URI')
43+
44+
# if config:
45+
# # Merge `config` into the app's configuration
46+
# # to override the app's default settings for testing
47+
# app.config.update(config)
48+
49+
# db.init_app(app)
50+
# migrate.init_app(app, db)
51+
52+
# # Register Blueprints here
53+
# app.register_blueprint(tasks_bp)
54+
55+
# return app
56+

app/models/goal.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
from sqlalchemy.orm import Mapped, mapped_column
22
from ..db import db
3+
from datetime import datetime
4+
from app.routes.utilities_routes import create_model, validate_model, check_for_completion
5+
from typing import Optional
36

47
class Goal(db.Model):
58
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
9+
title: Mapped[str]
10+
# description=Mapped[str]
11+
# completed_at: Mapped[Optional[datetime]]=mapped_column(nullable = True)
12+
13+
14+
def to_dict(self):
15+
task_as_dict = {}
16+
task_as_dict["id"] = self.id
17+
task_as_dict["title"] = self.title
18+
# task_as_dict["description"] = self.description
19+
# task_as_dict["is_complete"] = check_for_completion(Goal,self)
20+
21+
return task_as_dict
22+
23+
24+
25+
@classmethod
26+
def from_dict(cls, goal_data):
27+
new_task = cls(
28+
title=goal_data["title"],
29+
# description=goal_data["description"],
30+
# completed_at=goal_data["completed_at"]
31+
)
32+
return new_task

app/models/task.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from sqlalchemy.orm import Mapped, mapped_column
22
from ..db import db
33
from datetime import datetime
4+
from app.routes.utilities_routes import create_model, validate_model, check_for_completion
45
from typing import Optional
56

67
class Task(db.Model):
@@ -9,5 +10,20 @@ class Task(db.Model):
910
description: Mapped[str]
1011
completed_at: Mapped[Optional[datetime]]= mapped_column(nullable = True)
1112

13+
def to_dict(self):
14+
task_as_dict = {}
15+
task_as_dict["id"] = self.id
16+
task_as_dict["title"] = self.title
17+
task_as_dict["description"] = self.description
18+
task_as_dict["is_complete"] = check_for_completion(Task,self)
19+
20+
return task_as_dict
1221

1322

23+
@classmethod
24+
def from_dict(cls, task_data):
25+
new_task = cls(
26+
title=task_data["title"],
27+
description=task_data["description"],
28+
)
29+
return new_task

app/routes/goal_routes.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,42 @@
1-
from flask import Blueprint
1+
from flask import Blueprint, abort, make_response, request, Response
2+
from app.models.task import Task
3+
from ..db import db
4+
from datetime import datetime
5+
from app.routes.utilities_routes import create_model, validate_model, get_models_with_filters, check_for_completion, delete_model
6+
from app.models.goal import Goal
7+
import requests
8+
9+
goals_bp = Blueprint("goals_bp",__name__, url_prefix= "/goals")
10+
11+
12+
@goals_bp.post("")
13+
def create_goal():
14+
request_body = request.get_json()
15+
return create_model(Goal,request_body)
16+
17+
@goals_bp.get("")
18+
def get_goals():
19+
request_arguements = request.args
20+
return get_models_with_filters(Goal, request_arguements)
21+
22+
@goals_bp.get("/<goal_id>")
23+
def get_one_goal(goal_id):
24+
goal = validate_model(Goal, goal_id)
25+
response = {"goal": goal.to_dict()}
26+
return make_response(response, 200)
27+
28+
@goals_bp.put("/<goal_id>")
29+
def update_goal(goal_id):
30+
goal = validate_model(Goal, goal_id)
31+
request_body = request.get_json()
32+
33+
goal_title = request_body["title"]
34+
db.session.commit()
35+
36+
response_body = {"message": f"Goal #{goal_id} succesfully updated"}
37+
return make_response(response_body, 200)
38+
39+
@goals_bp.delete("/<goal_id>")
40+
def delete_goal(goal_id):
41+
goal = validate_model(Goal, goal_id)
42+
return delete_model(Goal, goal)

app/routes/slack_routes.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from flask import Blueprint, request, jsonify
2+
from slack_sdk import WebClient
3+
from slack_sdk.errors import SlackApiError
4+
import os
5+
6+
# Initialize the Blueprint
7+
slack_bp = Blueprint('slack_bp', __name__)
8+
9+
# Slack Bot Token from environment variable
10+
SLACK_BOT_TOKEN =" os.getenv("APITOKENHERE")
11+
client = WebClient(token=SLACK_BOT_TOKEN)
12+
13+
@slack_bp.post('/send_message')
14+
def send_message():
15+
data = request.get_json()
16+
channel = data.get("channel")
17+
message = data.get("message")
18+
19+
if not channel or not message:
20+
return jsonify({"error": "Channel and message are required"}), 400
21+
22+
try:
23+
# Make the chat.postMessage API call
24+
response = client.chat_postMessage(channel=channel, text=message)
25+
return jsonify({"ok": response["ok"], "message": "Message sent successfully!"}), 200
26+
except SlackApiError as e:
27+
# Handle Slack API error and print more details for debugging
28+
error_message = e.response["error"]
29+
print(f"Slack API Error: {error_message}")
30+
return jsonify({"ok": False, "error": error_message}), 400
31+
app.run(debug=True)
32+
33+

app/routes/task_routes.py

Lines changed: 38 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from flask import Blueprint, abort, make_response, request, Response
22
from app.models.task import Task
3+
from app.routes.utilities_routes import create_model, validate_model, get_models_with_filters, check_for_completion, delete_model
34
from ..db import db
45
from datetime import datetime
6+
import requests
57

68

79
tasks_bp = Blueprint("tasks_bp", __name__, url_prefix="/tasks")
@@ -11,41 +13,8 @@
1113
@tasks_bp.post("")
1214
def create_task():
1315
request_body = request.get_json()
14-
try:
15-
title = request_body["title"]
16-
except:
17-
abort(make_response(invalid_data_response))
16+
return create_model(Task,request_body)
1817

19-
try:
20-
description = request_body["description"]
21-
except:
22-
abort(make_response(invalid_data_response))
23-
24-
# is_complete = check_for_completion(request_body)
25-
is_complete = False
26-
##completed_at not an attribute
27-
try:
28-
completed_at = request_body["completed_at"]
29-
except:
30-
completed_at = None
31-
new_task = Task(title=title, description= description,completed_at= completed_at)
32-
33-
34-
db.session.add(new_task)
35-
db.session.commit()
36-
37-
38-
is_complete = check_for_completion(new_task)
39-
response = {"task":{
40-
"id": new_task.id,
41-
"title": new_task.title,
42-
"description": new_task.description,
43-
"is_complete": is_complete
44-
}}
45-
46-
return response, 201
47-
48-
#get all tasks with query paramaters added in
4918
@tasks_bp.get("")
5019
def get_tasks():
5120
query = db.select(Task)
@@ -76,16 +45,16 @@ def get_tasks():
7645
tasks_response = []
7746

7847
for task in tasks:
79-
tasks_response.append(get_dict(task))
48+
tasks_response.append(task.to_dict())
8049

8150
return tasks_response,200
8251

8352

8453
#get task by task id:
8554
@tasks_bp.get("/<task_id>")
8655
def get_one_task(task_id):
87-
task = validate_task(task_id)
88-
task_dict = get_dict(task)
56+
task = validate_model(Task,task_id)
57+
task_dict = task.to_dict()
8958
response = {"task":task_dict}
9059
expected = {
9160
"task": {
@@ -102,7 +71,7 @@ def get_one_task(task_id):
10271
#update task
10372
@tasks_bp.put("/<task_id>")
10473
def update_task(task_id):
105-
task = validate_task(task_id)
74+
task = validate_model(Task,task_id)
10675

10776
request_body = request.get_json()
10877
task.title = request_body["title"]
@@ -115,70 +84,60 @@ def update_task(task_id):
11584
task.completed_at = completed_at
11685
db.session.commit()
11786

118-
response = {"task":get_dict(task)}
87+
response = {"task":task.to_dict()}
11988
return response, 200
12089

12190

12291
#Delete task
12392
@tasks_bp.delete("/<task_id>")
12493
def delete_task(task_id):
125-
task = validate_task(task_id)
126-
task_title = task.title
94+
task = validate_model(Task,task_id)
95+
return delete_model(Task, task)
96+
# task_title = task.title
12797

128-
db.session.delete(task)
129-
db.session.commit()
130-
details = f"Task {task_id} \"{task_title}\" successfully deleted"
131-
response_body = {"details" : details}
98+
# db.session.delete(task)
99+
# db.session.commit()
100+
# details = f"Task {task_id} \"{task_title}\" successfully deleted"
101+
# response_body = {"details" : details}
102+
103+
# return response_body
132104

133-
return response_body
134105

106+
#route 2
135107
@tasks_bp.patch("/<task_id>/mark_complete")
136108
def mark_complete(task_id):
137-
task = validate_task(task_id)
109+
task = validate_model(Task, task_id)
138110
task.completed_at = datetime.now()
139111
db.session.commit()
140-
response = {"task": get_dict(task)}
112+
113+
message = f"Task {task.title} has been marked as complete!"
114+
115+
slack_url = "http://127.0.0.1:5000/send_message"
116+
payload = {
117+
"message": message,
118+
"channel": "api-test-channel"
119+
}
120+
121+
try:
122+
response = requests.post(slack_url, json=payload)
123+
response.raise_for_status()
124+
except requests.exceptions.RequestException as e:
125+
print(f"failed to send slack message: {e}")
126+
127+
response = {"task": task.to_dict()}
141128
return make_response(response, 200)
142129

143130
@tasks_bp.patch("/<task_id>/mark_incomplete")
144131
def mark_incomplete(task_id):
145-
task = validate_task(task_id)
132+
task = validate_model(Task, task_id)
146133
task.completed_at = None
147134
db.session.commit()
148-
response = {"task": get_dict(task)}
135+
response = {"task": task.to_dict()}
149136
return make_response(response,200)
150-
#helperfunctions
151137

152-
def check_for_completion(task):
153-
completed_at = task.completed_at
154-
if completed_at is None:
155-
return False
156-
else:
157-
return True
158-
159-
def get_dict(task):
160-
return {
161-
"id": task.id,
162-
"title": task.title,
163-
"description": task.description,
164-
"is_complete": check_for_completion(task)
165-
}
166138

167-
def validate_task(task_id):
168-
try:
169-
task_id = int(task_id)
170-
except:
171-
response = ({"details" : "invalid data"},400)
172-
abort(make_response(response))
173-
174-
query = db.select(Task).where(Task.id == task_id)
175-
task = db.session.scalar(query)
176139

177-
if not task:
178-
response = ({"details": f"task {task_id} not found"},404)
179-
abort(make_response(response))
180-
181-
return task
140+
#helperfunctions
182141

183142

184143

0 commit comments

Comments
 (0)