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.
This commit is contained in:
Joey Orlando 2024-09-24 15:16:22 -04:00 committed by GitHub
parent fc58aaad20
commit 51c72fcea2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 59 additions and 18 deletions

View file

@ -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**

View file

@ -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/<TEAM_ID>/`
| 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"

View file

@ -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": [
{

View file

@ -5,7 +5,14 @@ from apps.user_management.models import Team
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",
]

View file

@ -20,13 +20,21 @@ class SlackUserIdentitySerializer(serializers.ModelSerializer):
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 @@ class FastUserSerializer(serializers.ModelSerializer):
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

View file

@ -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,

View file

@ -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,