Resolution notes endpoint docs (#2404)

# What this PR does
- Add docs for `/resolution_notes` public api endpoint
- Fix resolution notes order to show notes for the newest alert group on
top

## Which issue(s) this PR fixes
https://github.com/grafana/oncall/issues/222

## 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] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required)
This commit is contained in:
Yulya Artyukhina 2023-06-29 16:08:21 +02:00 committed by GitHub
parent cc20c9dfdd
commit 04047c6ebe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 177 deletions

View file

@ -7,9 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
### Added
- Docs for `/resolution_notes` public api endpoint [#222](https://github.com/grafana/oncall/issues/222)
### Fixed
- Change alerts order for `/alert` public api endpoint [#1031](https://github.com/grafana/oncall/issues/1031)
- Change resolution notes order for `/resolution_notes` public api endpoint to show notes for the newest alert group
on top ([#2404](https://github.com/grafana/oncall/pull/2404))
## v1.3.2 (2023-06-29)

View file

@ -1,152 +0,0 @@
---
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/postmortems/
draft: true
title: Postmortem HTTP API
weight: 1000
---
# Create a postmortem
```shell
curl "{{API_URL}}/api/v1/postmortems/" \
--request POST \
--header "Authorization: meowmeowmeow" \
--header "Content-Type: application/json" \
--data '{
"alert_group_id": "I68T24C13IFW1",
"text": "Demo postmortem text"
}'
```
The above command returns JSON structured in the following way:
```json
{
"id": "P658FE5K87EWZ",
"alert_group_id": "I68T24C13IFW1",
"created_at": "2020-06-19T12:37:01.430444Z",
"text": "Demo postmortem text"
}
```
**HTTP request**
`POST {{API_URL}}/api/v1/postmortems/`
# Get a postmortem
```shell
curl "{{API_URL}}/api/v1/postmortems/P658FE5K87EWZ/" \
--request GET \
--header "Authorization: meowmeowmeow" \
--header "Content-Type: application/json"
```
The above command returns JSON structured in the following way:
```json
{
"id": "P658FE5K87EWZ",
"alert_group_id": "I68T24C13IFW1",
"created_at": "2020-06-19T12:37:01.430444Z",
"text": "Demo postmortem text",
"postmortem_messages": [
{
"id": "M4BTQUS3PRHYQ",
"alert_group_id": "I68T24C13IFW1",
"author": "U4DNY931HHJS5",
"source": "web",
"created_at": "2020-06-19T12:40:01.429805Z",
"text": "Demo postmortem message"
}
]
}
```
**HTTP request**
`GET {{API_URL}}/api/v1/postmortems/<POSTMORTEM_ID>/`
# List postmortems
```shell
curl "{{API_URL}}/api/v1/postmortems/" \
--request GET \
--header "Authorization: meowmeowmeow" \
--header "Content-Type: application/json"
```
The above command returns JSON structured in the following way:
```json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "P658FE5K87EWZ",
"alert_group_id": "I68T24C13IFW1",
"created_at": "2020-06-19T12:37:01.430444Z",
"text": "Demo postmortem text",
"postmortem_messages": [
{
"id": "M4BTQUS3PRHYQ",
"alert_group_id": "I68T24C13IFW1",
"author": "U4DNY931HHJS5",
"source": "web",
"created_at": "2020-06-19T12:40:01.429805Z",
"text": "Demo postmortem message"
}
]
}
]
}
```
The following available filter parameter should be provided with a `GET` argument:
- `alert_group_id`
**HTTP request**
`GET {{API_URL}}/api/v1/postmortems/`
# Update a postmortem
```shell
curl "{{API_URL}}/api/v1/postmortems/P658FE5K87EWZ/" \
--request PUT \
--header "Authorization: meowmeowmeow" \
--header "Content-Type: application/json" \
--data '{
"text": "Demo postmortem text"
}'
```
The above command returns JSON structured in the following way:
```json
{
"id": "P658FE5K87EWZ",
"alert_group_id": "I68T24C13IFW1",
"created_at": "2020-06-19T12:37:01.430444Z",
"text": "Demo postmortem text"
}
```
**HTTP request**
`PUT {{API_URL}}/api/v1/postmortems/<POSTMORTEM_ID>/`
# Delete a postmortem
```shell
curl "{{API_URL}}/api/v1/postmortems/P658FE5K87EWZ/" \
--request DELETE \
--header "Authorization: meowmeowmeow"
```
**HTTP request**
`DELETE {{API_URL}}/api/v1/postmortems/<POSTMORTEM_ID>/`

View file

@ -1,20 +1,19 @@
---
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/postmortem_messages/
draft: true
title: Postmortem Messages HTTP API
canonical: https://grafana.com/docs/oncall/latest/oncall-api-reference/resolution_notes/
title: Resolution Notes HTTP API
weight: 900
---
# Create a postmortem message
# Create a resolution note
```shell
curl "{{API_URL}}/api/v1/postmortem_messages/" \
curl "{{API_URL}}/api/v1/resolution_notes/" \
--request POST \
--header "Authorization: meowmeowmeow" \
--header "Content-Type: application/json" \
--data '{
"alert_group_id": "I68T24C13IFW1",
"text": "Demo postmortem message"
"text": "Demo resolution note"
}'
```
@ -27,18 +26,23 @@ The above command returns JSON structured in the following way:
"author": "U4DNY931HHJS5",
"source": "web",
"created_at": "2020-06-19T12:40:01.429805Z",
"text": "Demo postmortem message"
"text": "Demo resolution note"
}
```
| Parameter | Required | Description |
| --------------- | :------: | :--------------------- |
| `alert_group_id`| Yes | Alert group ID | |
| `text` | Yes | Resolution note text |
**HTTP request**
`POST {{API_URL}}/api/v1/postmortem_messages/`
`POST {{API_URL}}/api/v1/resolution_notes/`
# Get a postmortem message
# Get a resolution note
```shell
curl "{{API_URL}}/api/v1/postmortem_messages/M4BTQUS3PRHYQ/" \
curl "{{API_URL}}/api/v1/resolution_notes/M4BTQUS3PRHYQ/" \
--request GET \
--header "Authorization: meowmeowmeow" \
--header "Content-Type: application/json"
@ -53,18 +57,18 @@ The above command returns JSON structured in the following way:
"author": "U4DNY931HHJS5",
"source": "web",
"created_at": "2020-06-19T12:40:01.429805Z",
"text": "Demo postmortem message"
"text": "Demo resolution note"
}
```
**HTTP request**
`GET {{API_URL}}/api/v1/postmortem_messages/<POSTMORTEM_MESSAGE_ID>/`
`GET {{API_URL}}/api/v1/resolution_notes/<RESOLUTION_NOTE_ID>/`
# List postmortem messages
# List resolution notes
```shell
curl "{{API_URL}}/api/v1/postmortem_messages/" \
curl "{{API_URL}}/api/v1/resolution_notes/" \
--request GET \
--header "Authorization: meowmeowmeow" \
--header "Content-Type: application/json"
@ -84,7 +88,7 @@ The above command returns JSON structured in the following way:
"author": "U4DNY931HHJS5",
"source": "web",
"created_at": "2020-06-19T12:40:01.429805Z",
"text": "Demo postmortem message"
"text": "Demo resolution note"
}
]
}
@ -96,17 +100,17 @@ The following available filter parameter should be provided as a `GET` argument:
**HTTP request**
`GET {{API_URL}}/api/v1/postmortem_messages/`
`GET {{API_URL}}/api/v1/resolution_notes/`
# Update a postmortem message
# Update a resolution note
```shell
curl "{{API_URL}}/api/v1/postmortem_messages/M4BTQUS3PRHYQ/" \
curl "{{API_URL}}/api/v1/resolution_notes/M4BTQUS3PRHYQ/" \
--request PUT \
--header "Authorization: meowmeowmeow" \
--header "Content-Type: application/json" \
--data '{
"text": "Demo postmortem message"
"text": "Demo resolution note updated"
}'
```
@ -119,22 +123,22 @@ The above command returns JSON structured in the following way:
"author": "U4DNY931HHJS5",
"source": "web",
"created_at": "2020-06-19T12:40:01.429805Z",
"text": "Demo postmortem message"
"text": "Demo resolution note updated"
}
```
**HTTP request**
`PUT {{API_URL}}/api/v1/postmortem_messages/<POSTMORTEM_MESSAGE_ID>/`
`PUT {{API_URL}}/api/v1/resolution_notes/<RESOLUTION_NOTE_ID>/`
# Delete a postmortem message
# Delete a resolution note
```shell
curl "{{API_URL}}/api/v1/postmortem_messages/M4BTQUS3PRHYQ/" \
curl "{{API_URL}}/api/v1/resolution_notes/M4BTQUS3PRHYQ/" \
--request DELETE \
--header "Authorization: meowmeowmeow"
```
**HTTP request**
`DELETE {{API_URL}}/api/v1/postmortem_messages/<POSTMORTEM_MESSAGE_ID>/`
`DELETE {{API_URL}}/api/v1/resolution_notes/<RESOLUTION_NOTE_ID>/`

View file

@ -6,6 +6,63 @@ from rest_framework.test import APIClient
from apps.alerts.models import ResolutionNote
@pytest.mark.django_db
def test_get_resolution_notes(
make_organization_and_user_with_token,
make_alert_receive_channel,
make_alert_group,
make_resolution_note,
):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()
alert_receive_channel = make_alert_receive_channel(organization)
alert_group_1 = make_alert_group(alert_receive_channel)
alert_group_2 = make_alert_group(alert_receive_channel)
resolution_note_1 = make_resolution_note(
alert_group=alert_group_1,
source=ResolutionNote.Source.WEB,
author=user,
)
resolution_note_2 = make_resolution_note(
alert_group=alert_group_2,
source=ResolutionNote.Source.WEB,
author=user,
)
url = reverse("api-public:resolution_notes-list")
response = client.get(url, format="json", HTTP_AUTHORIZATION=f"{token}")
expected_response = {
"count": 2,
"next": None,
"previous": None,
"results": [
{
"id": resolution_note_2.public_primary_key,
"alert_group_id": alert_group_2.public_primary_key,
"author": user.public_primary_key,
"source": resolution_note_2.get_source_display(),
"created_at": resolution_note_2.created_at.isoformat().replace("+00:00", "Z"),
"text": resolution_note_2.text,
},
{
"id": resolution_note_1.public_primary_key,
"alert_group_id": alert_group_1.public_primary_key,
"author": user.public_primary_key,
"source": resolution_note_1.get_source_display(),
"created_at": resolution_note_1.created_at.isoformat().replace("+00:00", "Z"),
"text": resolution_note_1.text,
},
],
}
assert response.status_code == status.HTTP_200_OK
assert response.json() == expected_response
@pytest.mark.django_db
def test_get_resolution_note(
make_organization_and_user_with_token,

View file

@ -35,7 +35,7 @@ class ResolutionNoteView(RateLimitHeadersMixin, UpdateSerializerMixin, ModelView
queryset = self.serializer_class.setup_eager_loading(queryset)
if alert_group_id:
queryset = queryset.filter(alert_group__public_primary_key=alert_group_id)
return queryset.order_by("alert_group__started_at")
return queryset.order_by("-alert_group__started_at")
def get_object(self):
public_primary_key = self.kwargs["pk"]