Skip to content

Conversation

@xixilele1990
Copy link

all tests passed with the picture of wave4



The result show as below
![](assets/lexy-slackbot.png)
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for including the image ^_^

app/__init__.py Outdated
Comment on lines 8 to 9
from dotenv import load_dotenv
load_dotenv()
Copy link
Contributor

Choose a reason for hiding this comment

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

Were you running into an issue that required calling load_dotenv() from here?

We need to call load_dotenv() in conftest.py to load up variables for the testing flow, but that shouldn't be necessary in production mode if we've configured things the same as we did for the hello-books and solar-system APIs.

If this code is not necessary, then we should remove it.

Copy link
Author

@xixilele1990 xixilele1990 Nov 15, 2025

Choose a reason for hiding this comment

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

yes, I have duplicated , the one in init removed in my update commit, thanks

@@ -1,5 +1,25 @@
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.orm import Mapped, mapped_column,relationship
Copy link
Contributor

Choose a reason for hiding this comment

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

Small spacing issue:

Suggested change
from sqlalchemy.orm import Mapped, mapped_column,relationship
from sqlalchemy.orm import Mapped, mapped_column, relationship

The same issue for the same import shows up in the Task model file.

Copy link
Author

Choose a reason for hiding this comment

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

updated.thanks

from sqlalchemy.orm import Mapped, mapped_column,relationship
from ..db import db
from sqlalchemy import String
#from sqlalchemy import Date
Copy link
Contributor

Choose a reason for hiding this comment

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

If an import was not required, the line should be removed completely before merging code from our branch into the main repo.

Comment on lines 33 to 35



Copy link
Contributor

Choose a reason for hiding this comment

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

Small spacing issue, PEP8 best practices are to use a single line to separate methods within a class to visually show that these are closely related.

Comment on lines 134 to 135


Copy link
Contributor

Choose a reason for hiding this comment

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

Best practices are that we should only have a single blank line at most separating lines inside of a function. More lines makes the reader think the function has ended and can be very confusing when trying to quickly read through code.

Copy link
Author

Choose a reason for hiding this comment

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

thanks for the headsup

Comment on lines 140 to 148
if not current_app.config.get("TESTING"):
response = requests.post(
"https://slack.com/api/chat.postMessage",
headers={"Authorization": f"Bearer {slack_token}"},

json={"channel": slack_channel, "text": message}
)
if current_app.config.get("TESTING"):
return Response(status=204, mimetype="application/json")
Copy link
Contributor

Choose a reason for hiding this comment

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

We could make this a little more concise and unindent the main flow of the application by first checking if we are in testing mode:

    if current_app.config.get("TESTING"):
        return Response(status=204, mimetype="application/json")
        
    response = requests.post(
        "https://slack.com/api/chat.postMessage",
        headers={"Authorization": f"Bearer {slack_token}"},
        json={"channel": slack_channel, "text": message}
    ) 

If we handle the edge case return first, then if we move past that without returning we must be on the production path and do not need to indent it with an if-statement to check.

Copy link
Author

Choose a reason for hiding this comment

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

if not current_app.config.get("TESTING"):
response = requests.post(
"https://slack.com/api/chat.postMessage",
headers={"Authorization": f"Bearer {slack_token}"},

        json={"channel": slack_channel, "text": message}
    )
return Response(status=204, mimetype="application/json")       , not sure how to avoid using if ..

Comment on lines 148 to 151
return Response(status=204, mimetype="application/json")


return jsonify({"task": task.to_dict()}), 200
Copy link
Contributor

Choose a reason for hiding this comment

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

This function is not meeting the specification in the project READMEs. The function returns a different result in production vs when in testing. This would not be acceptable in a development team since the tests are not actually testing what the end user would see.

This function needs to be revisited to return the same response no matter what mode we are in. What would need to change to gracefully handle ignoring the slack message if the token isn't set or we are in testing mode?

Comment on lines 21 to 32
def create_model(cls, model_data):
try:
new_model = cls.from_dict(model_data)
except KeyError as e:
#response = {"message": f"Invalid request: missing {e.args[0]}"}
#abort(make_response(response, 400))
abort(make_response({"details": "Invalid data"}, 400))

db.session.add(new_model)
db.session.commit()

return new_model.to_dict(), 201
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this both creates a model and creates an http response, I'd consider renaming this to create_model_and_response. Or to better follow single responsibility principles, we could split this into 2 functions:

  • one function that only manages creating and returns the new model
  • one function that uses the function above to get the model, then creates and returns the response based on that model.

Comment on lines 25 to 26
#response = {"message": f"Invalid request: missing {e.args[0]}"}
#abort(make_response(response, 400))
Copy link
Contributor

Choose a reason for hiding this comment

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

Please remove commented code before opening PRs.


db.session.commit()

return Response(status = 204,mimetype ="application/json")
Copy link
Contributor

Choose a reason for hiding this comment

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

Small spacing issues.

We don't include spaces around the = when we are filling out a keyword argument in a function invocation.

  • This differs from when it is used for variable assignment or as part of a comparison operator where we always surround = in spaces.
Suggested change
return Response(status = 204,mimetype ="application/json")
return Response(status=204, mimetype="application/json")

if current_app.config.get("TESTING"):
return Response(status=204, mimetype="application/json")
#if current_app.config.get("TESTING"):
return Response(status=204, mimetype="application/json")
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice restructuring so the message is only sent in production mode, but we always return the same response.


return jsonify(new_goal.to_dict()), 201
#return jsonify(new_goal.to_dict()), 201
return create_model(Goal,request_body)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice update to use create_model for the Goal class! Is there a reason we cannot use it for Tasks as well?

Copy link
Author

Choose a reason for hiding this comment

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

just updated

Comment on lines 15 to 23
# try:
# new_goal = Goal.from_dict(request_body)
# except KeyError:
# return jsonify({"details": "Invalid data"}), 400

db.session.add(new_goal)
db.session.commit()
# db.session.add(new_goal)
# db.session.commit()

return jsonify(new_goal.to_dict()), 201
#return jsonify(new_goal.to_dict()), 201
Copy link
Contributor

Choose a reason for hiding this comment

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

As part of these updates, please follow best practices to remove the old code once the refactor is working as expected.

Copy link
Author

Choose a reason for hiding this comment

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

sure!

@xixilele1990 xixilele1990 force-pushed the main branch 3 times, most recently from bc464ac to 6e7836f Compare November 18, 2025 00:21
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
title: Mapped[str] = mapped_column(String(100), nullable=False)
description: Mapped[str] = mapped_column(String(255))
completed_at:Mapped[datetime.date] = mapped_column(Date, nullable=True)
Copy link
Contributor

Choose a reason for hiding this comment

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

This line is referencing two different data types datetime.date and sqlalchemy.Date:

completed_at:Mapped[datetime.date] = mapped_column(Date, nullable=True)

It seems like some kind of type coercion might be happening under the hood such that we are not running into errors, but this can lead to bugs or unexpected behavior if changes to either data type in the future means that the type coercion fails.

Depending on the requirements of a project we might choose one type or the other, but as with many programming best practices, it's most important to choose a single type and be consistent across the project with what you use. For this project either datetime.date or sqlalchemy.Date works here, but we should choose only one of them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants