Skip to content

Commit c35c1d7

Browse files
Merge branch 'master' of https://github.com/grafana/grafana into macros/sql
2 parents 105b3d6 + 175e95a commit c35c1d7

File tree

19 files changed

+268
-60
lines changed

19 files changed

+268
-60
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,18 @@
33
* **Dataproxy**: Pass configured/auth headers to a Datasource [#10971](https://github.com/grafana/grafana/issues/10971), thx [@mrsiano](https://github.com/mrsiano)
44
* **Cleanup**: Make temp file time to live configurable [#11607](https://github.com/grafana/grafana/issues/11607), thx [@xapon](https://github.com/xapon)
55

6+
### Minor
7+
8+
* **Api**: Delete nonexistent datasource should return 404 [#12313](https://github.com/grafana/grafana/issues/12313), thx [@AustinWinstanley](https://github.com/AustinWinstanley)
9+
* **Dashboard**: Fix selecting current dashboard from search should not reload dashboard [#12248](https://github.com/grafana/grafana/issues/12248)
10+
611
# 5.2.0 (unreleased)
712

13+
### Minor
14+
15+
* **Plugins**: Handle errors correctly when loading datasource plugin [#12383](https://github.com/grafana/grafana/pull/12383) thx [@rozetko](https://github.com/rozetko)
16+
* **Render**: Enhance error message if phantomjs executable is not found [#11868](https://github.com/grafana/grafana/issues/11868)
17+
818
# 5.2.0-beta3 (2018-06-21)
919

1020
### Minor

pkg/api/annotations.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ func GetAnnotations(c *m.ReqContext) Response {
3737
if item.Email != "" {
3838
item.AvatarUrl = dtos.GetGravatarUrl(item.Email)
3939
}
40-
item.Time = item.Time
4140
}
4241

4342
return JSON(200, items)
@@ -214,7 +213,9 @@ func DeleteAnnotations(c *m.ReqContext, cmd dtos.DeleteAnnotationsCmd) Response
214213
repo := annotations.GetRepository()
215214

216215
err := repo.Delete(&annotations.DeleteParams{
217-
AlertId: cmd.PanelId,
216+
OrgId: c.OrgId,
217+
Id: cmd.AnnotationId,
218+
RegionId: cmd.RegionId,
218219
DashboardId: cmd.DashboardId,
219220
PanelId: cmd.PanelId,
220221
})
@@ -235,7 +236,8 @@ func DeleteAnnotationByID(c *m.ReqContext) Response {
235236
}
236237

237238
err := repo.Delete(&annotations.DeleteParams{
238-
Id: annotationID,
239+
OrgId: c.OrgId,
240+
Id: annotationID,
239241
})
240242

241243
if err != nil {
@@ -254,6 +256,7 @@ func DeleteAnnotationRegion(c *m.ReqContext) Response {
254256
}
255257

256258
err := repo.Delete(&annotations.DeleteParams{
259+
OrgId: c.OrgId,
257260
RegionId: regionID,
258261
})
259262

pkg/api/annotations_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
100100
Id: 1,
101101
}
102102

103+
deleteCmd := dtos.DeleteAnnotationsCmd{
104+
DashboardId: 1,
105+
PanelId: 1,
106+
}
107+
103108
viewerRole := m.ROLE_VIEWER
104109
editorRole := m.ROLE_EDITOR
105110

@@ -171,6 +176,25 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
171176
})
172177
})
173178
})
179+
180+
Convey("When user is an Admin", func() {
181+
role := m.ROLE_ADMIN
182+
Convey("Should be able to do anything", func() {
183+
postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
184+
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
185+
So(sc.resp.Code, ShouldEqual, 200)
186+
})
187+
188+
putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
189+
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
190+
So(sc.resp.Code, ShouldEqual, 200)
191+
})
192+
deleteAnnotationsScenario("When calling POST on", "/api/annotations/mass-delete", "/api/annotations/mass-delete", role, deleteCmd, func(sc *scenarioContext) {
193+
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
194+
So(sc.resp.Code, ShouldEqual, 200)
195+
})
196+
})
197+
})
174198
})
175199
}
176200

@@ -239,3 +263,26 @@ func putAnnotationScenario(desc string, url string, routePattern string, role m.
239263
fn(sc)
240264
})
241265
}
266+
267+
func deleteAnnotationsScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.DeleteAnnotationsCmd, fn scenarioFunc) {
268+
Convey(desc+" "+url, func() {
269+
defer bus.ClearBusHandlers()
270+
271+
sc := setupScenarioContext(url)
272+
sc.defaultHandler = wrap(func(c *m.ReqContext) Response {
273+
sc.context = c
274+
sc.context.UserId = TestUserID
275+
sc.context.OrgId = TestOrgID
276+
sc.context.OrgRole = role
277+
278+
return DeleteAnnotations(c, cmd)
279+
})
280+
281+
fakeAnnoRepo = &fakeAnnotationsRepo{}
282+
annotations.SetRepository(fakeAnnoRepo)
283+
284+
sc.m.Post(routePattern, sc.defaultHandler)
285+
286+
fn(sc)
287+
})
288+
}

pkg/api/api.go

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"github.com/go-macaron/binding"
55
"github.com/grafana/grafana/pkg/api/avatar"
66
"github.com/grafana/grafana/pkg/api/dtos"
7+
"github.com/grafana/grafana/pkg/api/routing"
78
"github.com/grafana/grafana/pkg/middleware"
89
m "github.com/grafana/grafana/pkg/models"
910
)
@@ -117,10 +118,10 @@ func (hs *HTTPServer) registerRoutes() {
117118
r.Get("/api/login/ping", quota("session"), LoginAPIPing)
118119

119120
// authed api
120-
r.Group("/api", func(apiRoute RouteRegister) {
121+
r.Group("/api", func(apiRoute routing.RouteRegister) {
121122

122123
// user (signed in)
123-
apiRoute.Group("/user", func(userRoute RouteRegister) {
124+
apiRoute.Group("/user", func(userRoute routing.RouteRegister) {
124125
userRoute.Get("/", wrap(GetSignedInUser))
125126
userRoute.Put("/", bind(m.UpdateUserCommand{}), wrap(UpdateSignedInUser))
126127
userRoute.Post("/using/:id", wrap(UserSetUsingOrg))
@@ -140,7 +141,7 @@ func (hs *HTTPServer) registerRoutes() {
140141
})
141142

142143
// users (admin permission required)
143-
apiRoute.Group("/users", func(usersRoute RouteRegister) {
144+
apiRoute.Group("/users", func(usersRoute routing.RouteRegister) {
144145
usersRoute.Get("/", wrap(SearchUsers))
145146
usersRoute.Get("/search", wrap(SearchUsersWithPaging))
146147
usersRoute.Get("/:id", wrap(GetUserByID))
@@ -152,7 +153,7 @@ func (hs *HTTPServer) registerRoutes() {
152153
}, reqGrafanaAdmin)
153154

154155
// team (admin permission required)
155-
apiRoute.Group("/teams", func(teamsRoute RouteRegister) {
156+
apiRoute.Group("/teams", func(teamsRoute routing.RouteRegister) {
156157
teamsRoute.Post("/", bind(m.CreateTeamCommand{}), wrap(CreateTeam))
157158
teamsRoute.Put("/:teamId", bind(m.UpdateTeamCommand{}), wrap(UpdateTeam))
158159
teamsRoute.Delete("/:teamId", wrap(DeleteTeamByID))
@@ -162,19 +163,19 @@ func (hs *HTTPServer) registerRoutes() {
162163
}, reqOrgAdmin)
163164

164165
// team without requirement of user to be org admin
165-
apiRoute.Group("/teams", func(teamsRoute RouteRegister) {
166+
apiRoute.Group("/teams", func(teamsRoute routing.RouteRegister) {
166167
teamsRoute.Get("/:teamId", wrap(GetTeamByID))
167168
teamsRoute.Get("/search", wrap(SearchTeams))
168169
})
169170

170171
// org information available to all users.
171-
apiRoute.Group("/org", func(orgRoute RouteRegister) {
172+
apiRoute.Group("/org", func(orgRoute routing.RouteRegister) {
172173
orgRoute.Get("/", wrap(GetOrgCurrent))
173174
orgRoute.Get("/quotas", wrap(GetOrgQuotas))
174175
})
175176

176177
// current org
177-
apiRoute.Group("/org", func(orgRoute RouteRegister) {
178+
apiRoute.Group("/org", func(orgRoute routing.RouteRegister) {
178179
orgRoute.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrgCurrent))
179180
orgRoute.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddressCurrent))
180181
orgRoute.Post("/users", quota("user"), bind(m.AddOrgUserCommand{}), wrap(AddOrgUserToCurrentOrg))
@@ -192,7 +193,7 @@ func (hs *HTTPServer) registerRoutes() {
192193
}, reqOrgAdmin)
193194

194195
// current org without requirement of user to be org admin
195-
apiRoute.Group("/org", func(orgRoute RouteRegister) {
196+
apiRoute.Group("/org", func(orgRoute routing.RouteRegister) {
196197
orgRoute.Get("/users", wrap(GetOrgUsersForCurrentOrg))
197198
})
198199

@@ -203,7 +204,7 @@ func (hs *HTTPServer) registerRoutes() {
203204
apiRoute.Get("/orgs", reqGrafanaAdmin, wrap(SearchOrgs))
204205

205206
// orgs (admin routes)
206-
apiRoute.Group("/orgs/:orgId", func(orgsRoute RouteRegister) {
207+
apiRoute.Group("/orgs/:orgId", func(orgsRoute routing.RouteRegister) {
207208
orgsRoute.Get("/", wrap(GetOrgByID))
208209
orgsRoute.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrg))
209210
orgsRoute.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddress))
@@ -217,24 +218,24 @@ func (hs *HTTPServer) registerRoutes() {
217218
}, reqGrafanaAdmin)
218219

219220
// orgs (admin routes)
220-
apiRoute.Group("/orgs/name/:name", func(orgsRoute RouteRegister) {
221+
apiRoute.Group("/orgs/name/:name", func(orgsRoute routing.RouteRegister) {
221222
orgsRoute.Get("/", wrap(GetOrgByName))
222223
}, reqGrafanaAdmin)
223224

224225
// auth api keys
225-
apiRoute.Group("/auth/keys", func(keysRoute RouteRegister) {
226+
apiRoute.Group("/auth/keys", func(keysRoute routing.RouteRegister) {
226227
keysRoute.Get("/", wrap(GetAPIKeys))
227228
keysRoute.Post("/", quota("api_key"), bind(m.AddApiKeyCommand{}), wrap(AddAPIKey))
228229
keysRoute.Delete("/:id", wrap(DeleteAPIKey))
229230
}, reqOrgAdmin)
230231

231232
// Preferences
232-
apiRoute.Group("/preferences", func(prefRoute RouteRegister) {
233+
apiRoute.Group("/preferences", func(prefRoute routing.RouteRegister) {
233234
prefRoute.Post("/set-home-dash", bind(m.SavePreferencesCommand{}), wrap(SetHomeDashboard))
234235
})
235236

236237
// Data sources
237-
apiRoute.Group("/datasources", func(datasourceRoute RouteRegister) {
238+
apiRoute.Group("/datasources", func(datasourceRoute routing.RouteRegister) {
238239
datasourceRoute.Get("/", wrap(GetDataSources))
239240
datasourceRoute.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), wrap(AddDataSource))
240241
datasourceRoute.Put("/:id", bind(m.UpdateDataSourceCommand{}), wrap(UpdateDataSource))
@@ -250,7 +251,7 @@ func (hs *HTTPServer) registerRoutes() {
250251
apiRoute.Get("/plugins/:pluginId/settings", wrap(GetPluginSettingByID))
251252
apiRoute.Get("/plugins/:pluginId/markdown/:name", wrap(GetPluginMarkdown))
252253

253-
apiRoute.Group("/plugins", func(pluginRoute RouteRegister) {
254+
apiRoute.Group("/plugins", func(pluginRoute routing.RouteRegister) {
254255
pluginRoute.Get("/:pluginId/dashboards/", wrap(GetPluginDashboards))
255256
pluginRoute.Post("/:pluginId/settings", bind(m.UpdatePluginSettingCmd{}), wrap(UpdatePluginSetting))
256257
}, reqOrgAdmin)
@@ -260,25 +261,25 @@ func (hs *HTTPServer) registerRoutes() {
260261
apiRoute.Any("/datasources/proxy/:id", reqSignedIn, hs.ProxyDataSourceRequest)
261262

262263
// Folders
263-
apiRoute.Group("/folders", func(folderRoute RouteRegister) {
264+
apiRoute.Group("/folders", func(folderRoute routing.RouteRegister) {
264265
folderRoute.Get("/", wrap(GetFolders))
265266
folderRoute.Get("/id/:id", wrap(GetFolderByID))
266267
folderRoute.Post("/", bind(m.CreateFolderCommand{}), wrap(CreateFolder))
267268

268-
folderRoute.Group("/:uid", func(folderUidRoute RouteRegister) {
269+
folderRoute.Group("/:uid", func(folderUidRoute routing.RouteRegister) {
269270
folderUidRoute.Get("/", wrap(GetFolderByUID))
270271
folderUidRoute.Put("/", bind(m.UpdateFolderCommand{}), wrap(UpdateFolder))
271272
folderUidRoute.Delete("/", wrap(DeleteFolder))
272273

273-
folderUidRoute.Group("/permissions", func(folderPermissionRoute RouteRegister) {
274+
folderUidRoute.Group("/permissions", func(folderPermissionRoute routing.RouteRegister) {
274275
folderPermissionRoute.Get("/", wrap(GetFolderPermissionList))
275276
folderPermissionRoute.Post("/", bind(dtos.UpdateDashboardAclCommand{}), wrap(UpdateFolderPermissions))
276277
})
277278
})
278279
})
279280

280281
// Dashboard
281-
apiRoute.Group("/dashboards", func(dashboardRoute RouteRegister) {
282+
apiRoute.Group("/dashboards", func(dashboardRoute routing.RouteRegister) {
282283
dashboardRoute.Get("/uid/:uid", wrap(GetDashboard))
283284
dashboardRoute.Delete("/uid/:uid", wrap(DeleteDashboardByUID))
284285

@@ -292,25 +293,25 @@ func (hs *HTTPServer) registerRoutes() {
292293
dashboardRoute.Get("/tags", GetDashboardTags)
293294
dashboardRoute.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard))
294295

295-
dashboardRoute.Group("/id/:dashboardId", func(dashIdRoute RouteRegister) {
296+
dashboardRoute.Group("/id/:dashboardId", func(dashIdRoute routing.RouteRegister) {
296297
dashIdRoute.Get("/versions", wrap(GetDashboardVersions))
297298
dashIdRoute.Get("/versions/:id", wrap(GetDashboardVersion))
298299
dashIdRoute.Post("/restore", bind(dtos.RestoreDashboardVersionCommand{}), wrap(RestoreDashboardVersion))
299300

300-
dashIdRoute.Group("/permissions", func(dashboardPermissionRoute RouteRegister) {
301+
dashIdRoute.Group("/permissions", func(dashboardPermissionRoute routing.RouteRegister) {
301302
dashboardPermissionRoute.Get("/", wrap(GetDashboardPermissionList))
302303
dashboardPermissionRoute.Post("/", bind(dtos.UpdateDashboardAclCommand{}), wrap(UpdateDashboardPermissions))
303304
})
304305
})
305306
})
306307

307308
// Dashboard snapshots
308-
apiRoute.Group("/dashboard/snapshots", func(dashboardRoute RouteRegister) {
309+
apiRoute.Group("/dashboard/snapshots", func(dashboardRoute routing.RouteRegister) {
309310
dashboardRoute.Get("/", wrap(SearchDashboardSnapshots))
310311
})
311312

312313
// Playlist
313-
apiRoute.Group("/playlists", func(playlistRoute RouteRegister) {
314+
apiRoute.Group("/playlists", func(playlistRoute routing.RouteRegister) {
314315
playlistRoute.Get("/", wrap(SearchPlaylists))
315316
playlistRoute.Get("/:id", ValidateOrgPlaylist, wrap(GetPlaylist))
316317
playlistRoute.Get("/:id/items", ValidateOrgPlaylist, wrap(GetPlaylistItems))
@@ -329,7 +330,7 @@ func (hs *HTTPServer) registerRoutes() {
329330
apiRoute.Get("/tsdb/testdata/gensql", reqGrafanaAdmin, wrap(GenerateSQLTestData))
330331
apiRoute.Get("/tsdb/testdata/random-walk", wrap(GetTestDataRandomWalk))
331332

332-
apiRoute.Group("/alerts", func(alertsRoute RouteRegister) {
333+
apiRoute.Group("/alerts", func(alertsRoute routing.RouteRegister) {
333334
alertsRoute.Post("/test", bind(dtos.AlertTestCommand{}), wrap(AlertTest))
334335
alertsRoute.Post("/:alertId/pause", reqEditorRole, bind(dtos.PauseAlertCommand{}), wrap(PauseAlert))
335336
alertsRoute.Get("/:alertId", ValidateOrgAlert, wrap(GetAlert))
@@ -340,7 +341,7 @@ func (hs *HTTPServer) registerRoutes() {
340341
apiRoute.Get("/alert-notifications", wrap(GetAlertNotifications))
341342
apiRoute.Get("/alert-notifiers", wrap(GetAlertNotifiers))
342343

343-
apiRoute.Group("/alert-notifications", func(alertNotifications RouteRegister) {
344+
apiRoute.Group("/alert-notifications", func(alertNotifications routing.RouteRegister) {
344345
alertNotifications.Post("/test", bind(dtos.NotificationTestCommand{}), wrap(NotificationTest))
345346
alertNotifications.Post("/", bind(m.CreateAlertNotificationCommand{}), wrap(CreateAlertNotification))
346347
alertNotifications.Put("/:notificationId", bind(m.UpdateAlertNotificationCommand{}), wrap(UpdateAlertNotification))
@@ -351,7 +352,7 @@ func (hs *HTTPServer) registerRoutes() {
351352
apiRoute.Get("/annotations", wrap(GetAnnotations))
352353
apiRoute.Post("/annotations/mass-delete", reqOrgAdmin, bind(dtos.DeleteAnnotationsCmd{}), wrap(DeleteAnnotations))
353354

354-
apiRoute.Group("/annotations", func(annotationsRoute RouteRegister) {
355+
apiRoute.Group("/annotations", func(annotationsRoute routing.RouteRegister) {
355356
annotationsRoute.Post("/", bind(dtos.PostAnnotationsCmd{}), wrap(PostAnnotation))
356357
annotationsRoute.Delete("/:annotationId", wrap(DeleteAnnotationByID))
357358
annotationsRoute.Put("/:annotationId", bind(dtos.UpdateAnnotationsCmd{}), wrap(UpdateAnnotation))
@@ -365,7 +366,7 @@ func (hs *HTTPServer) registerRoutes() {
365366
}, reqSignedIn)
366367

367368
// admin api
368-
r.Group("/api/admin", func(adminRoute RouteRegister) {
369+
r.Group("/api/admin", func(adminRoute routing.RouteRegister) {
369370
adminRoute.Get("/settings", AdminGetSettings)
370371
adminRoute.Post("/users", bind(dtos.AdminCreateUserForm{}), AdminCreateUser)
371372
adminRoute.Put("/users/:id/password", bind(dtos.AdminUpdateUserPasswordForm{}), AdminUpdateUserPassword)

pkg/api/datasources.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ func DeleteDataSourceByName(c *m.ReqContext) Response {
103103

104104
getCmd := &m.GetDataSourceByNameQuery{Name: name, OrgId: c.OrgId}
105105
if err := bus.Dispatch(getCmd); err != nil {
106+
if err == m.ErrDataSourceNotFound {
107+
return Error(404, "Data source not found", nil)
108+
}
106109
return Error(500, "Failed to delete datasource", err)
107110
}
108111

pkg/api/datasources_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,13 @@ func TestDataSourcesProxy(t *testing.T) {
4646
So(respJSON[3]["name"], ShouldEqual, "ZZZ")
4747
})
4848
})
49+
50+
Convey("Should be able to save a data source", func() {
51+
loggedInUserScenario("When calling DELETE on non-existing", "/api/datasources/name/12345", func(sc *scenarioContext) {
52+
sc.handlerFunc = DeleteDataSourceByName
53+
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
54+
So(sc.resp.Code, ShouldEqual, 404)
55+
})
56+
})
4957
})
5058
}

pkg/api/http_server.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"path"
1212
"time"
1313

14+
"github.com/grafana/grafana/pkg/api/routing"
1415
"github.com/prometheus/client_golang/prometheus"
1516

1617
"github.com/prometheus/client_golang/prometheus/promhttp"
@@ -43,10 +44,10 @@ type HTTPServer struct {
4344
cache *gocache.Cache
4445
httpSrv *http.Server
4546

46-
RouteRegister RouteRegister `inject:""`
47-
Bus bus.Bus `inject:""`
48-
RenderService rendering.Service `inject:""`
49-
Cfg *setting.Cfg `inject:""`
47+
RouteRegister routing.RouteRegister `inject:""`
48+
Bus bus.Bus `inject:""`
49+
RenderService rendering.Service `inject:""`
50+
Cfg *setting.Cfg `inject:""`
5051
}
5152

5253
func (hs *HTTPServer) Init() error {

0 commit comments

Comments
 (0)