Skip to content

Conversation

@harshithadurai
Copy link
Contributor

@harshithadurai harshithadurai commented Nov 1, 2024

Issue: #79827

This PR modifies the existing DashbaordsPermissions model. Previously, edit access for a dashboard could be restricted only to the dashboard's creator. Now, selective teams can be granted edit access.

Summary of changes:

Changes to DashboardPermissions model:

  • Add new ManytoMany field, teams_with_edit_access
  • Add new field, is_editable_by_everyone which will eventually serve as a replacement for is_creator_only_editable

Serializer changes:

  • Add logic to handle teams_with_edit_access as a list of team IDs in the API requests
  • Add validation to ensure the teams exist
  • Add validation to ensure that only the creator of a Dashboard can modify the perms

Tests:

  • Update old tests that update perms by ensuring that the user making the request is logged in as the creator (because of above validation)
  • Add new tests for teams functionality

@harshithadurai harshithadurai requested a review from a team as a code owner November 1, 2024 17:42
@harshithadurai harshithadurai requested review from a team November 1, 2024 17:42
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Nov 1, 2024
Copy link
Member

@wedamija wedamija left a comment

Choose a reason for hiding this comment

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

I'd recommend splitting out the migrations here from the logic, just since the migration is a little complicated

@codecov

This comment was marked as outdated.

@github-actions github-actions bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Nov 1, 2024
@github-actions
Copy link
Contributor

github-actions bot commented Nov 1, 2024

🚨 Warning: This pull request contains Frontend and Backend changes!

It's discouraged to make changes to Sentry's Frontend and Backend in a single pull request. The Frontend and Backend are not atomically deployed. If the changes are interdependent of each other, they must be separated into two pull requests and be made forward or backwards compatible, such that the Backend or Frontend can be safely deployed independently.

Have questions? Please ask in the #discuss-dev-infra channel.

@github-actions

This comment was marked as outdated.

Copy link
Member

@markstory markstory left a comment

Choose a reason for hiding this comment

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

Schema changes look good to me.

if teams_data == [] or permissions_data["is_editable_by_everyone"] is True:
permissions.teams_with_edit_access.clear()
else:
permissions.teams_with_edit_access.set(Team.objects.filter(id__in=teams_data))
Copy link
Member

Choose a reason for hiding this comment

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

At this point has teams_data been run through validation to ensure that only teams within the current organization are referenced?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, but added an org filter here as well

Comment on lines 46 to 47
for team in self.teams_with_edit_access.all():
if user_id in team.get_member_user_ids():
Copy link
Member

Choose a reason for hiding this comment

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

You have N queries here. If team assignments to dashboards get long this could get slow.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to this:

        return self.teams_with_edit_access.filter(
            organizationmemberteam__organizationmember__user_id=user_id
        ).exists()

Copy link
Member

Choose a reason for hiding this comment

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

🎉 Very nice, much better.

updated_perms = DashboardPermissions.objects.get(dashboard=self.dashboard)
assert set(updated_perms.teams_with_edit_access.all()) == {team1, new_team1, new_team2}

def test_update_dashboard_permissions_with_invalid_teams(self):
Copy link
Member

Choose a reason for hiding this comment

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

It would be good to have a test for teams from other organizations as well.

Copy link
Member

@narsaynorath narsaynorath left a comment

Choose a reason for hiding this comment

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

One last comment! Everything else looks good, I just realized we should feature flag the validation check for now. Let me know what you want to do with the permission check. I think the easiest option to avoid bugs in the future is to handle it in the backend or else someone in the frontend may forget and send permissions, and we'd get validation issues.

Comment on lines 563 to 569
permissions = data.get("permissions")
if permissions and self.instance:
currentUser = self.context["request"].user
if self.instance.created_by_id != currentUser.id:
raise serializers.ValidationError(
"Only the Dashboard Creator may modify Dashboard Edit Access"
)
Copy link
Member

Choose a reason for hiding this comment

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

I just realized, this will trigger if a user updates the dashboard (e.g. they change the title) and the dashboard that we're sending from the frontend has "permissions" in its state, right?

  1. We should feature flag this so it doesn't affect customers inadvertently
  2. Either we should check that the request is actually changing the permissions, or we should ensure that the frontend only sends this when they change the permissions selector

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the case that the user is just updating the dashboard's title, permissions will be None, so it wouldn't go through the if condition. Do you mean that there needs to be a check before the data.get("permissions") statement?

@github-actions
Copy link
Contributor

github-actions bot commented Nov 6, 2024

This PR has a migration; here is the generated SQL for src/sentry/migrations/0785_add_new_field_to_dashboard_permissions.py ()

--
-- Custom state/database change combination
--

                    ALTER TABLE "sentry_dashboardpermissions" ADD COLUMN "is_editable_by_everyone" boolean NOT NULL DEFAULT true;
                    
--
-- Create model DashboardPermissionsTeam
--
CREATE TABLE "sentry_dashboardpermissionsteam" ("id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, "permissions_id" bigint NOT NULL, "team_id" bigint NOT NULL);
CREATE UNIQUE INDEX CONCURRENTLY "sentry_dashboardpermissi_team_id_permissions_id_87e7a578_uniq" ON "sentry_dashboardpermissionsteam" ("team_id", "permissions_id");
ALTER TABLE "sentry_dashboardpermissionsteam" ADD CONSTRAINT "sentry_dashboardpermissi_team_id_permissions_id_87e7a578_uniq" UNIQUE USING INDEX "sentry_dashboardpermissi_team_id_permissions_id_87e7a578_uniq";
ALTER TABLE "sentry_dashboardpermissionsteam" ADD CONSTRAINT "sentry_dashboardperm_permissions_id_bf945b43_fk_sentry_da" FOREIGN KEY ("permissions_id") REFERENCES "sentry_dashboardpermissions" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_dashboardpermissionsteam" VALIDATE CONSTRAINT "sentry_dashboardperm_permissions_id_bf945b43_fk_sentry_da";
ALTER TABLE "sentry_dashboardpermissionsteam" ADD CONSTRAINT "sentry_dashboardperm_team_id_3de35a2f_fk_sentry_te" FOREIGN KEY ("team_id") REFERENCES "sentry_team" ("id") DEFERRABLE INITIALLY DEFERRED NOT VALID;
ALTER TABLE "sentry_dashboardpermissionsteam" VALIDATE CONSTRAINT "sentry_dashboardperm_team_id_3de35a2f_fk_sentry_te";
CREATE INDEX CONCURRENTLY "sentry_dashboardpermissionsteam_permissions_id_bf945b43" ON "sentry_dashboardpermissionsteam" ("permissions_id");
CREATE INDEX CONCURRENTLY "sentry_dashboardpermissionsteam_team_id_3de35a2f" ON "sentry_dashboardpermissionsteam" ("team_id");
--
-- Add field teams_with_edit_access to dashboardpermissions
--
-- (no-op)

Copy link
Member

@narsaynorath narsaynorath left a comment

Choose a reason for hiding this comment

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

Great! Changes are looking good, excited to see teams support for permissions 🙏

@harshithadurai harshithadurai merged commit 0ca1a46 into master Nov 6, 2024
50 of 51 checks passed
@harshithadurai harshithadurai deleted the harshi/ref/update-dashboard-perms-with-teams-backend branch November 6, 2024 19:00
harshithadurai added a commit that referenced this pull request Nov 8, 2024
…#80344)

Addresses: #79828 and #79833 
Corresponding backend change:
#80136

- Add teams as options to the `EditAccessSelector` component 
- Refactor use of `isCreatorOnlyEditable` to use  `isEditableByEveryone`
- Add `updateDashbaordPermissions()` function to make a separate `PUT`
request to dashboard details endpoint that sends only the perms object
- Rename 'Everyone' option to 'All users', and modify tests as well


Before:
<img width="200" alt="Screenshot 2024-11-07 at 10 26 47 AM"
src="https://github.com/user-attachments/assets/9aacc1d6-3002-439b-9a03-c39ec952b955">
After:
<img width="200" alt="Screenshot 2024-11-07 at 10 25 38 AM"
src="https://github.com/user-attachments/assets/1358752c-30e7-48d0-ba64-f36f15b183b3">

---------

Co-authored-by: harshithadurai <harshi.durai@esentry.io>
@github-actions github-actions bot locked and limited conversation to collaborators Nov 22, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Scope: Backend Automatically applied to PRs that change backend components Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants