Skip to content
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(shared-views): Add endpoint to star and unstar views #87463

Merged
merged 2 commits into from
Mar 20, 2025

Conversation

MichaelSun48
Copy link
Member

This PR adds the POST /group-search-views/:viewId/starred endpoint, which exposes the ability to star and unstar a view.

At a high level the logic is as follows:

  1. Validate that the view exists and that the user has access to the view (either they own it, or its an org shared view)
  2. if the starred query param is true:
    a. Do nothing if the view was already starred.
    b. If position is provided, insert at that position and increment any new views
    c. if position is not provided, star the view and insert at the end of the list.
  3. If the starred query param is false, do nothing if its already unstarred, otherwise unstar the view.

@MichaelSun48 MichaelSun48 requested review from a team as code owners March 19, 2025 22:59
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Mar 19, 2025
Comment on lines +52 to +61
try:
view = GroupSearchView.objects.get(id=view_id, organization=organization)
except GroupSearchView.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)

if not (
view.user_id == request.user.id
or view.visibility == GroupSearchViewVisibility.ORGANIZATION
):
return Response(status=status.HTTP_404_NOT_FOUND)
Copy link
Member

Choose a reason for hiding this comment

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

should we create a OrganizationGroupSearchViewBase endpoint that validates this? (similar to how say how member or group endpoint have this)

Copy link
Member Author

Choose a reason for hiding this comment

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

This is a great idea actually! Though this should probably be in its own PR, I’ll add it to my todo list

@@ -48,6 +65,77 @@ def reorder_starred_views(
if views_to_update:
self.bulk_update(views_to_update, ["position"])

def insert_starred_view(
Copy link
Member

Choose a reason for hiding this comment

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

do we need to put this function in a db transaction? (can use transaction.atomic decorator if so).

Copy link
Member Author

Choose a reason for hiding this comment

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

I don’t think this set of db updates is particularly high risk, but I suppose it can’t hurt. Is there any downside to running it in a transaction that I’m not thinking of?

Copy link
Member

Choose a reason for hiding this comment

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

just thinking if two requests hit this endpoint simultaneously, could that put things into a weird state? if no, no need. i don't think there's a huge downside to putting it in a transaction at the scale of traffic this endpoint will likely get.

Copy link
Member Author

@MichaelSun48 MichaelSun48 Mar 19, 2025

Choose a reason for hiding this comment

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

hmm yeah It's possible if two endpoints try to star a view and add it in the same position at the same time, then the later request might hit a unique constraint violation. I imagine the odds of that are exceedingly small given the traffic for this endpoint, but better safe than sorry I suppose.

ValueError: If the view is already starred
"""
if self.get_starred_view(organization, user_id, view):
raise ValueError("View is already starred.")
Copy link
Member

Choose a reason for hiding this comment

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

in both cases where we raise a ValueError we catch it then continue -- maybe we should just return instead?

can see chapter 10, define errors out of existence in "A Philosophy of Software Design" for an opinion ons on errors and interfaces https://milkov.tech/assets/psd.pdf

Copy link
Member Author

Choose a reason for hiding this comment

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

I thought about that, and you're right that the endpoint in this PR happens to not care if it gets raised or not, but I figured that since function is on the model manager and is designed to be reusable, it would be better if it took the least opinionated/most verbose approach possible.

Copy link
Member

Choose a reason for hiding this comment

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

i think it would be fair to return for now -- if you don't need it now, whoever is using the obj manager method in the future can add that error in and handle it. one other thing you could do is return a boolean saying whether or not the view was creator or not, and for now you don't need to use it.

relevant links for thought:


def get_starred_view(
self, organization: Organization, user_id: int, view: GroupSearchView
) -> "GroupSearchViewStarred | None":
Copy link
Member

Choose a reason for hiding this comment

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

if you put from __future__ import annotations at top of file i don't think you need the quotes around the return types?

Copy link
Member

@JoshFerge JoshFerge left a comment

Choose a reason for hiding this comment

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

looks good!

@MichaelSun48 MichaelSun48 merged commit 7f347f2 into master Mar 20, 2025
48 checks passed
@MichaelSun48 MichaelSun48 deleted the msun/sharedViews/starredEndpoint branch March 20, 2025 17:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Scope: Backend Automatically applied to PRs that change backend components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants