mirror of
https://github.com/grafana/grafana.git
synced 2025-02-13 17:15:40 -06:00
Added PATCH verb end point for annotation op
Added new PATCH verb annotation endpoint Removed unwanted fmt Added test cases for PATCH verb annotation endpoint Fixed formatting issue Check arr len before proceeding Updated doc to include PATCH verb annotation endpt
This commit is contained in:
parent
57457e2aa4
commit
a7a964ec19
@ -160,15 +160,18 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
## Update Annotation
|
||||
## Replace Annotation
|
||||
|
||||
`PUT /api/annotations/:id`
|
||||
|
||||
Replaces the annotation that matches the specified id.
|
||||
|
||||
**Example Request**:
|
||||
|
||||
```json
|
||||
PUT /api/annotations/1141 HTTP/1.1
|
||||
Accept: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
@ -180,6 +183,28 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
## Update Annotation
|
||||
|
||||
`PATCH /api/annotations/:id`
|
||||
|
||||
Updates one or more properties of an annotation that matches the specified id.
|
||||
|
||||
**Example Request**:
|
||||
|
||||
```json
|
||||
PATCH /api/annotations/1145 HTTP/1.1
|
||||
Accept: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"time":1507037197000,
|
||||
"timeEnd":1507180807095,
|
||||
"text":"New Annotation Description",
|
||||
"tags":["tag6","tag7","tag8"]
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Annotation By Id
|
||||
|
||||
`DELETE /api/annotations/:id`
|
||||
|
@ -210,6 +210,65 @@ func UpdateAnnotation(c *m.ReqContext, cmd dtos.UpdateAnnotationsCmd) Response {
|
||||
return Success("Annotation updated")
|
||||
}
|
||||
|
||||
func PatchAnnotation(c *m.ReqContext, cmd dtos.PatchAnnotationsCmd) Response {
|
||||
annotationID := c.ParamsInt64(":annotationId")
|
||||
|
||||
repo := annotations.GetRepository()
|
||||
|
||||
if resp := canSave(c, repo, annotationID); resp != nil {
|
||||
return resp
|
||||
}
|
||||
|
||||
items, err := repo.Find(&annotations.ItemQuery{AnnotationId: annotationID, OrgId: c.OrgId})
|
||||
|
||||
if err != nil || len(items) == 0 {
|
||||
return Error(500, "Could not find annotation to update", err)
|
||||
}
|
||||
|
||||
existing := annotations.Item{
|
||||
OrgId: c.OrgId,
|
||||
UserId: c.UserId,
|
||||
Id: annotationID,
|
||||
Epoch: items[0].Time,
|
||||
Text: items[0].Text,
|
||||
Tags: items[0].Tags,
|
||||
RegionId: items[0].RegionId,
|
||||
}
|
||||
|
||||
if cmd.Tags != nil {
|
||||
existing.Tags = cmd.Tags
|
||||
}
|
||||
|
||||
if cmd.Text != "" && cmd.Text != existing.Text {
|
||||
existing.Text = cmd.Text
|
||||
}
|
||||
|
||||
if cmd.Time > 0 && cmd.Time != existing.Epoch {
|
||||
existing.Epoch = cmd.Time
|
||||
}
|
||||
|
||||
if err := repo.Update(&existing); err != nil {
|
||||
return Error(500, "Failed to update annotation", err)
|
||||
}
|
||||
|
||||
// Update region end time if provided
|
||||
if existing.RegionId != 0 && cmd.TimeEnd > 0 {
|
||||
itemRight := existing
|
||||
itemRight.RegionId = existing.Id
|
||||
itemRight.Epoch = cmd.TimeEnd
|
||||
|
||||
// We don't know id of region right event, so set it to 0 and find then using query like
|
||||
// ... WHERE region_id = <item.RegionId> AND id != <item.RegionId> ...
|
||||
itemRight.Id = 0
|
||||
|
||||
if err := repo.Update(&itemRight); err != nil {
|
||||
return Error(500, "Failed to update annotation for region end time", err)
|
||||
}
|
||||
}
|
||||
|
||||
return Success("Annotation patched")
|
||||
}
|
||||
|
||||
func DeleteAnnotations(c *m.ReqContext, cmd dtos.DeleteAnnotationsCmd) Response {
|
||||
repo := annotations.GetRepository()
|
||||
|
||||
|
@ -27,6 +27,12 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
|
||||
IsRegion: false,
|
||||
}
|
||||
|
||||
patchCmd := dtos.PatchAnnotationsCmd{
|
||||
Time: 1000,
|
||||
Text: "annotation text",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
}
|
||||
|
||||
Convey("When user is an Org Viewer", func() {
|
||||
role := m.ROLE_VIEWER
|
||||
Convey("Should not be allowed to save an annotation", func() {
|
||||
@ -40,6 +46,11 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
|
||||
patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteAnnotationByID
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
@ -67,6 +78,11 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
|
||||
patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteAnnotationByID
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
@ -100,6 +116,13 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
|
||||
Id: 1,
|
||||
}
|
||||
|
||||
patchCmd := dtos.PatchAnnotationsCmd{
|
||||
Time: 8000,
|
||||
Text: "annotation text 50",
|
||||
Tags: []string{"foo", "bar"},
|
||||
Id: 1,
|
||||
}
|
||||
|
||||
deleteCmd := dtos.DeleteAnnotationsCmd{
|
||||
DashboardId: 1,
|
||||
PanelId: 1,
|
||||
@ -136,6 +159,11 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
|
||||
patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteAnnotationByID
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
@ -163,6 +191,11 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
|
||||
patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteAnnotationByID
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
@ -189,6 +222,12 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
|
||||
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
|
||||
patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
|
||||
deleteAnnotationsScenario("When calling POST on", "/api/annotations/mass-delete", "/api/annotations/mass-delete", role, deleteCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
@ -264,6 +303,29 @@ func putAnnotationScenario(desc string, url string, routePattern string, role m.
|
||||
})
|
||||
}
|
||||
|
||||
func patchAnnotationScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.PatchAnnotationsCmd, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.OrgRole = role
|
||||
|
||||
return PatchAnnotation(c, cmd)
|
||||
})
|
||||
|
||||
fakeAnnoRepo = &fakeAnnotationsRepo{}
|
||||
annotations.SetRepository(fakeAnnoRepo)
|
||||
|
||||
sc.m.Patch(routePattern, sc.defaultHandler)
|
||||
|
||||
fn(sc)
|
||||
})
|
||||
}
|
||||
|
||||
func deleteAnnotationsScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.DeleteAnnotationsCmd, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
@ -354,6 +354,7 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
annotationsRoute.Post("/", bind(dtos.PostAnnotationsCmd{}), Wrap(PostAnnotation))
|
||||
annotationsRoute.Delete("/:annotationId", Wrap(DeleteAnnotationByID))
|
||||
annotationsRoute.Put("/:annotationId", bind(dtos.UpdateAnnotationsCmd{}), Wrap(UpdateAnnotation))
|
||||
annotationsRoute.Patch("/:annotationId", bind(dtos.PatchAnnotationsCmd{}), Wrap(PatchAnnotation))
|
||||
annotationsRoute.Delete("/region/:regionId", Wrap(DeleteAnnotationRegion))
|
||||
annotationsRoute.Post("/graphite", reqEditorRole, bind(dtos.PostGraphiteAnnotationsCmd{}), Wrap(PostGraphiteAnnotation))
|
||||
})
|
||||
|
@ -22,6 +22,14 @@ type UpdateAnnotationsCmd struct {
|
||||
TimeEnd int64 `json:"timeEnd"`
|
||||
}
|
||||
|
||||
type PatchAnnotationsCmd struct {
|
||||
Id int64 `json:"id"`
|
||||
Time int64 `json:"time"`
|
||||
Text string `json:"text"`
|
||||
Tags []string `json:"tags"`
|
||||
TimeEnd int64 `json:"timeEnd"`
|
||||
}
|
||||
|
||||
type DeleteAnnotationsCmd struct {
|
||||
AlertId int64 `json:"alertId"`
|
||||
DashboardId int64 `json:"dashboardId"`
|
||||
|
Loading…
Reference in New Issue
Block a user