-
Notifications
You must be signed in to change notification settings - Fork 13.9k
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
feat(Tags): Allow users to favorite Tags on CRUD Listview page #24701
Conversation
Codecov Report
@@ Coverage Diff @@
## master #24701 +/- ##
==========================================
+ Coverage 68.84% 68.98% +0.14%
==========================================
Files 1902 1903 +1
Lines 73997 74086 +89
Branches 8195 8194 -1
==========================================
+ Hits 50944 51110 +166
+ Misses 20934 20860 -74
+ Partials 2119 2116 -3
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 11 files with indirect coverage changes 📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
05e3e8a
to
4d18262
Compare
superset/daos/tag.py
Outdated
|
||
if tag and user: | ||
tag.users_favorited.append(user) | ||
db.session.add(tag) |
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.
should we use session.merge as this tag object is returned object from the DAO?
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.
whats the difference between just doing add/commit?
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.
see https://docs.sqlalchemy.org/en/20/orm/session_state_management.html
and https://stackoverflow.com/questions/1849567/can-sqlalchemys-session-merge-update-its-result-with-newer-data-from-the-data
I believe since you get tag from the TagDAO the tag object is already in the session.
Calling add here is redundant.
But I am not sure about that g.user
if that's returning a user object in the same session or if it's in a different session.
If it's in different sqla session, you will want to call merge() here so that it merges the user object to current session by matching the user.id.
Regardless, I think merge() is safer.
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.
Agree. We should pass the user as a param as opposed to using the global
superset/daos/tag.py
Outdated
@@ -257,3 +266,90 @@ def get_tagged_objects_for_tags( | |||
for obj in saved_queries | |||
) | |||
return results | |||
|
|||
@staticmethod | |||
def user_favorite_tag(tag_id: int) -> None: |
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.
naming: maybe favor_tag_by_id_for_current_user
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.
or you can pass in user_id as param so it will be like def favor_tag_by_id(tag_id: int, user_id: int) -> None
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.
is there any authorization that you need to check or any user can favor any tag?
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.
right now any user can favorite a tag and matches the current functionality for other resources
db.session.commit() | ||
|
||
@staticmethod | ||
def favorited_ids(tags: list[Tag]) -> list[int]: |
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.
naming: favorited_tag_ids
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.
I think it's better to just pass in tag IDs instead of the tag objects
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.
i want to follow the same convention i the other DAOs:
https://github.com/preset-io/superset/blob/84c183e0e6005738b0dad60a30824b17a087a752/superset/daos/chart.py#L73
superset/tags/api.py
Outdated
$ref: '#/components/responses/500' | ||
""" | ||
requested_ids = kwargs["rison"] | ||
tags = TagDAO.find_by_ids(requested_ids) |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
Returns: | ||
None. | ||
""" | ||
tag = TagDAO.find_by_id(tag_id) |
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.
we should check tag is None here and throw.
Then in the controller you catch the TagNotFoundException and return 404 http code
@hughhhh would you mind including screenshots (or the designs) to help provide more context. |
superset/daos/tag.py
Outdated
|
||
# Remove the tag from the user's favorites | ||
if tag and user: | ||
tag.users_favorited.remove(user) |
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.
What's the TL;DR between tags and favoriting? It seems like we're doing double bookkeeping here which is likely suboptimal.
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.
tags will become the defacto for managing favorites moving forward, i have a ticket to manage migration and handle the cleanup.
This table is needed becuase we can leverage tags to favorite tags with the circuliar dependency
superset/daos/tag.py
Outdated
Returns: | ||
None. | ||
""" | ||
# Find the tag |
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.
This comment seems superfluous. Well named methods FTW!
superset/daos/tag.py
Outdated
tag = TagDAO.find_by_id(tag_id) | ||
user = g.user | ||
|
||
# Remove the tag from the user's favorites |
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.
See previous comment.
b7a5ae5
to
5c414ed
Compare
5c414ed
to
0943192
Compare
0943192
to
6948f13
Compare
6948f13
to
2a29be1
Compare
superset/tags/api.py
Outdated
500: | ||
$ref: '#/components/responses/500' | ||
""" | ||
TagDAO.favorite_tag_by_id_for_current_user(pk) |
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.
do you need to handle UserNotFound and TagNotFound exception here?
superset/tags/api.py
Outdated
if not TagDAO.find_by_id(pk): | ||
return self.response_404() | ||
|
||
TagDAO.remove_user_favorite_tag(pk) |
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.
do you need to handle UserNotFound and TagNotFound exception here? You can remove line 516 then
@@ -372,3 +372,47 @@ def test_delete_tags(self): | |||
# check that tags are all gone | |||
tags = db.session.query(Tag).filter(Tag.name.in_(example_tag_names)) | |||
self.assertEqual(tags.count(), 0) | |||
|
|||
@pytest.mark.usefixtures("create_tags") | |||
def test_add_delete_favorite_tag(self): |
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.
add some negative tests for bad tag id
mock_session.commit.assert_called_once() | ||
|
||
|
||
def test_remove_user_favorite_tag(mocker): |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
bc20c0b
to
8c5772b
Compare
@pytest.mark.usefixtures("create_tags") | ||
def test_add_tag_not_found(self): | ||
self.login(username="admin") | ||
user_id = self.get_user(username="admin").get_id() |
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.
user_id is not used
57a00a3
to
903cdaa
Compare
…xgh-update-tags-page
88fd3a4
to
4e01884
Compare
4e01884
to
c1a6082
Compare
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.
lgtm
SUMMARY
Update CRUD Tag Page to have favorites stars, and filter dropdowns from @kasiazjc designs. The main change is now allowing users to favorite tags
BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
TESTING INSTRUCTIONS
ADDITIONAL INFORMATION