From 51c72fcea2d729851ff9c56a2db48745715a86d2 Mon Sep 17 00:00:00 2001 From: Joey Orlando Date: Tue, 24 Sep 2024 15:16:22 -0400 Subject: [PATCH] feat: add Grafana IDs to users and teams public API endpoints (#5075) # What this PR does - add Grafana IDs to users and teams public API endpoints - update Schedules public API docs to reflect the fact that [we allow filtering by `team_id`](https://github.com/grafana/oncall/blob/dev/engine/apps/public_api/views/schedules.py#L42) ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] Added the relevant release notes label (see labels prefixed w/ `release:`). These labels dictate how your PR will show up in the autogenerated release notes. --- .../sources/oncall-api-reference/schedules.md | 1 + docs/sources/oncall-api-reference/teams.md | 15 +++++++----- docs/sources/oncall-api-reference/users.md | 21 +++++++++-------- engine/apps/public_api/serializers/teams.py | 9 +++++++- engine/apps/public_api/serializers/users.py | 23 +++++++++++++++++-- engine/apps/public_api/tests/test_teams.py | 2 ++ engine/apps/public_api/tests/test_users.py | 6 +++++ 7 files changed, 59 insertions(+), 18 deletions(-) diff --git a/docs/sources/oncall-api-reference/schedules.md b/docs/sources/oncall-api-reference/schedules.md index 4193c26b1b..57dfdf1d7e 100644 --- a/docs/sources/oncall-api-reference/schedules.md +++ b/docs/sources/oncall-api-reference/schedules.md @@ -150,6 +150,7 @@ The above command returns JSON structured in the following way: The following available filter parameter should be provided as a `GET` argument: - `name` (Exact match) +- `team_id` (Exact match, team ID) **HTTP request** diff --git a/docs/sources/oncall-api-reference/teams.md b/docs/sources/oncall-api-reference/teams.md index 802e39d9ae..04e001ae2d 100644 --- a/docs/sources/oncall-api-reference/teams.md +++ b/docs/sources/oncall-api-reference/teams.md @@ -28,6 +28,7 @@ The above command returns JSON structured in the following way: ```json { "id": "TI73TDU19W48J", + "grafana_id": 123, "name": "my test team", "email": "", "avatar_url": "/avatar/3f49c15916554246daa714b9bd0ee398" @@ -38,12 +39,13 @@ The above command returns JSON structured in the following way: `GET {{API_URL}}/api/v1/teams//` -| Parameter | Unique | Description | -| ---------- | :-----: | :----------------------------------------------------------------- | -| `id` | Yes/org | Team ID | -| `name` | Yes/org | Team name | -| `email` | Yes/org | Team e-mail | -| `avatar_url` | Yes | Avatar URL of the Grafana team | +| Parameter | Unique | Description | +| ----------------- | :-----: | :----------------------------- | +| `id` | Yes/org | OnCall team ID | +| `grafana_id` | Yes/org | Grafana team ID | +| `name` | Yes/org | Team name | +| `email` | Yes/org | Team e-mail | +| `avatar_url` | Yes | Avatar URL of the Grafana team | ## List Teams @@ -64,6 +66,7 @@ The above command returns JSON structured in the following way: "results": [ { "id": "TI73TDU19W48J", + "grafana_id": 123, "name": "my test team", "email": "", "avatar_url": "/avatar/3f49c15916554246daa714b9bd0ee398" diff --git a/docs/sources/oncall-api-reference/users.md b/docs/sources/oncall-api-reference/users.md index 6d15b3dbef..f7421a7781 100644 --- a/docs/sources/oncall-api-reference/users.md +++ b/docs/sources/oncall-api-reference/users.md @@ -28,6 +28,7 @@ The above command returns JSON structured in the following way: ```json { "id": "U4DNY931HHJS5", + "grafana_id": 456, "email": "public-api-demo-user-1@grafana.com", "slack": [ { @@ -48,15 +49,16 @@ The above command returns JSON structured in the following way: Use `{{API_URL}}/api/v1/users/current` to retrieve the current user. -| Parameter | Unique | Description | -| ---------- | :-----: | :----------------------------------------------------------------- | -| `id` | Yes/org | User ID | -| `email` | Yes/org | User e-mail | -| `slack` | Yes/org | List of user IDs from connected Slack. User linking key is e-mail. | -| `username` | Yes/org | User username | -| `role` | No | One of: `user`, `observer`, `admin`. | -| `timezone` | No | timezone of the user one of [time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). | -| `teams` | No | List of team IDs the user belongs to | +| Parameter | Unique | Description | +| ----------------- | :-----: | :----------------------------------------------------------------- | +| `id` | Yes/org | OnCall user ID | +| `grafana_id` | Yes/org | Grafana user ID | +| `email` | Yes/org | User e-mail | +| `slack` | Yes/org | List of user IDs from connected Slack. User linking key is e-mail. | +| `username` | Yes/org | User username | +| `role` | No | One of: `user`, `observer`, `admin`. | +| `timezone` | No | timezone of the user one of [time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). | +| `teams` | No | List of team IDs the user belongs to | ## List Users @@ -77,6 +79,7 @@ The above command returns JSON structured in the following way: "results": [ { "id": "U4DNY931HHJS5", + "grafana_id": 456, "email": "public-api-demo-user-1@grafana.com", "slack": [ { diff --git a/engine/apps/public_api/serializers/teams.py b/engine/apps/public_api/serializers/teams.py index 04c36c0088..d448a282c4 100644 --- a/engine/apps/public_api/serializers/teams.py +++ b/engine/apps/public_api/serializers/teams.py @@ -5,7 +5,14 @@ class TeamSerializer(serializers.ModelSerializer): id = serializers.CharField(read_only=True, source="public_primary_key") + grafana_id = serializers.IntegerField(read_only=True, source="team_id") class Meta: model = Team - fields = ("id", "name", "email", "avatar_url") + fields = [ + "id", + "grafana_id", + "name", + "email", + "avatar_url", + ] diff --git a/engine/apps/public_api/serializers/users.py b/engine/apps/public_api/serializers/users.py index de0a2fecea..dfe48aa868 100644 --- a/engine/apps/public_api/serializers/users.py +++ b/engine/apps/public_api/serializers/users.py @@ -20,13 +20,21 @@ class Meta: class FastUserSerializer(serializers.ModelSerializer): id: str = serializers.ReadOnlyField(read_only=True, source="public_primary_key") + grafana_id: int = serializers.IntegerField(read_only=True, source="user_id") email: str = serializers.EmailField(read_only=True) role: str = serializers.SerializerMethodField() # LEGACY, should be removed eventually is_phone_number_verified: bool = serializers.SerializerMethodField() class Meta: model = User - fields = ["id", "email", "username", "role", "is_phone_number_verified"] + fields = [ + "id", + "grafana_id", + "email", + "username", + "role", + "is_phone_number_verified", + ] @staticmethod def get_role(obj: User) -> str: @@ -41,6 +49,7 @@ def get_is_phone_number_verified(self, obj: User) -> bool: class UserSerializer(serializers.ModelSerializer, EagerLoadingMixin): id: str = serializers.ReadOnlyField(read_only=True, source="public_primary_key") + grafana_id: int = serializers.IntegerField(read_only=True, source="user_id") email: str = serializers.EmailField(read_only=True) slack: SlackUserIdentity = SlackUserIdentitySerializer(read_only=True, source="slack_user_identity") role: str = serializers.SerializerMethodField() # LEGACY, should be removed eventually @@ -55,7 +64,17 @@ class UserSerializer(serializers.ModelSerializer, EagerLoadingMixin): class Meta: model = User - fields = ["id", "email", "slack", "username", "role", "is_phone_number_verified", "timezone", "teams"] + fields = [ + "id", + "grafana_id", + "email", + "slack", + "username", + "role", + "is_phone_number_verified", + "timezone", + "teams", + ] read_only_fields = ["timezone"] @staticmethod diff --git a/engine/apps/public_api/tests/test_teams.py b/engine/apps/public_api/tests/test_teams.py index ce31993ec9..f59cc5e5d6 100644 --- a/engine/apps/public_api/tests/test_teams.py +++ b/engine/apps/public_api/tests/test_teams.py @@ -33,6 +33,7 @@ def test_get_teams_list(team_public_api_setup): "results": [ { "id": team.public_primary_key, + "grafana_id": team.team_id, "name": team.name, "email": team.email, "avatar_url": team.avatar_url, @@ -59,6 +60,7 @@ def test_get_team(team_public_api_setup): expected_payload = { "id": team.public_primary_key, + "grafana_id": team.team_id, "name": team.name, "email": team.email, "avatar_url": team.avatar_url, diff --git a/engine/apps/public_api/tests/test_users.py b/engine/apps/public_api/tests/test_users.py index 3c7cd54267..d381849d58 100644 --- a/engine/apps/public_api/tests/test_users.py +++ b/engine/apps/public_api/tests/test_users.py @@ -29,6 +29,7 @@ def test_get_user( expected_response = { "id": user.public_primary_key, + "grafana_id": user.user_id, "email": user.email, "slack": {"user_id": slack_user_identity.slack_id, "team_id": slack_team_identity.slack_id}, "username": user.username, @@ -72,6 +73,7 @@ def test_get_users_list( "results": [ { "id": user_1.public_primary_key, + "grafana_id": user_1.user_id, "email": user_1.email, "slack": {"user_id": slack_user_identity.slack_id, "team_id": slack_team_identity.slack_id}, "username": user_1.username, @@ -82,6 +84,7 @@ def test_get_users_list( }, { "id": user_2.public_primary_key, + "grafana_id": user_2.user_id, "email": user_2.email, "slack": None, "username": user_2.username, @@ -120,6 +123,7 @@ def test_get_users_list_short( "results": [ { "id": user_1.public_primary_key, + "grafana_id": user_1.user_id, "email": user_1.email, "username": user_1.username, "role": "admin", @@ -127,6 +131,7 @@ def test_get_users_list_short( }, { "id": user_2.public_primary_key, + "grafana_id": user_2.user_id, "email": user_2.email, "username": user_2.username, "role": "admin", @@ -178,6 +183,7 @@ def test_get_users_list_all_role_users(user_public_api_setup, make_user_for_orga "results": [ { "id": user.public_primary_key, + "grafana_id": user.user_id, "email": user.email, "username": user.username, "role": role,