Merge branch 'master' into master

This commit is contained in:
Dan Cech
2018-04-19 12:01:48 -04:00
committed by GitHub
648 changed files with 103284 additions and 9539 deletions
+11 -3
View File
@@ -1,15 +1,15 @@
package api
import (
"regexp"
"strings"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
)
func AdminGetSettings(c *middleware.Context) {
func AdminGetSettings(c *m.ReqContext) {
settings := make(map[string]interface{})
for _, section := range setting.Cfg.Sections() {
@@ -22,6 +22,14 @@ func AdminGetSettings(c *middleware.Context) {
if strings.Contains(keyName, "secret") || strings.Contains(keyName, "password") || (strings.Contains(keyName, "provider_config")) {
value = "************"
}
if strings.Contains(keyName, "url") {
var rgx = regexp.MustCompile(`.*:\/\/([^:]*):([^@]*)@.*?$`)
var subs = rgx.FindAllSubmatch([]byte(value), -1)
if subs != nil && len(subs[0]) == 3 {
value = strings.Replace(value, string(subs[0][1]), "******", 1)
value = strings.Replace(value, string(subs[0][2]), "******", 1)
}
}
jsonSec[keyName] = value
}
@@ -30,7 +38,7 @@ func AdminGetSettings(c *middleware.Context) {
c.JSON(200, settings)
}
func AdminGetStats(c *middleware.Context) {
func AdminGetStats(c *m.ReqContext) {
statsQuery := m.GetAdminStatsQuery{}
+11 -12
View File
@@ -4,12 +4,11 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util"
)
func AdminCreateUser(c *middleware.Context, form dtos.AdminCreateUserForm) {
func AdminCreateUser(c *m.ReqContext, form dtos.AdminCreateUserForm) {
cmd := m.CreateUserCommand{
Login: form.Login,
Email: form.Email,
@@ -47,15 +46,15 @@ func AdminCreateUser(c *middleware.Context, form dtos.AdminCreateUserForm) {
c.JSON(200, result)
}
func AdminUpdateUserPassword(c *middleware.Context, form dtos.AdminUpdateUserPasswordForm) {
userId := c.ParamsInt64(":id")
func AdminUpdateUserPassword(c *m.ReqContext, form dtos.AdminUpdateUserPasswordForm) {
userID := c.ParamsInt64(":id")
if len(form.Password) < 4 {
c.JsonApiErr(400, "New password too short", nil)
return
}
userQuery := m.GetUserByIdQuery{Id: userId}
userQuery := m.GetUserByIdQuery{Id: userID}
if err := bus.Dispatch(&userQuery); err != nil {
c.JsonApiErr(500, "Could not read user from database", err)
@@ -65,7 +64,7 @@ func AdminUpdateUserPassword(c *middleware.Context, form dtos.AdminUpdateUserPas
passwordHashed := util.EncodePassword(form.Password, userQuery.Result.Salt)
cmd := m.ChangeUserPasswordCommand{
UserId: userId,
UserId: userID,
NewPassword: passwordHashed,
}
@@ -77,11 +76,11 @@ func AdminUpdateUserPassword(c *middleware.Context, form dtos.AdminUpdateUserPas
c.JsonOK("User password updated")
}
func AdminUpdateUserPermissions(c *middleware.Context, form dtos.AdminUpdateUserPermissionsForm) {
userId := c.ParamsInt64(":id")
func AdminUpdateUserPermissions(c *m.ReqContext, form dtos.AdminUpdateUserPermissionsForm) {
userID := c.ParamsInt64(":id")
cmd := m.UpdateUserPermissionsCommand{
UserId: userId,
UserId: userID,
IsGrafanaAdmin: form.IsGrafanaAdmin,
}
@@ -93,10 +92,10 @@ func AdminUpdateUserPermissions(c *middleware.Context, form dtos.AdminUpdateUser
c.JsonOK("User permissions updated")
}
func AdminDeleteUser(c *middleware.Context) {
userId := c.ParamsInt64(":id")
func AdminDeleteUser(c *m.ReqContext) {
userID := c.ParamsInt64(":id")
cmd := m.DeleteUserCommand{UserId: userId}
cmd := m.DeleteUserCommand{UserId: userID}
if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, "Failed to delete user", err)
+68 -69
View File
@@ -5,15 +5,14 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/guardian"
)
func ValidateOrgAlert(c *middleware.Context) {
func ValidateOrgAlert(c *m.ReqContext) {
id := c.ParamsInt64(":alertId")
query := models.GetAlertByIdQuery{Id: id}
query := m.GetAlertByIdQuery{Id: id}
if err := bus.Dispatch(&query); err != nil {
c.JsonApiErr(404, "Alert not found", nil)
@@ -26,28 +25,28 @@ func ValidateOrgAlert(c *middleware.Context) {
}
}
func GetAlertStatesForDashboard(c *middleware.Context) Response {
dashboardId := c.QueryInt64("dashboardId")
func GetAlertStatesForDashboard(c *m.ReqContext) Response {
dashboardID := c.QueryInt64("dashboardId")
if dashboardId == 0 {
return ApiError(400, "Missing query parameter dashboardId", nil)
if dashboardID == 0 {
return Error(400, "Missing query parameter dashboardId", nil)
}
query := models.GetAlertStatesForDashboardQuery{
query := m.GetAlertStatesForDashboardQuery{
OrgId: c.OrgId,
DashboardId: c.QueryInt64("dashboardId"),
}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to fetch alert states", err)
return Error(500, "Failed to fetch alert states", err)
}
return Json(200, query.Result)
return JSON(200, query.Result)
}
// GET /api/alerts
func GetAlerts(c *middleware.Context) Response {
query := models.GetAlertsQuery{
func GetAlerts(c *m.ReqContext) Response {
query := m.GetAlertsQuery{
OrgId: c.OrgId,
DashboardId: c.QueryInt64("dashboardId"),
PanelId: c.QueryInt64("panelId"),
@@ -61,20 +60,20 @@ func GetAlerts(c *middleware.Context) Response {
}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "List alerts failed", err)
return Error(500, "List alerts failed", err)
}
for _, alert := range query.Result {
alert.Url = models.GetDashboardUrl(alert.DashboardUid, alert.DashboardSlug)
alert.Url = m.GetDashboardUrl(alert.DashboardUid, alert.DashboardSlug)
}
return Json(200, query.Result)
return JSON(200, query.Result)
}
// POST /api/alerts/test
func AlertTest(c *middleware.Context, dto dtos.AlertTestCommand) Response {
func AlertTest(c *m.ReqContext, dto dtos.AlertTestCommand) Response {
if _, idErr := dto.Dashboard.Get("id").Int64(); idErr != nil {
return ApiError(400, "The dashboard needs to be saved at least once before you can test an alert rule", nil)
return Error(400, "The dashboard needs to be saved at least once before you can test an alert rule", nil)
}
backendCmd := alerting.AlertTestCommand{
@@ -85,9 +84,9 @@ func AlertTest(c *middleware.Context, dto dtos.AlertTestCommand) Response {
if err := bus.Dispatch(&backendCmd); err != nil {
if validationErr, ok := err.(alerting.ValidationError); ok {
return ApiError(422, validationErr.Error(), nil)
return Error(422, validationErr.Error(), nil)
}
return ApiError(500, "Failed to test rule", err)
return Error(500, "Failed to test rule", err)
}
res := backendCmd.Result
@@ -110,30 +109,30 @@ func AlertTest(c *middleware.Context, dto dtos.AlertTestCommand) Response {
dtoRes.TimeMs = fmt.Sprintf("%1.3fms", res.GetDurationMs())
return Json(200, dtoRes)
return JSON(200, dtoRes)
}
// GET /api/alerts/:id
func GetAlert(c *middleware.Context) Response {
func GetAlert(c *m.ReqContext) Response {
id := c.ParamsInt64(":alertId")
query := models.GetAlertByIdQuery{Id: id}
query := m.GetAlertByIdQuery{Id: id}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "List alerts failed", err)
return Error(500, "List alerts failed", err)
}
return Json(200, &query.Result)
return JSON(200, &query.Result)
}
func GetAlertNotifiers(c *middleware.Context) Response {
return Json(200, alerting.GetNotifiers())
func GetAlertNotifiers(c *m.ReqContext) Response {
return JSON(200, alerting.GetNotifiers())
}
func GetAlertNotifications(c *middleware.Context) Response {
query := &models.GetAllAlertNotificationsQuery{OrgId: c.OrgId}
func GetAlertNotifications(c *m.ReqContext) Response {
query := &m.GetAllAlertNotificationsQuery{OrgId: c.OrgId}
if err := bus.Dispatch(query); err != nil {
return ApiError(500, "Failed to get alert notifications", err)
return Error(500, "Failed to get alert notifications", err)
}
result := make([]*dtos.AlertNotification, 0)
@@ -149,57 +148,57 @@ func GetAlertNotifications(c *middleware.Context) Response {
})
}
return Json(200, result)
return JSON(200, result)
}
func GetAlertNotificationById(c *middleware.Context) Response {
query := &models.GetAlertNotificationsQuery{
func GetAlertNotificationByID(c *m.ReqContext) Response {
query := &m.GetAlertNotificationsQuery{
OrgId: c.OrgId,
Id: c.ParamsInt64("notificationId"),
}
if err := bus.Dispatch(query); err != nil {
return ApiError(500, "Failed to get alert notifications", err)
return Error(500, "Failed to get alert notifications", err)
}
return Json(200, query.Result)
return JSON(200, query.Result)
}
func CreateAlertNotification(c *middleware.Context, cmd models.CreateAlertNotificationCommand) Response {
func CreateAlertNotification(c *m.ReqContext, cmd m.CreateAlertNotificationCommand) Response {
cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to create alert notification", err)
return Error(500, "Failed to create alert notification", err)
}
return Json(200, cmd.Result)
return JSON(200, cmd.Result)
}
func UpdateAlertNotification(c *middleware.Context, cmd models.UpdateAlertNotificationCommand) Response {
func UpdateAlertNotification(c *m.ReqContext, cmd m.UpdateAlertNotificationCommand) Response {
cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to update alert notification", err)
return Error(500, "Failed to update alert notification", err)
}
return Json(200, cmd.Result)
return JSON(200, cmd.Result)
}
func DeleteAlertNotification(c *middleware.Context) Response {
cmd := models.DeleteAlertNotificationCommand{
func DeleteAlertNotification(c *m.ReqContext) Response {
cmd := m.DeleteAlertNotificationCommand{
OrgId: c.OrgId,
Id: c.ParamsInt64("notificationId"),
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to delete alert notification", err)
return Error(500, "Failed to delete alert notification", err)
}
return ApiSuccess("Notification deleted")
return Success("Notification deleted")
}
//POST /api/alert-notifications/test
func NotificationTest(c *middleware.Context, dto dtos.NotificationTestCommand) Response {
func NotificationTest(c *m.ReqContext, dto dtos.NotificationTestCommand) Response {
cmd := &alerting.NotificationTestCommand{
Name: dto.Name,
Type: dto.Type,
@@ -207,74 +206,74 @@ func NotificationTest(c *middleware.Context, dto dtos.NotificationTestCommand) R
}
if err := bus.Dispatch(cmd); err != nil {
if err == models.ErrSmtpNotEnabled {
return ApiError(412, err.Error(), err)
if err == m.ErrSmtpNotEnabled {
return Error(412, err.Error(), err)
}
return ApiError(500, "Failed to send alert notifications", err)
return Error(500, "Failed to send alert notifications", err)
}
return ApiSuccess("Test notification sent")
return Success("Test notification sent")
}
//POST /api/alerts/:alertId/pause
func PauseAlert(c *middleware.Context, dto dtos.PauseAlertCommand) Response {
alertId := c.ParamsInt64("alertId")
func PauseAlert(c *m.ReqContext, dto dtos.PauseAlertCommand) Response {
alertID := c.ParamsInt64("alertId")
query := models.GetAlertByIdQuery{Id: alertId}
query := m.GetAlertByIdQuery{Id: alertID}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Get Alert failed", err)
return Error(500, "Get Alert failed", err)
}
guardian := guardian.New(query.Result.DashboardId, c.OrgId, c.SignedInUser)
if canEdit, err := guardian.CanEdit(); err != nil || !canEdit {
if err != nil {
return ApiError(500, "Error while checking permissions for Alert", err)
return Error(500, "Error while checking permissions for Alert", err)
}
return ApiError(403, "Access denied to this dashboard and alert", nil)
return Error(403, "Access denied to this dashboard and alert", nil)
}
cmd := models.PauseAlertCommand{
cmd := m.PauseAlertCommand{
OrgId: c.OrgId,
AlertIds: []int64{alertId},
AlertIds: []int64{alertID},
Paused: dto.Paused,
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "", err)
return Error(500, "", err)
}
var response models.AlertStateType = models.AlertStatePending
var response m.AlertStateType = m.AlertStatePending
pausedState := "un-paused"
if cmd.Paused {
response = models.AlertStatePaused
response = m.AlertStatePaused
pausedState = "paused"
}
result := map[string]interface{}{
"alertId": alertId,
"alertId": alertID,
"state": response,
"message": "Alert " + pausedState,
}
return Json(200, result)
return JSON(200, result)
}
//POST /api/admin/pause-all-alerts
func PauseAllAlerts(c *middleware.Context, dto dtos.PauseAllAlertsCommand) Response {
updateCmd := models.PauseAllAlertCommand{
func PauseAllAlerts(c *m.ReqContext, dto dtos.PauseAllAlertsCommand) Response {
updateCmd := m.PauseAllAlertCommand{
Paused: dto.Paused,
}
if err := bus.Dispatch(&updateCmd); err != nil {
return ApiError(500, "Failed to pause alerts", err)
return Error(500, "Failed to pause alerts", err)
}
var response models.AlertStateType = models.AlertStatePending
var response m.AlertStateType = m.AlertStatePending
pausedState := "un paused"
if updateCmd.Paused {
response = models.AlertStatePaused
response = m.AlertStatePaused
pausedState = "paused"
}
@@ -284,5 +283,5 @@ func PauseAllAlerts(c *middleware.Context, dto dtos.PauseAllAlertsCommand) Respo
"alertsAffected": updateCmd.ResultCount,
}
return Json(200, result)
return JSON(200, result)
}
+1 -2
View File
@@ -5,7 +5,6 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
@@ -81,7 +80,7 @@ func postAlertScenario(desc string, url string, routePattern string, role m.Role
defer bus.ClearBusHandlers()
sc := setupScenarioContext(url)
sc.defaultHandler = wrap(func(c *middleware.Context) Response {
sc.defaultHandler = wrap(func(c *m.ReqContext) Response {
sc.context = c
sc.context.UserId = TestUserID
sc.context.OrgId = TestOrgID
+53 -54
View File
@@ -6,14 +6,13 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/util"
)
func GetAnnotations(c *middleware.Context) Response {
func GetAnnotations(c *m.ReqContext) Response {
query := &annotations.ItemQuery{
From: c.QueryInt64("from") / 1000,
@@ -31,7 +30,7 @@ func GetAnnotations(c *middleware.Context) Response {
items, err := repo.Find(query)
if err != nil {
return ApiError(500, "Failed to get annotations", err)
return Error(500, "Failed to get annotations", err)
}
for _, item := range items {
@@ -41,7 +40,7 @@ func GetAnnotations(c *middleware.Context) Response {
item.Time = item.Time * 1000
}
return Json(200, items)
return JSON(200, items)
}
type CreateAnnotationError struct {
@@ -52,8 +51,8 @@ func (e *CreateAnnotationError) Error() string {
return e.message
}
func PostAnnotation(c *middleware.Context, cmd dtos.PostAnnotationsCmd) Response {
if canSave, err := canSaveByDashboardId(c, cmd.DashboardId); err != nil || !canSave {
func PostAnnotation(c *m.ReqContext, cmd dtos.PostAnnotationsCmd) Response {
if canSave, err := canSaveByDashboardID(c, cmd.DashboardId); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
@@ -61,7 +60,7 @@ func PostAnnotation(c *middleware.Context, cmd dtos.PostAnnotationsCmd) Response
if cmd.Text == "" {
err := &CreateAnnotationError{"text field should not be empty"}
return ApiError(500, "Failed to save annotation", err)
return Error(500, "Failed to save annotation", err)
}
item := annotations.Item{
@@ -80,7 +79,7 @@ func PostAnnotation(c *middleware.Context, cmd dtos.PostAnnotationsCmd) Response
}
if err := repo.Save(&item); err != nil {
return ApiError(500, "Failed to save annotation", err)
return Error(500, "Failed to save annotation", err)
}
startID := item.Id
@@ -94,24 +93,24 @@ func PostAnnotation(c *middleware.Context, cmd dtos.PostAnnotationsCmd) Response
}
if err := repo.Update(&item); err != nil {
return ApiError(500, "Failed set regionId on annotation", err)
return Error(500, "Failed set regionId on annotation", err)
}
item.Id = 0
item.Epoch = cmd.TimeEnd / 1000
if err := repo.Save(&item); err != nil {
return ApiError(500, "Failed save annotation for region end time", err)
return Error(500, "Failed save annotation for region end time", err)
}
return Json(200, util.DynMap{
return JSON(200, util.DynMap{
"message": "Annotation added",
"id": startID,
"endId": item.Id,
})
}
return Json(200, util.DynMap{
return JSON(200, util.DynMap{
"message": "Annotation added",
"id": startID,
})
@@ -125,12 +124,12 @@ func formatGraphiteAnnotation(what string, data string) string {
return text
}
func PostGraphiteAnnotation(c *middleware.Context, cmd dtos.PostGraphiteAnnotationsCmd) Response {
func PostGraphiteAnnotation(c *m.ReqContext, cmd dtos.PostGraphiteAnnotationsCmd) Response {
repo := annotations.GetRepository()
if cmd.What == "" {
err := &CreateAnnotationError{"what field should not be empty"}
return ApiError(500, "Failed to save Graphite annotation", err)
return Error(500, "Failed to save Graphite annotation", err)
}
if cmd.When == 0 {
@@ -153,12 +152,12 @@ func PostGraphiteAnnotation(c *middleware.Context, cmd dtos.PostGraphiteAnnotati
tagsArray = append(tagsArray, tagStr)
} else {
err := &CreateAnnotationError{"tag should be a string"}
return ApiError(500, "Failed to save Graphite annotation", err)
return Error(500, "Failed to save Graphite annotation", err)
}
}
default:
err := &CreateAnnotationError{"unsupported tags format"}
return ApiError(500, "Failed to save Graphite annotation", err)
return Error(500, "Failed to save Graphite annotation", err)
}
item := annotations.Item{
@@ -170,35 +169,35 @@ func PostGraphiteAnnotation(c *middleware.Context, cmd dtos.PostGraphiteAnnotati
}
if err := repo.Save(&item); err != nil {
return ApiError(500, "Failed to save Graphite annotation", err)
return Error(500, "Failed to save Graphite annotation", err)
}
return Json(200, util.DynMap{
return JSON(200, util.DynMap{
"message": "Graphite annotation added",
"id": item.Id,
})
}
func UpdateAnnotation(c *middleware.Context, cmd dtos.UpdateAnnotationsCmd) Response {
annotationId := c.ParamsInt64(":annotationId")
func UpdateAnnotation(c *m.ReqContext, cmd dtos.UpdateAnnotationsCmd) Response {
annotationID := c.ParamsInt64(":annotationId")
repo := annotations.GetRepository()
if resp := canSave(c, repo, annotationId); resp != nil {
if resp := canSave(c, repo, annotationID); resp != nil {
return resp
}
item := annotations.Item{
OrgId: c.OrgId,
UserId: c.UserId,
Id: annotationId,
Id: annotationID,
Epoch: cmd.Time / 1000,
Text: cmd.Text,
Tags: cmd.Tags,
}
if err := repo.Update(&item); err != nil {
return ApiError(500, "Failed to update annotation", err)
return Error(500, "Failed to update annotation", err)
}
if cmd.IsRegion {
@@ -211,14 +210,14 @@ func UpdateAnnotation(c *middleware.Context, cmd dtos.UpdateAnnotationsCmd) Resp
itemRight.Id = 0
if err := repo.Update(&itemRight); err != nil {
return ApiError(500, "Failed to update annotation for region end time", err)
return Error(500, "Failed to update annotation for region end time", err)
}
}
return ApiSuccess("Annotation updated")
return Success("Annotation updated")
}
func DeleteAnnotations(c *middleware.Context, cmd dtos.DeleteAnnotationsCmd) Response {
func DeleteAnnotations(c *m.ReqContext, cmd dtos.DeleteAnnotationsCmd) Response {
repo := annotations.GetRepository()
err := repo.Delete(&annotations.DeleteParams{
@@ -228,57 +227,57 @@ func DeleteAnnotations(c *middleware.Context, cmd dtos.DeleteAnnotationsCmd) Res
})
if err != nil {
return ApiError(500, "Failed to delete annotations", err)
return Error(500, "Failed to delete annotations", err)
}
return ApiSuccess("Annotations deleted")
return Success("Annotations deleted")
}
func DeleteAnnotationById(c *middleware.Context) Response {
func DeleteAnnotationByID(c *m.ReqContext) Response {
repo := annotations.GetRepository()
annotationId := c.ParamsInt64(":annotationId")
annotationID := c.ParamsInt64(":annotationId")
if resp := canSave(c, repo, annotationId); resp != nil {
if resp := canSave(c, repo, annotationID); resp != nil {
return resp
}
err := repo.Delete(&annotations.DeleteParams{
Id: annotationId,
Id: annotationID,
})
if err != nil {
return ApiError(500, "Failed to delete annotation", err)
return Error(500, "Failed to delete annotation", err)
}
return ApiSuccess("Annotation deleted")
return Success("Annotation deleted")
}
func DeleteAnnotationRegion(c *middleware.Context) Response {
func DeleteAnnotationRegion(c *m.ReqContext) Response {
repo := annotations.GetRepository()
regionId := c.ParamsInt64(":regionId")
regionID := c.ParamsInt64(":regionId")
if resp := canSave(c, repo, regionId); resp != nil {
if resp := canSave(c, repo, regionID); resp != nil {
return resp
}
err := repo.Delete(&annotations.DeleteParams{
RegionId: regionId,
RegionId: regionID,
})
if err != nil {
return ApiError(500, "Failed to delete annotation region", err)
return Error(500, "Failed to delete annotation region", err)
}
return ApiSuccess("Annotation region deleted")
return Success("Annotation region deleted")
}
func canSaveByDashboardId(c *middleware.Context, dashboardId int64) (bool, error) {
if dashboardId == 0 && !c.SignedInUser.HasRole(m.ROLE_EDITOR) {
func canSaveByDashboardID(c *m.ReqContext, dashboardID int64) (bool, error) {
if dashboardID == 0 && !c.SignedInUser.HasRole(m.ROLE_EDITOR) {
return false, nil
}
if dashboardId > 0 {
guardian := guardian.New(dashboardId, c.OrgId, c.SignedInUser)
if dashboardID > 0 {
guardian := guardian.New(dashboardID, c.OrgId, c.SignedInUser)
if canEdit, err := guardian.CanEdit(); err != nil || !canEdit {
return false, err
}
@@ -287,32 +286,32 @@ func canSaveByDashboardId(c *middleware.Context, dashboardId int64) (bool, error
return true, nil
}
func canSave(c *middleware.Context, repo annotations.Repository, annotationId int64) Response {
items, err := repo.Find(&annotations.ItemQuery{AnnotationId: annotationId, OrgId: c.OrgId})
func canSave(c *m.ReqContext, repo annotations.Repository, annotationID int64) Response {
items, err := repo.Find(&annotations.ItemQuery{AnnotationId: annotationID, OrgId: c.OrgId})
if err != nil || len(items) == 0 {
return ApiError(500, "Could not find annotation to update", err)
return Error(500, "Could not find annotation to update", err)
}
dashboardId := items[0].DashboardId
dashboardID := items[0].DashboardId
if canSave, err := canSaveByDashboardId(c, dashboardId); err != nil || !canSave {
if canSave, err := canSaveByDashboardID(c, dashboardID); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
return nil
}
func canSaveByRegionId(c *middleware.Context, repo annotations.Repository, regionId int64) Response {
items, err := repo.Find(&annotations.ItemQuery{RegionId: regionId, OrgId: c.OrgId})
func canSaveByRegionID(c *m.ReqContext, repo annotations.Repository, regionID int64) Response {
items, err := repo.Find(&annotations.ItemQuery{RegionId: regionID, OrgId: c.OrgId})
if err != nil || len(items) == 0 {
return ApiError(500, "Could not find annotation to update", err)
return Error(500, "Could not find annotation to update", err)
}
dashboardId := items[0].DashboardId
dashboardID := items[0].DashboardId
if canSave, err := canSaveByDashboardId(c, dashboardId); err != nil || !canSave {
if canSave, err := canSaveByDashboardID(c, dashboardID); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
+6 -7
View File
@@ -5,7 +5,6 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/annotations"
@@ -42,7 +41,7 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
})
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
sc.handlerFunc = DeleteAnnotationById
sc.handlerFunc = DeleteAnnotationByID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
So(sc.resp.Code, ShouldEqual, 403)
})
@@ -69,7 +68,7 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
})
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
sc.handlerFunc = DeleteAnnotationById
sc.handlerFunc = DeleteAnnotationByID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
So(sc.resp.Code, ShouldEqual, 200)
})
@@ -133,7 +132,7 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
})
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
sc.handlerFunc = DeleteAnnotationById
sc.handlerFunc = DeleteAnnotationByID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
So(sc.resp.Code, ShouldEqual, 403)
})
@@ -160,7 +159,7 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
})
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
sc.handlerFunc = DeleteAnnotationById
sc.handlerFunc = DeleteAnnotationByID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
So(sc.resp.Code, ShouldEqual, 200)
})
@@ -200,7 +199,7 @@ func postAnnotationScenario(desc string, url string, routePattern string, role m
defer bus.ClearBusHandlers()
sc := setupScenarioContext(url)
sc.defaultHandler = wrap(func(c *middleware.Context) Response {
sc.defaultHandler = wrap(func(c *m.ReqContext) Response {
sc.context = c
sc.context.UserId = TestUserID
sc.context.OrgId = TestOrgID
@@ -223,7 +222,7 @@ func putAnnotationScenario(desc string, url string, routePattern string, role m.
defer bus.ClearBusHandlers()
sc := setupScenarioContext(url)
sc.defaultHandler = wrap(func(c *middleware.Context) Response {
sc.defaultHandler = wrap(func(c *m.ReqContext) Response {
sc.context = c
sc.context.UserId = TestUserID
sc.context.OrgId = TestOrgID
+37 -28
View File
@@ -9,14 +9,14 @@ import (
)
// Register adds http routes
func (hs *HttpServer) registerRoutes() {
func (hs *HTTPServer) registerRoutes() {
macaronR := hs.macaron
reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)
reqOrgAdmin := middleware.RoleAuth(m.ROLE_ADMIN)
redirectFromLegacyDashboardUrl := middleware.RedirectFromLegacyDashboardUrl()
redirectFromLegacyDashboardSoloUrl := middleware.RedirectFromLegacyDashboardSoloUrl()
redirectFromLegacyDashboardURL := middleware.RedirectFromLegacyDashboardURL()
redirectFromLegacyDashboardSoloURL := middleware.RedirectFromLegacyDashboardSoloURL()
quota := middleware.Quota
bind := binding.Bind
@@ -66,11 +66,12 @@ func (hs *HttpServer) registerRoutes() {
r.Get("/plugins/:id/page/:page", reqSignedIn, Index)
r.Get("/d/:uid/:slug", reqSignedIn, Index)
r.Get("/dashboard/db/:slug", reqSignedIn, redirectFromLegacyDashboardUrl, Index)
r.Get("/d/:uid", reqSignedIn, Index)
r.Get("/dashboard/db/:slug", reqSignedIn, redirectFromLegacyDashboardURL, Index)
r.Get("/dashboard/script/*", reqSignedIn, Index)
r.Get("/dashboard-solo/snapshot/*", Index)
r.Get("/d-solo/:uid/:slug", reqSignedIn, Index)
r.Get("/dashboard-solo/db/:slug", reqSignedIn, redirectFromLegacyDashboardSoloUrl, Index)
r.Get("/dashboard-solo/db/:slug", reqSignedIn, redirectFromLegacyDashboardSoloURL, Index)
r.Get("/dashboard-solo/script/*", reqSignedIn, Index)
r.Get("/import/dashboard", reqSignedIn, Index)
r.Get("/dashboards/", reqSignedIn, Index)
@@ -109,7 +110,7 @@ func (hs *HttpServer) registerRoutes() {
r.Get("/api/snapshots-delete/:key", reqEditorRole, wrap(DeleteDashboardSnapshot))
// api renew session based on remember cookie
r.Get("/api/login/ping", quota("session"), LoginApiPing)
r.Get("/api/login/ping", quota("session"), LoginAPIPing)
// authed api
r.Group("/api", func(apiRoute RouteRegister) {
@@ -138,7 +139,7 @@ func (hs *HttpServer) registerRoutes() {
apiRoute.Group("/users", func(usersRoute RouteRegister) {
usersRoute.Get("/", wrap(SearchUsers))
usersRoute.Get("/search", wrap(SearchUsersWithPaging))
usersRoute.Get("/:id", wrap(GetUserById))
usersRoute.Get("/:id", wrap(GetUserByID))
usersRoute.Get("/:id/orgs", wrap(GetUserOrgList))
// query parameters /users/lookup?loginOrEmail=admin@example.com
usersRoute.Get("/lookup", wrap(GetUserByLoginOrEmail))
@@ -148,16 +149,20 @@ func (hs *HttpServer) registerRoutes() {
// team (admin permission required)
apiRoute.Group("/teams", func(teamsRoute RouteRegister) {
teamsRoute.Get("/:teamId", wrap(GetTeamById))
teamsRoute.Get("/search", wrap(SearchTeams))
teamsRoute.Post("/", quota("teams"), bind(m.CreateTeamCommand{}), wrap(CreateTeam))
teamsRoute.Post("/", bind(m.CreateTeamCommand{}), wrap(CreateTeam))
teamsRoute.Put("/:teamId", bind(m.UpdateTeamCommand{}), wrap(UpdateTeam))
teamsRoute.Delete("/:teamId", wrap(DeleteTeamById))
teamsRoute.Delete("/:teamId", wrap(DeleteTeamByID))
teamsRoute.Get("/:teamId/members", wrap(GetTeamMembers))
teamsRoute.Post("/:teamId/members", quota("teams"), bind(m.AddTeamMemberCommand{}), wrap(AddTeamMember))
teamsRoute.Post("/:teamId/members", bind(m.AddTeamMemberCommand{}), wrap(AddTeamMember))
teamsRoute.Delete("/:teamId/members/:userId", wrap(RemoveTeamMember))
}, reqOrgAdmin)
// team without requirement of user to be org admin
apiRoute.Group("/teams", func(teamsRoute RouteRegister) {
teamsRoute.Get("/:teamId", wrap(GetTeamByID))
teamsRoute.Get("/search", wrap(SearchTeams))
})
// org information available to all users.
apiRoute.Group("/org", func(orgRoute RouteRegister) {
orgRoute.Get("/", wrap(GetOrgCurrent))
@@ -169,7 +174,6 @@ func (hs *HttpServer) registerRoutes() {
orgRoute.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrgCurrent))
orgRoute.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddressCurrent))
orgRoute.Post("/users", quota("user"), bind(m.AddOrgUserCommand{}), wrap(AddOrgUserToCurrentOrg))
orgRoute.Get("/users", wrap(GetOrgUsersForCurrentOrg))
orgRoute.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUserForCurrentOrg))
orgRoute.Delete("/users/:userId", wrap(RemoveOrgUserForCurrentOrg))
@@ -183,6 +187,11 @@ func (hs *HttpServer) registerRoutes() {
orgRoute.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), wrap(UpdateOrgPreferences))
}, reqOrgAdmin)
// current org without requirement of user to be org admin
apiRoute.Group("/org", func(orgRoute RouteRegister) {
orgRoute.Get("/users", wrap(GetOrgUsersForCurrentOrg))
})
// create new org
apiRoute.Post("/orgs", quota("org"), bind(m.CreateOrgCommand{}), wrap(CreateOrg))
@@ -191,10 +200,10 @@ func (hs *HttpServer) registerRoutes() {
// orgs (admin routes)
apiRoute.Group("/orgs/:orgId", func(orgsRoute RouteRegister) {
orgsRoute.Get("/", wrap(GetOrgById))
orgsRoute.Get("/", wrap(GetOrgByID))
orgsRoute.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrg))
orgsRoute.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddress))
orgsRoute.Delete("/", wrap(DeleteOrgById))
orgsRoute.Delete("/", wrap(DeleteOrgByID))
orgsRoute.Get("/users", wrap(GetOrgUsers))
orgsRoute.Post("/users", bind(m.AddOrgUserCommand{}), wrap(AddOrgUser))
orgsRoute.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUser))
@@ -210,9 +219,9 @@ func (hs *HttpServer) registerRoutes() {
// auth api keys
apiRoute.Group("/auth/keys", func(keysRoute RouteRegister) {
keysRoute.Get("/", wrap(GetApiKeys))
keysRoute.Post("/", quota("api_key"), bind(m.AddApiKeyCommand{}), wrap(AddApiKey))
keysRoute.Delete("/:id", wrap(DeleteApiKey))
keysRoute.Get("/", wrap(GetAPIKeys))
keysRoute.Post("/", quota("api_key"), bind(m.AddApiKeyCommand{}), wrap(AddAPIKey))
keysRoute.Delete("/:id", wrap(DeleteAPIKey))
}, reqOrgAdmin)
// Preferences
@@ -225,16 +234,16 @@ func (hs *HttpServer) registerRoutes() {
datasourceRoute.Get("/", wrap(GetDataSources))
datasourceRoute.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), wrap(AddDataSource))
datasourceRoute.Put("/:id", bind(m.UpdateDataSourceCommand{}), wrap(UpdateDataSource))
datasourceRoute.Delete("/:id", wrap(DeleteDataSourceById))
datasourceRoute.Delete("/:id", wrap(DeleteDataSourceByID))
datasourceRoute.Delete("/name/:name", wrap(DeleteDataSourceByName))
datasourceRoute.Get("/:id", wrap(GetDataSourceById))
datasourceRoute.Get("/:id", wrap(GetDataSourceByID))
datasourceRoute.Get("/name/:name", wrap(GetDataSourceByName))
}, reqOrgAdmin)
apiRoute.Get("/datasources/id/:name", wrap(GetDataSourceIdByName), reqSignedIn)
apiRoute.Get("/datasources/id/:name", wrap(GetDataSourceIDByName), reqSignedIn)
apiRoute.Get("/plugins", wrap(GetPluginList))
apiRoute.Get("/plugins/:pluginId/settings", wrap(GetPluginSettingById))
apiRoute.Get("/plugins/:pluginId/settings", wrap(GetPluginSettingByID))
apiRoute.Get("/plugins/:pluginId/markdown/:name", wrap(GetPluginMarkdown))
apiRoute.Group("/plugins", func(pluginRoute RouteRegister) {
@@ -249,11 +258,11 @@ func (hs *HttpServer) registerRoutes() {
// Folders
apiRoute.Group("/folders", func(folderRoute RouteRegister) {
folderRoute.Get("/", wrap(GetFolders))
folderRoute.Get("/id/:id", wrap(GetFolderById))
folderRoute.Get("/id/:id", wrap(GetFolderByID))
folderRoute.Post("/", bind(m.CreateFolderCommand{}), wrap(CreateFolder))
folderRoute.Group("/:uid", func(folderUidRoute RouteRegister) {
folderUidRoute.Get("/", wrap(GetFolderByUid))
folderUidRoute.Get("/", wrap(GetFolderByUID))
folderUidRoute.Put("/", bind(m.UpdateFolderCommand{}), wrap(UpdateFolder))
folderUidRoute.Delete("/", wrap(DeleteFolder))
@@ -267,7 +276,7 @@ func (hs *HttpServer) registerRoutes() {
// Dashboard
apiRoute.Group("/dashboards", func(dashboardRoute RouteRegister) {
dashboardRoute.Get("/uid/:uid", wrap(GetDashboard))
dashboardRoute.Delete("/uid/:uid", wrap(DeleteDashboardByUid))
dashboardRoute.Delete("/uid/:uid", wrap(DeleteDashboardByUID))
dashboardRoute.Get("/db/:slug", wrap(GetDashboard))
dashboardRoute.Delete("/db/:slug", wrap(DeleteDashboard))
@@ -313,7 +322,7 @@ func (hs *HttpServer) registerRoutes() {
// metrics
apiRoute.Post("/tsdb/query", bind(dtos.MetricRequest{}), wrap(QueryMetrics))
apiRoute.Get("/tsdb/testdata/scenarios", wrap(GetTestDataScenarios))
apiRoute.Get("/tsdb/testdata/gensql", reqGrafanaAdmin, wrap(GenerateSqlTestData))
apiRoute.Get("/tsdb/testdata/gensql", reqGrafanaAdmin, wrap(GenerateSQLTestData))
apiRoute.Get("/tsdb/testdata/random-walk", wrap(GetTestDataRandomWalk))
apiRoute.Group("/alerts", func(alertsRoute RouteRegister) {
@@ -331,7 +340,7 @@ func (hs *HttpServer) registerRoutes() {
alertNotifications.Post("/test", bind(dtos.NotificationTestCommand{}), wrap(NotificationTest))
alertNotifications.Post("/", bind(m.CreateAlertNotificationCommand{}), wrap(CreateAlertNotification))
alertNotifications.Put("/:notificationId", bind(m.UpdateAlertNotificationCommand{}), wrap(UpdateAlertNotification))
alertNotifications.Get("/:notificationId", wrap(GetAlertNotificationById))
alertNotifications.Get("/:notificationId", wrap(GetAlertNotificationByID))
alertNotifications.Delete("/:notificationId", wrap(DeleteAlertNotification))
}, reqEditorRole)
@@ -340,7 +349,7 @@ func (hs *HttpServer) registerRoutes() {
apiRoute.Group("/annotations", func(annotationsRoute RouteRegister) {
annotationsRoute.Post("/", bind(dtos.PostAnnotationsCmd{}), wrap(PostAnnotation))
annotationsRoute.Delete("/:annotationId", wrap(DeleteAnnotationById))
annotationsRoute.Delete("/:annotationId", wrap(DeleteAnnotationByID))
annotationsRoute.Put("/:annotationId", bind(dtos.UpdateAnnotationsCmd{}), wrap(UpdateAnnotation))
annotationsRoute.Delete("/region/:regionId", wrap(DeleteAnnotationRegion))
annotationsRoute.Post("/graphite", reqEditorRole, bind(dtos.PostGraphiteAnnotationsCmd{}), wrap(PostGraphiteAnnotation))
+10 -11
View File
@@ -4,15 +4,14 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/apikeygen"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
)
func GetApiKeys(c *middleware.Context) Response {
func GetAPIKeys(c *m.ReqContext) Response {
query := m.GetApiKeysQuery{OrgId: c.OrgId}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to list api keys", err)
return Error(500, "Failed to list api keys", err)
}
result := make([]*m.ApiKeyDTO, len(query.Result))
@@ -24,25 +23,25 @@ func GetApiKeys(c *middleware.Context) Response {
}
}
return Json(200, result)
return JSON(200, result)
}
func DeleteApiKey(c *middleware.Context) Response {
func DeleteAPIKey(c *m.ReqContext) Response {
id := c.ParamsInt64(":id")
cmd := &m.DeleteApiKeyCommand{Id: id, OrgId: c.OrgId}
err := bus.Dispatch(cmd)
if err != nil {
return ApiError(500, "Failed to delete API key", err)
return Error(500, "Failed to delete API key", err)
}
return ApiSuccess("API key deleted")
return Success("API key deleted")
}
func AddApiKey(c *middleware.Context, cmd m.AddApiKeyCommand) Response {
func AddAPIKey(c *m.ReqContext, cmd m.AddApiKeyCommand) Response {
if !cmd.Role.IsValid() {
return ApiError(400, "Invalid role specified", nil)
return Error(400, "Invalid role specified", nil)
}
cmd.OrgId = c.OrgId
@@ -51,12 +50,12 @@ func AddApiKey(c *middleware.Context, cmd m.AddApiKeyCommand) Response {
cmd.Key = newKeyInfo.HashedKey
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to add API key", err)
return Error(500, "Failed to add API key", err)
}
result := &dtos.NewApiKeyResult{
Name: cmd.Result.Name,
Key: newKeyInfo.ClientSecret}
return Json(200, result)
return JSON(200, result)
}
+3 -3
View File
@@ -55,11 +55,11 @@ func InitAppPluginRoutes(r *macaron.Macaron) {
}
}
func AppPluginRoute(route *plugins.AppPluginRoute, appId string) macaron.Handler {
return func(c *middleware.Context) {
func AppPluginRoute(route *plugins.AppPluginRoute, appID string) macaron.Handler {
return func(c *m.ReqContext) {
path := c.Params("*")
proxy := pluginproxy.NewApiPluginProxy(c, path, route, appId)
proxy := pluginproxy.NewApiPluginProxy(c, path, route, appID)
proxy.Transport = pluginProxyTransport
proxy.ServeHTTP(c.Resp, c.Req.Request)
}
+2 -5
View File
@@ -258,9 +258,6 @@ func (this *thunderTask) fetch() error {
this.Avatar.data = &bytes.Buffer{}
writer := bufio.NewWriter(this.Avatar.data)
if _, err = io.Copy(writer, resp.Body); err != nil {
return err
}
return nil
_, err = io.Copy(writer, resp.Body)
return err
}
+17 -13
View File
@@ -4,22 +4,22 @@ import (
"encoding/json"
"net/http"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"gopkg.in/macaron.v1"
)
var (
NotFound = func() Response {
return ApiError(404, "Not found", nil)
return Error(404, "Not found", nil)
}
ServerError = func(err error) Response {
return ApiError(500, "Server error", err)
return Error(500, "Server error", err)
}
)
type Response interface {
WriteTo(ctx *middleware.Context)
WriteTo(ctx *m.ReqContext)
}
type NormalResponse struct {
@@ -32,7 +32,7 @@ type NormalResponse struct {
func wrap(action interface{}) macaron.Handler {
return func(c *middleware.Context) {
return func(c *m.ReqContext) {
var res Response
val, err := c.Invoke(action)
if err == nil && val != nil && len(val) > 0 {
@@ -45,7 +45,7 @@ func wrap(action interface{}) macaron.Handler {
}
}
func (r *NormalResponse) WriteTo(ctx *middleware.Context) {
func (r *NormalResponse) WriteTo(ctx *m.ReqContext) {
if r.err != nil {
ctx.Logger.Error(r.errMessage, "error", r.err)
}
@@ -67,22 +67,25 @@ func (r *NormalResponse) Header(key, value string) *NormalResponse {
return r
}
// functions to create responses
// Empty create an empty response
func Empty(status int) *NormalResponse {
return Respond(status, nil)
}
func Json(status int, body interface{}) *NormalResponse {
// JSON create a JSON response
func JSON(status int, body interface{}) *NormalResponse {
return Respond(status, body).Header("Content-Type", "application/json")
}
func ApiSuccess(message string) *NormalResponse {
// Success create a successful response
func Success(message string) *NormalResponse {
resp := make(map[string]interface{})
resp["message"] = message
return Json(200, resp)
return JSON(200, resp)
}
func ApiError(status int, message string, err error) *NormalResponse {
// Error create a erroneous response
func Error(status int, message string, err error) *NormalResponse {
data := make(map[string]interface{})
switch status {
@@ -102,7 +105,7 @@ func ApiError(status int, message string, err error) *NormalResponse {
}
}
resp := Json(status, data)
resp := JSON(status, data)
if err != nil {
resp.errMessage = message
@@ -112,6 +115,7 @@ func ApiError(status int, message string, err error) *NormalResponse {
return resp
}
// Respond create a response
func Respond(status int, body interface{}) *NormalResponse {
var b []byte
var err error
@@ -122,7 +126,7 @@ func Respond(status int, body interface{}) *NormalResponse {
b = []byte(t)
default:
if b, err = json.Marshal(body); err != nil {
return ApiError(500, "body json marshal", err)
return Error(500, "body json marshal", err)
}
}
return &NormalResponse{
+8 -8
View File
@@ -8,22 +8,22 @@ import (
"github.com/go-macaron/session"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
macaron "gopkg.in/macaron.v1"
m "github.com/grafana/grafana/pkg/models"
"gopkg.in/macaron.v1"
. "github.com/smartystreets/goconvey/convey"
)
func loggedInUserScenario(desc string, url string, fn scenarioFunc) {
loggedInUserScenarioWithRole(desc, "GET", url, url, models.ROLE_EDITOR, fn)
loggedInUserScenarioWithRole(desc, "GET", url, url, m.ROLE_EDITOR, fn)
}
func loggedInUserScenarioWithRole(desc string, method string, url string, routePattern string, role models.RoleType, fn scenarioFunc) {
func loggedInUserScenarioWithRole(desc string, method string, url string, routePattern string, role m.RoleType, fn scenarioFunc) {
Convey(desc+" "+url, func() {
defer bus.ClearBusHandlers()
sc := setupScenarioContext(url)
sc.defaultHandler = wrap(func(c *middleware.Context) Response {
sc.defaultHandler = wrap(func(c *m.ReqContext) Response {
sc.context = c
sc.context.UserId = TestUserID
sc.context.OrgId = TestOrgID
@@ -71,7 +71,7 @@ func (sc *scenarioContext) fakeReqWithParams(method, url string, queryParams map
type scenarioContext struct {
m *macaron.Macaron
context *middleware.Context
context *m.ReqContext
resp *httptest.ResponseRecorder
handlerFunc handlerFunc
defaultHandler macaron.Handler
@@ -84,7 +84,7 @@ func (sc *scenarioContext) exec() {
}
type scenarioFunc func(c *scenarioContext)
type handlerFunc func(c *middleware.Context) Response
type handlerFunc func(c *m.ReqContext) Response
func setupScenarioContext(url string) *scenarioContext {
sc := &scenarioContext{
@@ -99,7 +99,7 @@ func setupScenarioContext(url string) *scenarioContext {
}))
sc.m.Use(middleware.GetContextHandler())
sc.m.Use(middleware.Sessioner(&session.Options{}))
sc.m.Use(middleware.Sessioner(&session.Options{}, 0))
return sc
}
+75 -67
View File
@@ -14,20 +14,20 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/quota"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
func isDashboardStarredByUser(c *middleware.Context, dashId int64) (bool, error) {
func isDashboardStarredByUser(c *m.ReqContext, dashID int64) (bool, error) {
if !c.IsSignedIn {
return false, nil
}
query := m.IsStarredByUserQuery{UserId: c.UserId, DashboardId: dashId}
query := m.IsStarredByUserQuery{UserId: c.UserId, DashboardId: dashID}
if err := bus.Dispatch(&query); err != nil {
return false, err
}
@@ -37,13 +37,13 @@ func isDashboardStarredByUser(c *middleware.Context, dashId int64) (bool, error)
func dashboardGuardianResponse(err error) Response {
if err != nil {
return ApiError(500, "Error while checking dashboard permissions", err)
return Error(500, "Error while checking dashboard permissions", err)
}
return ApiError(403, "Access denied to this dashboard", nil)
return Error(403, "Access denied to this dashboard", nil)
}
func GetDashboard(c *middleware.Context) Response {
func GetDashboard(c *m.ReqContext) Response {
dash, rsp := getDashboardHelper(c.OrgId, c.Params(":slug"), 0, c.Params(":uid"))
if rsp != nil {
return rsp
@@ -60,7 +60,7 @@ func GetDashboard(c *middleware.Context) Response {
isStarred, err := isDashboardStarredByUser(c, dash.Id)
if err != nil {
return ApiError(500, "Error while checking if dashboard was starred by user", err)
return Error(500, "Error while checking if dashboard was starred by user", err)
}
// Finding creator and last updater of the dashboard
@@ -96,12 +96,22 @@ func GetDashboard(c *middleware.Context) Response {
if dash.FolderId > 0 {
query := m.GetDashboardQuery{Id: dash.FolderId, OrgId: c.OrgId}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Dashboard folder could not be read", err)
return Error(500, "Dashboard folder could not be read", err)
}
meta.FolderTitle = query.Result.Title
meta.FolderUrl = query.Result.GetUrl()
}
isDashboardProvisioned := &m.IsDashboardProvisionedQuery{DashboardId: dash.Id}
err = bus.Dispatch(isDashboardProvisioned)
if err != nil {
return Error(500, "Error while checking if dashboard is provisioned", err)
}
if isDashboardProvisioned.Result {
meta.Provisioned = true
}
// make sure db version is in sync with json model version
dash.Data.Set("version", dash.Version)
@@ -111,45 +121,43 @@ func GetDashboard(c *middleware.Context) Response {
}
c.TimeRequest(metrics.M_Api_Dashboard_Get)
return Json(200, dto)
return JSON(200, dto)
}
func getUserLogin(userId int64) string {
query := m.GetUserByIdQuery{Id: userId}
func getUserLogin(userID int64) string {
query := m.GetUserByIdQuery{Id: userID}
err := bus.Dispatch(&query)
if err != nil {
return "Anonymous"
} else {
user := query.Result
return user.Login
}
return query.Result.Login
}
func getDashboardHelper(orgId int64, slug string, id int64, uid string) (*m.Dashboard, Response) {
func getDashboardHelper(orgID int64, slug string, id int64, uid string) (*m.Dashboard, Response) {
var query m.GetDashboardQuery
if len(uid) > 0 {
query = m.GetDashboardQuery{Uid: uid, Id: id, OrgId: orgId}
query = m.GetDashboardQuery{Uid: uid, Id: id, OrgId: orgID}
} else {
query = m.GetDashboardQuery{Slug: slug, Id: id, OrgId: orgId}
query = m.GetDashboardQuery{Slug: slug, Id: id, OrgId: orgID}
}
if err := bus.Dispatch(&query); err != nil {
return nil, ApiError(404, "Dashboard not found", err)
return nil, Error(404, "Dashboard not found", err)
}
return query.Result, nil
}
func DeleteDashboard(c *middleware.Context) Response {
func DeleteDashboard(c *m.ReqContext) Response {
query := m.GetDashboardsBySlugQuery{OrgId: c.OrgId, Slug: c.Params(":slug")}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to retrieve dashboards by slug", err)
return Error(500, "Failed to retrieve dashboards by slug", err)
}
if len(query.Result) > 1 {
return Json(412, util.DynMap{"status": "multiple-slugs-exists", "message": m.ErrDashboardsWithSameSlugExists.Error()})
return JSON(412, util.DynMap{"status": "multiple-slugs-exists", "message": m.ErrDashboardsWithSameSlugExists.Error()})
}
dash, rsp := getDashboardHelper(c.OrgId, c.Params(":slug"), 0, "")
@@ -164,16 +172,16 @@ func DeleteDashboard(c *middleware.Context) Response {
cmd := m.DeleteDashboardCommand{OrgId: c.OrgId, Id: dash.Id}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to delete dashboard", err)
return Error(500, "Failed to delete dashboard", err)
}
return Json(200, util.DynMap{
return JSON(200, util.DynMap{
"title": dash.Title,
"message": fmt.Sprintf("Dashboard %s deleted", dash.Title),
})
}
func DeleteDashboardByUid(c *middleware.Context) Response {
func DeleteDashboardByUID(c *m.ReqContext) Response {
dash, rsp := getDashboardHelper(c.OrgId, "", 0, c.Params(":uid"))
if rsp != nil {
return rsp
@@ -186,28 +194,28 @@ func DeleteDashboardByUid(c *middleware.Context) Response {
cmd := m.DeleteDashboardCommand{OrgId: c.OrgId, Id: dash.Id}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to delete dashboard", err)
return Error(500, "Failed to delete dashboard", err)
}
return Json(200, util.DynMap{
return JSON(200, util.DynMap{
"title": dash.Title,
"message": fmt.Sprintf("Dashboard %s deleted", dash.Title),
})
}
func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response {
func PostDashboard(c *m.ReqContext, cmd m.SaveDashboardCommand) Response {
cmd.OrgId = c.OrgId
cmd.UserId = c.UserId
dash := cmd.GetDashboardModel()
if dash.Id == 0 && dash.Uid == "" {
limitReached, err := middleware.QuotaReached(c, "dashboard")
limitReached, err := quota.QuotaReached(c, "dashboard")
if err != nil {
return ApiError(500, "failed to get quota", err)
return Error(500, "failed to get quota", err)
}
if limitReached {
return ApiError(403, "Quota reached", nil)
return Error(403, "Quota reached", nil)
}
}
@@ -230,24 +238,25 @@ func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response {
err == m.ErrDashboardWithSameUIDExists ||
err == m.ErrFolderNotFound ||
err == m.ErrDashboardFolderCannotHaveParent ||
err == m.ErrDashboardFolderNameExists {
return ApiError(400, err.Error(), nil)
err == m.ErrDashboardFolderNameExists ||
err == m.ErrDashboardCannotSaveProvisionedDashboard {
return Error(400, err.Error(), nil)
}
if err == m.ErrDashboardUpdateAccessDenied {
return ApiError(403, err.Error(), err)
return Error(403, err.Error(), err)
}
if err == m.ErrDashboardContainsInvalidAlertData {
return ApiError(500, "Invalid alert data. Cannot save dashboard", err)
return Error(500, "Invalid alert data. Cannot save dashboard", err)
}
if err != nil {
if err == m.ErrDashboardWithSameNameInFolderExists {
return Json(412, util.DynMap{"status": "name-exists", "message": err.Error()})
return JSON(412, util.DynMap{"status": "name-exists", "message": err.Error()})
}
if err == m.ErrDashboardVersionMismatch {
return Json(412, util.DynMap{"status": "version-mismatch", "message": err.Error()})
return JSON(412, util.DynMap{"status": "version-mismatch", "message": err.Error()})
}
if pluginErr, ok := err.(m.UpdatePluginDashboardError); ok {
message := "The dashboard belongs to plugin " + pluginErr.PluginId + "."
@@ -255,20 +264,20 @@ func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response {
if pluginDef, exist := plugins.Plugins[pluginErr.PluginId]; exist {
message = "The dashboard belongs to plugin " + pluginDef.Name + "."
}
return Json(412, util.DynMap{"status": "plugin-dashboard", "message": message})
return JSON(412, util.DynMap{"status": "plugin-dashboard", "message": message})
}
if err == m.ErrDashboardNotFound {
return Json(404, util.DynMap{"status": "not-found", "message": err.Error()})
return JSON(404, util.DynMap{"status": "not-found", "message": err.Error()})
}
return ApiError(500, "Failed to save dashboard", err)
return Error(500, "Failed to save dashboard", err)
}
if err == m.ErrDashboardFailedToUpdateAlertData {
return ApiError(500, "Invalid alert data. Cannot save dashboard", err)
return Error(500, "Invalid alert data. Cannot save dashboard", err)
}
c.TimeRequest(metrics.M_Api_Dashboard_Save)
return Json(200, util.DynMap{
return JSON(200, util.DynMap{
"status": "success",
"slug": dashboard.Slug,
"version": dashboard.Version,
@@ -278,10 +287,10 @@ func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response {
})
}
func GetHomeDashboard(c *middleware.Context) Response {
func GetHomeDashboard(c *m.ReqContext) Response {
prefsQuery := m.GetPreferencesWithDefaultsQuery{OrgId: c.OrgId, UserId: c.UserId}
if err := bus.Dispatch(&prefsQuery); err != nil {
return ApiError(500, "Failed to get preferences", err)
return Error(500, "Failed to get preferences", err)
}
if prefsQuery.Result.HomeDashboardId != 0 {
@@ -290,16 +299,15 @@ func GetHomeDashboard(c *middleware.Context) Response {
if err == nil {
url := m.GetDashboardUrl(slugQuery.Result.Uid, slugQuery.Result.Slug)
dashRedirect := dtos.DashboardRedirect{RedirectUri: url}
return Json(200, &dashRedirect)
} else {
log.Warn("Failed to get slug from database, %s", err.Error())
return JSON(200, &dashRedirect)
}
log.Warn("Failed to get slug from database, %s", err.Error())
}
filePath := path.Join(setting.StaticRootPath, "dashboards/home.json")
file, err := os.Open(filePath)
if err != nil {
return ApiError(500, "Failed to load home dashboard", err)
return Error(500, "Failed to load home dashboard", err)
}
dash := dtos.DashboardFullWithMeta{}
@@ -309,14 +317,14 @@ func GetHomeDashboard(c *middleware.Context) Response {
jsonParser := json.NewDecoder(file)
if err := jsonParser.Decode(&dash.Dashboard); err != nil {
return ApiError(500, "Failed to load home dashboard", err)
return Error(500, "Failed to load home dashboard", err)
}
if c.HasUserRole(m.ROLE_ADMIN) && !c.HasHelpFlag(m.HelpFlagGettingStartedPanelDismissed) {
addGettingStartedPanelToHomeDashboard(dash.Dashboard)
}
return Json(200, &dash)
return JSON(200, &dash)
}
func addGettingStartedPanelToHomeDashboard(dash *simplejson.Json) {
@@ -338,23 +346,23 @@ func addGettingStartedPanelToHomeDashboard(dash *simplejson.Json) {
}
// GetDashboardVersions returns all dashboard versions as JSON
func GetDashboardVersions(c *middleware.Context) Response {
dashId := c.ParamsInt64(":dashboardId")
func GetDashboardVersions(c *m.ReqContext) Response {
dashID := c.ParamsInt64(":dashboardId")
guardian := guardian.New(dashId, c.OrgId, c.SignedInUser)
guardian := guardian.New(dashID, c.OrgId, c.SignedInUser)
if canSave, err := guardian.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
query := m.GetDashboardVersionsQuery{
OrgId: c.OrgId,
DashboardId: dashId,
DashboardId: dashID,
Limit: c.QueryInt("limit"),
Start: c.QueryInt("start"),
}
if err := bus.Dispatch(&query); err != nil {
return ApiError(404, fmt.Sprintf("No versions found for dashboardId %d", dashId), err)
return Error(404, fmt.Sprintf("No versions found for dashboardId %d", dashID), err)
}
for _, version := range query.Result {
@@ -373,26 +381,26 @@ func GetDashboardVersions(c *middleware.Context) Response {
}
}
return Json(200, query.Result)
return JSON(200, query.Result)
}
// GetDashboardVersion returns the dashboard version with the given ID.
func GetDashboardVersion(c *middleware.Context) Response {
dashId := c.ParamsInt64(":dashboardId")
func GetDashboardVersion(c *m.ReqContext) Response {
dashID := c.ParamsInt64(":dashboardId")
guardian := guardian.New(dashId, c.OrgId, c.SignedInUser)
guardian := guardian.New(dashID, c.OrgId, c.SignedInUser)
if canSave, err := guardian.CanSave(); err != nil || !canSave {
return dashboardGuardianResponse(err)
}
query := m.GetDashboardVersionQuery{
OrgId: c.OrgId,
DashboardId: dashId,
DashboardId: dashID,
Version: c.ParamsInt(":id"),
}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, fmt.Sprintf("Dashboard version %d not found for dashboardId %d", query.Version, dashId), err)
return Error(500, fmt.Sprintf("Dashboard version %d not found for dashboardId %d", query.Version, dashID), err)
}
creator := "Anonymous"
@@ -405,11 +413,11 @@ func GetDashboardVersion(c *middleware.Context) Response {
CreatedBy: creator,
}
return Json(200, dashVersionMeta)
return JSON(200, dashVersionMeta)
}
// POST /api/dashboards/calculate-diff performs diffs on two dashboards
func CalculateDashboardDiff(c *middleware.Context, apiOptions dtos.CalculateDiffOptions) Response {
func CalculateDashboardDiff(c *m.ReqContext, apiOptions dtos.CalculateDiffOptions) Response {
guardianBase := guardian.New(apiOptions.Base.DashboardId, c.OrgId, c.SignedInUser)
if canSave, err := guardianBase.CanSave(); err != nil || !canSave {
@@ -441,9 +449,9 @@ func CalculateDashboardDiff(c *middleware.Context, apiOptions dtos.CalculateDiff
result, err := dashdiffs.CalculateDiff(&options)
if err != nil {
if err == m.ErrDashboardVersionNotFound {
return ApiError(404, "Dashboard version not found", err)
return Error(404, "Dashboard version not found", err)
}
return ApiError(500, "Unable to compute diff", err)
return Error(500, "Unable to compute diff", err)
}
if options.DiffType == dashdiffs.DiffDelta {
@@ -454,7 +462,7 @@ func CalculateDashboardDiff(c *middleware.Context, apiOptions dtos.CalculateDiff
}
// RestoreDashboardVersion restores a dashboard to the given version.
func RestoreDashboardVersion(c *middleware.Context, apiCmd dtos.RestoreDashboardVersionCommand) Response {
func RestoreDashboardVersion(c *m.ReqContext, apiCmd dtos.RestoreDashboardVersionCommand) Response {
dash, rsp := getDashboardHelper(c.OrgId, "", c.ParamsInt64(":dashboardId"), "")
if rsp != nil {
return rsp
@@ -467,7 +475,7 @@ func RestoreDashboardVersion(c *middleware.Context, apiCmd dtos.RestoreDashboard
versionQuery := m.GetDashboardVersionQuery{DashboardId: dash.Id, Version: apiCmd.Version, OrgId: c.OrgId}
if err := bus.Dispatch(&versionQuery); err != nil {
return ApiError(404, "Dashboard version not found", nil)
return Error(404, "Dashboard version not found", nil)
}
version := versionQuery.Result
@@ -484,7 +492,7 @@ func RestoreDashboardVersion(c *middleware.Context, apiCmd dtos.RestoreDashboard
return PostDashboard(c, saveCmd)
}
func GetDashboardTags(c *middleware.Context) {
func GetDashboardTags(c *m.ReqContext) {
query := m.GetDashboardTagsQuery{OrgId: c.OrgId}
err := bus.Dispatch(&query)
if err != nil {
+23 -19
View File
@@ -5,20 +5,19 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/guardian"
)
func GetDashboardPermissionList(c *middleware.Context) Response {
dashId := c.ParamsInt64(":dashboardId")
func GetDashboardPermissionList(c *m.ReqContext) Response {
dashID := c.ParamsInt64(":dashboardId")
_, rsp := getDashboardHelper(c.OrgId, "", dashId, "")
_, rsp := getDashboardHelper(c.OrgId, "", dashID, "")
if rsp != nil {
return rsp
}
g := guardian.New(dashId, c.OrgId, c.SignedInUser)
g := guardian.New(dashID, c.OrgId, c.SignedInUser)
if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin {
return dashboardGuardianResponse(err)
@@ -26,38 +25,43 @@ func GetDashboardPermissionList(c *middleware.Context) Response {
acl, err := g.GetAcl()
if err != nil {
return ApiError(500, "Failed to get dashboard permissions", err)
return Error(500, "Failed to get dashboard permissions", err)
}
for _, perm := range acl {
perm.UserAvatarUrl = dtos.GetGravatarUrl(perm.UserEmail)
if perm.TeamId > 0 {
perm.TeamAvatarUrl = dtos.GetGravatarUrlWithDefault(perm.TeamEmail, perm.Team)
}
if perm.Slug != "" {
perm.Url = m.GetDashboardFolderUrl(perm.IsFolder, perm.Uid, perm.Slug)
}
}
return Json(200, acl)
return JSON(200, acl)
}
func UpdateDashboardPermissions(c *middleware.Context, apiCmd dtos.UpdateDashboardAclCommand) Response {
dashId := c.ParamsInt64(":dashboardId")
func UpdateDashboardPermissions(c *m.ReqContext, apiCmd dtos.UpdateDashboardAclCommand) Response {
dashID := c.ParamsInt64(":dashboardId")
_, rsp := getDashboardHelper(c.OrgId, "", dashId, "")
_, rsp := getDashboardHelper(c.OrgId, "", dashID, "")
if rsp != nil {
return rsp
}
g := guardian.New(dashId, c.OrgId, c.SignedInUser)
g := guardian.New(dashID, c.OrgId, c.SignedInUser)
if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin {
return dashboardGuardianResponse(err)
}
cmd := m.UpdateDashboardAclCommand{}
cmd.DashboardId = dashId
cmd.DashboardId = dashID
for _, item := range apiCmd.Items {
cmd.Items = append(cmd.Items, &m.DashboardAcl{
OrgId: c.OrgId,
DashboardId: dashId,
DashboardId: dashID,
UserId: item.UserId,
TeamId: item.TeamId,
Role: item.Role,
@@ -71,21 +75,21 @@ func UpdateDashboardPermissions(c *middleware.Context, apiCmd dtos.UpdateDashboa
if err != nil {
if err == guardian.ErrGuardianPermissionExists ||
err == guardian.ErrGuardianOverride {
return ApiError(400, err.Error(), err)
return Error(400, err.Error(), err)
}
return ApiError(500, "Error while checking dashboard permissions", err)
return Error(500, "Error while checking dashboard permissions", err)
}
return ApiError(403, "Cannot remove own admin permission for a folder", nil)
return Error(403, "Cannot remove own admin permission for a folder", nil)
}
if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrDashboardAclInfoMissing || err == m.ErrDashboardPermissionDashboardEmpty {
return ApiError(409, err.Error(), err)
return Error(409, err.Error(), err)
}
return ApiError(500, "Failed to create permission", err)
return Error(500, "Failed to create permission", err)
}
return ApiSuccess("Dashboard permissions updated")
return Success("Dashboard permissions updated")
}
+2 -3
View File
@@ -6,7 +6,6 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/guardian"
@@ -144,7 +143,7 @@ func TestDashboardPermissionApiEndpoint(t *testing.T) {
})
})
Convey("When trying to override inherited permissions with lower presedence", func() {
Convey("When trying to override inherited permissions with lower precedence", func() {
origNewGuardian := guardian.New
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
CanAdminValue: true,
@@ -195,7 +194,7 @@ func updateDashboardPermissionScenario(desc string, url string, routePattern str
sc := setupScenarioContext(url)
sc.defaultHandler = wrap(func(c *middleware.Context) Response {
sc.defaultHandler = wrap(func(c *m.ReqContext) Response {
sc.context = c
sc.context.OrgId = TestOrgID
sc.context.UserId = TestUserID
+15 -16
View File
@@ -6,14 +6,13 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
func GetSharingOptions(c *middleware.Context) {
func GetSharingOptions(c *m.ReqContext) {
c.JSON(200, util.DynMap{
"externalSnapshotURL": setting.ExternalSnapshotUrl,
"externalSnapshotName": setting.ExternalSnapshotName,
@@ -21,7 +20,7 @@ func GetSharingOptions(c *middleware.Context) {
})
}
func CreateDashboardSnapshot(c *middleware.Context, cmd m.CreateDashboardSnapshotCommand) {
func CreateDashboardSnapshot(c *m.ReqContext, cmd m.CreateDashboardSnapshotCommand) {
if cmd.Name == "" {
cmd.Name = "Unnamed snapshot"
}
@@ -58,7 +57,7 @@ func CreateDashboardSnapshot(c *middleware.Context, cmd m.CreateDashboardSnapsho
}
// GET /api/snapshots/:key
func GetDashboardSnapshot(c *middleware.Context) {
func GetDashboardSnapshot(c *m.ReqContext) {
key := c.Params(":key")
query := &m.GetDashboardSnapshotQuery{Key: key}
@@ -93,43 +92,43 @@ func GetDashboardSnapshot(c *middleware.Context) {
}
// GET /api/snapshots-delete/:key
func DeleteDashboardSnapshot(c *middleware.Context) Response {
func DeleteDashboardSnapshot(c *m.ReqContext) Response {
key := c.Params(":key")
query := &m.GetDashboardSnapshotQuery{DeleteKey: key}
err := bus.Dispatch(query)
if err != nil {
return ApiError(500, "Failed to get dashboard snapshot", err)
return Error(500, "Failed to get dashboard snapshot", err)
}
if query.Result == nil {
return ApiError(404, "Failed to get dashboard snapshot", nil)
return Error(404, "Failed to get dashboard snapshot", nil)
}
dashboard := query.Result.Dashboard
dashboardId := dashboard.Get("id").MustInt64()
dashboardID := dashboard.Get("id").MustInt64()
guardian := guardian.New(dashboardId, c.OrgId, c.SignedInUser)
guardian := guardian.New(dashboardID, c.OrgId, c.SignedInUser)
canEdit, err := guardian.CanEdit()
if err != nil {
return ApiError(500, "Error while checking permissions for snapshot", err)
return Error(500, "Error while checking permissions for snapshot", err)
}
if !canEdit && query.Result.UserId != c.SignedInUser.UserId {
return ApiError(403, "Access denied to this snapshot", nil)
return Error(403, "Access denied to this snapshot", nil)
}
cmd := &m.DeleteDashboardSnapshotCommand{DeleteKey: key}
if err := bus.Dispatch(cmd); err != nil {
return ApiError(500, "Failed to delete dashboard snapshot", err)
return Error(500, "Failed to delete dashboard snapshot", err)
}
return Json(200, util.DynMap{"message": "Snapshot deleted. It might take an hour before it's cleared from a CDN cache."})
return JSON(200, util.DynMap{"message": "Snapshot deleted. It might take an hour before it's cleared from a CDN cache."})
}
// GET /api/dashboard/snapshots
func SearchDashboardSnapshots(c *middleware.Context) Response {
func SearchDashboardSnapshots(c *m.ReqContext) Response {
query := c.Query("query")
limit := c.QueryInt("limit")
@@ -146,7 +145,7 @@ func SearchDashboardSnapshots(c *middleware.Context) Response {
err := bus.Dispatch(&searchQuery)
if err != nil {
return ApiError(500, "Search failed", err)
return Error(500, "Search failed", err)
}
dtos := make([]*m.DashboardSnapshotDTO, len(searchQuery.Result))
@@ -166,5 +165,5 @@ func SearchDashboardSnapshots(c *middleware.Context) Response {
}
}
return Json(200, dtos)
return JSON(200, dtos)
}
+36 -16
View File
@@ -8,7 +8,6 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/setting"
@@ -43,6 +42,11 @@ func TestDashboardApiEndpoint(t *testing.T) {
return nil
})
bus.AddHandler("test", func(query *m.IsDashboardProvisionedQuery) error {
query.Result = false
return nil
})
viewerRole := m.ROLE_VIEWER
editorRole := m.ROLE_EDITOR
@@ -106,7 +110,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
})
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
CallDeleteDashboardByUid(sc)
CallDeleteDashboardByUID(sc)
So(sc.resp.Code, ShouldEqual, 403)
Convey("Should lookup dashboard by uid", func() {
@@ -166,7 +170,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
})
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
CallDeleteDashboardByUid(sc)
CallDeleteDashboardByUID(sc)
So(sc.resp.Code, ShouldEqual, 200)
Convey("Should lookup dashboard by uid", func() {
@@ -193,6 +197,11 @@ func TestDashboardApiEndpoint(t *testing.T) {
fakeDash.HasAcl = true
setting.ViewersCanEdit = false
bus.AddHandler("test", func(query *m.IsDashboardProvisionedQuery) error {
query.Result = false
return nil
})
bus.AddHandler("test", func(query *m.GetDashboardsBySlugQuery) error {
dashboards := []*m.Dashboard{fakeDash}
query.Result = dashboards
@@ -272,7 +281,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
})
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
CallDeleteDashboardByUid(sc)
CallDeleteDashboardByUID(sc)
So(sc.resp.Code, ShouldEqual, 403)
Convey("Should lookup dashboard by uid", func() {
@@ -330,7 +339,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
})
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
CallDeleteDashboardByUid(sc)
CallDeleteDashboardByUID(sc)
So(sc.resp.Code, ShouldEqual, 403)
Convey("Should lookup dashboard by uid", func() {
@@ -399,7 +408,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
})
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
CallDeleteDashboardByUid(sc)
CallDeleteDashboardByUID(sc)
So(sc.resp.Code, ShouldEqual, 200)
Convey("Should lookup dashboard by uid", func() {
@@ -469,7 +478,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
})
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
CallDeleteDashboardByUid(sc)
CallDeleteDashboardByUID(sc)
So(sc.resp.Code, ShouldEqual, 403)
Convey("Should lookup dashboard by uid", func() {
@@ -528,7 +537,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
})
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
CallDeleteDashboardByUid(sc)
CallDeleteDashboardByUID(sc)
So(sc.resp.Code, ShouldEqual, 200)
Convey("Should lookup dashboard by uid", func() {
@@ -595,7 +604,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
})
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
CallDeleteDashboardByUid(sc)
CallDeleteDashboardByUID(sc)
So(sc.resp.Code, ShouldEqual, 403)
Convey("Should lookup dashboard by uid", func() {
@@ -626,6 +635,11 @@ func TestDashboardApiEndpoint(t *testing.T) {
dashTwo.FolderId = 3
dashTwo.HasAcl = false
bus.AddHandler("test", func(query *m.IsDashboardProvisionedQuery) error {
query.Result = false
return nil
})
bus.AddHandler("test", func(query *m.GetDashboardsBySlugQuery) error {
dashboards := []*m.Dashboard{dashOne, dashTwo}
query.Result = dashboards
@@ -639,7 +653,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
Convey("Should result in 412 Precondition failed", func() {
So(sc.resp.Code, ShouldEqual, 412)
result := sc.ToJson()
result := sc.ToJSON()
So(result.Get("status").MustString(), ShouldEqual, "multiple-slugs-exists")
So(result.Get("message").MustString(), ShouldEqual, m.ErrDashboardsWithSameSlugExists.Error())
})
@@ -687,7 +701,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
})
Convey("It should return correct response data", func() {
result := sc.ToJson()
result := sc.ToJSON()
So(result.Get("status").MustString(), ShouldEqual, "success")
So(result.Get("id").MustInt64(), ShouldEqual, 2)
So(result.Get("uid").MustString(), ShouldEqual, "uid")
@@ -721,6 +735,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
{SaveError: m.ErrDashboardUpdateAccessDenied, ExpectedStatusCode: 403},
{SaveError: m.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
{SaveError: m.ErrDashboardUidToLong, ExpectedStatusCode: 400},
{SaveError: m.ErrDashboardCannotSaveProvisionedDashboard, ExpectedStatusCode: 400},
{SaveError: m.UpdatePluginDashboardError{PluginId: "plug"}, ExpectedStatusCode: 412},
}
@@ -751,6 +766,11 @@ func TestDashboardApiEndpoint(t *testing.T) {
return nil
})
bus.AddHandler("test", func(query *m.IsDashboardProvisionedQuery) error {
query.Result = false
return nil
})
bus.AddHandler("test", func(query *m.GetDashboardVersionQuery) error {
query.Result = &m.DashboardVersion{
Data: simplejson.NewFromAny(map[string]interface{}{
@@ -838,12 +858,12 @@ func CallDeleteDashboard(sc *scenarioContext) {
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
}
func CallDeleteDashboardByUid(sc *scenarioContext) {
func CallDeleteDashboardByUID(sc *scenarioContext) {
bus.AddHandler("test", func(cmd *m.DeleteDashboardCommand) error {
return nil
})
sc.handlerFunc = DeleteDashboardByUid
sc.handlerFunc = DeleteDashboardByUID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
}
@@ -862,7 +882,7 @@ func postDashboardScenario(desc string, url string, routePattern string, mock *d
defer bus.ClearBusHandlers()
sc := setupScenarioContext(url)
sc.defaultHandler = wrap(func(c *middleware.Context) Response {
sc.defaultHandler = wrap(func(c *m.ReqContext) Response {
sc.context = c
sc.context.SignedInUser = &m.SignedInUser{OrgId: cmd.OrgId, UserId: cmd.UserId}
@@ -887,7 +907,7 @@ func postDiffScenario(desc string, url string, routePattern string, cmd dtos.Cal
defer bus.ClearBusHandlers()
sc := setupScenarioContext(url)
sc.defaultHandler = wrap(func(c *middleware.Context) Response {
sc.defaultHandler = wrap(func(c *m.ReqContext) Response {
sc.context = c
sc.context.SignedInUser = &m.SignedInUser{
OrgId: TestOrgID,
@@ -904,7 +924,7 @@ func postDiffScenario(desc string, url string, routePattern string, cmd dtos.Cal
})
}
func (sc *scenarioContext) ToJson() *simplejson.Json {
func (sc *scenarioContext) ToJSON() *simplejson.Json {
var result *simplejson.Json
err := json.NewDecoder(sc.resp.Body).Decode(&result)
So(err, ShouldBeNil)
+5 -6
View File
@@ -7,26 +7,25 @@ import (
"github.com/grafana/grafana/pkg/api/pluginproxy"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
)
const HeaderNameNoBackendCache = "X-Grafana-NoCache"
func (hs *HttpServer) getDatasourceById(id int64, orgId int64, nocache bool) (*m.DataSource, error) {
func (hs *HTTPServer) getDatasourceByID(id int64, orgID int64, nocache bool) (*m.DataSource, error) {
cacheKey := fmt.Sprintf("ds-%d", id)
if !nocache {
if cached, found := hs.cache.Get(cacheKey); found {
ds := cached.(*m.DataSource)
if ds.OrgId == orgId {
if ds.OrgId == orgID {
return ds, nil
}
}
}
query := m.GetDataSourceByIdQuery{Id: id, OrgId: orgId}
query := m.GetDataSourceByIdQuery{Id: id, OrgId: orgID}
if err := bus.Dispatch(&query); err != nil {
return nil, err
}
@@ -35,12 +34,12 @@ func (hs *HttpServer) getDatasourceById(id int64, orgId int64, nocache bool) (*m
return query.Result, nil
}
func (hs *HttpServer) ProxyDataSourceRequest(c *middleware.Context) {
func (hs *HTTPServer) ProxyDataSourceRequest(c *m.ReqContext) {
c.TimeRequest(metrics.M_DataSource_ProxyReq_Timer)
nocache := c.Req.Header.Get(HeaderNameNoBackendCache) == "true"
ds, err := hs.getDatasourceById(c.ParamsInt64(":id"), c.OrgId, nocache)
ds, err := hs.getDatasourceByID(c.ParamsInt64(":id"), c.OrgId, nocache)
if err != nil {
c.JsonApiErr(500, "Unable to load datasource meta data", err)
+44 -46
View File
@@ -5,17 +5,16 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/util"
)
func GetDataSources(c *middleware.Context) Response {
func GetDataSources(c *m.ReqContext) Response {
query := m.GetDataSourcesQuery{OrgId: c.OrgId}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to query datasources", err)
return Error(500, "Failed to query datasources", err)
}
result := make(dtos.DataSourceList, 0)
@@ -47,10 +46,10 @@ func GetDataSources(c *middleware.Context) Response {
sort.Sort(result)
return Json(200, &result)
return JSON(200, &result)
}
func GetDataSourceById(c *middleware.Context) Response {
func GetDataSourceByID(c *m.ReqContext) Response {
query := m.GetDataSourceByIdQuery{
Id: c.ParamsInt64(":id"),
OrgId: c.OrgId,
@@ -58,81 +57,81 @@ func GetDataSourceById(c *middleware.Context) Response {
if err := bus.Dispatch(&query); err != nil {
if err == m.ErrDataSourceNotFound {
return ApiError(404, "Data source not found", nil)
return Error(404, "Data source not found", nil)
}
return ApiError(500, "Failed to query datasources", err)
return Error(500, "Failed to query datasources", err)
}
ds := query.Result
dtos := convertModelToDtos(ds)
return Json(200, &dtos)
return JSON(200, &dtos)
}
func DeleteDataSourceById(c *middleware.Context) Response {
func DeleteDataSourceByID(c *m.ReqContext) Response {
id := c.ParamsInt64(":id")
if id <= 0 {
return ApiError(400, "Missing valid datasource id", nil)
return Error(400, "Missing valid datasource id", nil)
}
ds, err := getRawDataSourceById(id, c.OrgId)
ds, err := getRawDataSourceByID(id, c.OrgId)
if err != nil {
return ApiError(400, "Failed to delete datasource", nil)
return Error(400, "Failed to delete datasource", nil)
}
if ds.ReadOnly {
return ApiError(403, "Cannot delete read-only data source", nil)
return Error(403, "Cannot delete read-only data source", nil)
}
cmd := &m.DeleteDataSourceByIdCommand{Id: id, OrgId: c.OrgId}
err = bus.Dispatch(cmd)
if err != nil {
return ApiError(500, "Failed to delete datasource", err)
return Error(500, "Failed to delete datasource", err)
}
return ApiSuccess("Data source deleted")
return Success("Data source deleted")
}
func DeleteDataSourceByName(c *middleware.Context) Response {
func DeleteDataSourceByName(c *m.ReqContext) Response {
name := c.Params(":name")
if name == "" {
return ApiError(400, "Missing valid datasource name", nil)
return Error(400, "Missing valid datasource name", nil)
}
getCmd := &m.GetDataSourceByNameQuery{Name: name, OrgId: c.OrgId}
if err := bus.Dispatch(getCmd); err != nil {
return ApiError(500, "Failed to delete datasource", err)
return Error(500, "Failed to delete datasource", err)
}
if getCmd.Result.ReadOnly {
return ApiError(403, "Cannot delete read-only data source", nil)
return Error(403, "Cannot delete read-only data source", nil)
}
cmd := &m.DeleteDataSourceByNameCommand{Name: name, OrgId: c.OrgId}
err := bus.Dispatch(cmd)
if err != nil {
return ApiError(500, "Failed to delete datasource", err)
return Error(500, "Failed to delete datasource", err)
}
return ApiSuccess("Data source deleted")
return Success("Data source deleted")
}
func AddDataSource(c *middleware.Context, cmd m.AddDataSourceCommand) Response {
func AddDataSource(c *m.ReqContext, cmd m.AddDataSourceCommand) Response {
cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrDataSourceNameExists {
return ApiError(409, err.Error(), err)
return Error(409, err.Error(), err)
}
return ApiError(500, "Failed to add datasource", err)
return Error(500, "Failed to add datasource", err)
}
ds := convertModelToDtos(cmd.Result)
return Json(200, util.DynMap{
return JSON(200, util.DynMap{
"message": "Datasource added",
"id": cmd.Result.Id,
"name": cmd.Result.Name,
@@ -140,25 +139,24 @@ func AddDataSource(c *middleware.Context, cmd m.AddDataSourceCommand) Response {
})
}
func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) Response {
func UpdateDataSource(c *m.ReqContext, cmd m.UpdateDataSourceCommand) Response {
cmd.OrgId = c.OrgId
cmd.Id = c.ParamsInt64(":id")
err := fillWithSecureJsonData(&cmd)
err := fillWithSecureJSONData(&cmd)
if err != nil {
return ApiError(500, "Failed to update datasource", err)
return Error(500, "Failed to update datasource", err)
}
err = bus.Dispatch(&cmd)
if err != nil {
if err == m.ErrDataSourceUpdatingOldVersion {
return ApiError(500, "Failed to update datasource. Reload new version and try again", err)
} else {
return ApiError(500, "Failed to update datasource", err)
return Error(500, "Failed to update datasource. Reload new version and try again", err)
}
return Error(500, "Failed to update datasource", err)
}
ds := convertModelToDtos(cmd.Result)
return Json(200, util.DynMap{
return JSON(200, util.DynMap{
"message": "Datasource updated",
"id": cmd.Id,
"name": cmd.Name,
@@ -166,12 +164,12 @@ func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) Resp
})
}
func fillWithSecureJsonData(cmd *m.UpdateDataSourceCommand) error {
func fillWithSecureJSONData(cmd *m.UpdateDataSourceCommand) error {
if len(cmd.SecureJsonData) == 0 {
return nil
}
ds, err := getRawDataSourceById(cmd.Id, cmd.OrgId)
ds, err := getRawDataSourceByID(cmd.Id, cmd.OrgId)
if err != nil {
return err
}
@@ -180,8 +178,8 @@ func fillWithSecureJsonData(cmd *m.UpdateDataSourceCommand) error {
return m.ErrDatasourceIsReadOnly
}
secureJsonData := ds.SecureJsonData.Decrypt()
for k, v := range secureJsonData {
secureJSONData := ds.SecureJsonData.Decrypt()
for k, v := range secureJSONData {
if _, ok := cmd.SecureJsonData[k]; !ok {
cmd.SecureJsonData[k] = v
@@ -191,10 +189,10 @@ func fillWithSecureJsonData(cmd *m.UpdateDataSourceCommand) error {
return nil
}
func getRawDataSourceById(id int64, orgId int64) (*m.DataSource, error) {
func getRawDataSourceByID(id int64, orgID int64) (*m.DataSource, error) {
query := m.GetDataSourceByIdQuery{
Id: id,
OrgId: orgId,
OrgId: orgID,
}
if err := bus.Dispatch(&query); err != nil {
@@ -205,30 +203,30 @@ func getRawDataSourceById(id int64, orgId int64) (*m.DataSource, error) {
}
// Get /api/datasources/name/:name
func GetDataSourceByName(c *middleware.Context) Response {
func GetDataSourceByName(c *m.ReqContext) Response {
query := m.GetDataSourceByNameQuery{Name: c.Params(":name"), OrgId: c.OrgId}
if err := bus.Dispatch(&query); err != nil {
if err == m.ErrDataSourceNotFound {
return ApiError(404, "Data source not found", nil)
return Error(404, "Data source not found", nil)
}
return ApiError(500, "Failed to query datasources", err)
return Error(500, "Failed to query datasources", err)
}
dtos := convertModelToDtos(query.Result)
dtos.ReadOnly = true
return Json(200, &dtos)
return JSON(200, &dtos)
}
// Get /api/datasources/id/:name
func GetDataSourceIdByName(c *middleware.Context) Response {
func GetDataSourceIDByName(c *m.ReqContext) Response {
query := m.GetDataSourceByNameQuery{Name: c.Params(":name"), OrgId: c.OrgId}
if err := bus.Dispatch(&query); err != nil {
if err == m.ErrDataSourceNotFound {
return ApiError(404, "Data source not found", nil)
return Error(404, "Data source not found", nil)
}
return ApiError(500, "Failed to query datasources", err)
return Error(500, "Failed to query datasources", err)
}
ds := query.Result
@@ -236,7 +234,7 @@ func GetDataSourceIdByName(c *middleware.Context) Response {
Id: ds.Id,
}
return Json(200, &dtos)
return JSON(200, &dtos)
}
func convertModelToDtos(ds *m.DataSource) dtos.DataSource {
+1
View File
@@ -28,6 +28,7 @@ type DashboardMeta struct {
FolderId int64 `json:"folderId"`
FolderTitle string `json:"folderTitle"`
FolderUrl string `json:"folderUrl"`
Provisioned bool `json:"provisioned"`
}
type DashboardFullWithMeta struct {
+4
View File
@@ -50,6 +50,10 @@ type UserStars struct {
}
func GetGravatarUrl(text string) string {
if setting.DisableGravatar {
return "/public/img/user_profile.png"
}
if text == "" {
return ""
}
+2 -2
View File
@@ -2,12 +2,12 @@ package dtos
type Prefs struct {
Theme string `json:"theme"`
HomeDashboardId int64 `json:"homeDashboardId"`
HomeDashboardID int64 `json:"homeDashboardId"`
Timezone string `json:"timezone"`
}
type UpdatePrefsCmd struct {
Theme string `json:"theme"`
HomeDashboardId int64 `json:"homeDashboardId"`
HomeDashboardID int64 `json:"homeDashboardId"`
Timezone string `json:"timezone"`
}
+19 -20
View File
@@ -4,14 +4,13 @@ import (
"fmt"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/util"
)
func GetFolders(c *middleware.Context) Response {
func GetFolders(c *m.ReqContext) Response {
s := dashboards.NewFolderService(c.OrgId, c.SignedInUser)
folders, err := s.GetFolders(c.QueryInt("limit"))
@@ -29,33 +28,33 @@ func GetFolders(c *middleware.Context) Response {
})
}
return Json(200, result)
return JSON(200, result)
}
func GetFolderByUid(c *middleware.Context) Response {
func GetFolderByUID(c *m.ReqContext) Response {
s := dashboards.NewFolderService(c.OrgId, c.SignedInUser)
folder, err := s.GetFolderByUid(c.Params(":uid"))
folder, err := s.GetFolderByUID(c.Params(":uid"))
if err != nil {
return toFolderError(err)
}
g := guardian.New(folder.Id, c.OrgId, c.SignedInUser)
return Json(200, toFolderDto(g, folder))
return JSON(200, toFolderDto(g, folder))
}
func GetFolderById(c *middleware.Context) Response {
func GetFolderByID(c *m.ReqContext) Response {
s := dashboards.NewFolderService(c.OrgId, c.SignedInUser)
folder, err := s.GetFolderById(c.ParamsInt64(":id"))
folder, err := s.GetFolderByID(c.ParamsInt64(":id"))
if err != nil {
return toFolderError(err)
}
g := guardian.New(folder.Id, c.OrgId, c.SignedInUser)
return Json(200, toFolderDto(g, folder))
return JSON(200, toFolderDto(g, folder))
}
func CreateFolder(c *middleware.Context, cmd m.CreateFolderCommand) Response {
func CreateFolder(c *m.ReqContext, cmd m.CreateFolderCommand) Response {
s := dashboards.NewFolderService(c.OrgId, c.SignedInUser)
err := s.CreateFolder(&cmd)
if err != nil {
@@ -63,10 +62,10 @@ func CreateFolder(c *middleware.Context, cmd m.CreateFolderCommand) Response {
}
g := guardian.New(cmd.Result.Id, c.OrgId, c.SignedInUser)
return Json(200, toFolderDto(g, cmd.Result))
return JSON(200, toFolderDto(g, cmd.Result))
}
func UpdateFolder(c *middleware.Context, cmd m.UpdateFolderCommand) Response {
func UpdateFolder(c *m.ReqContext, cmd m.UpdateFolderCommand) Response {
s := dashboards.NewFolderService(c.OrgId, c.SignedInUser)
err := s.UpdateFolder(c.Params(":uid"), &cmd)
if err != nil {
@@ -74,17 +73,17 @@ func UpdateFolder(c *middleware.Context, cmd m.UpdateFolderCommand) Response {
}
g := guardian.New(cmd.Result.Id, c.OrgId, c.SignedInUser)
return Json(200, toFolderDto(g, cmd.Result))
return JSON(200, toFolderDto(g, cmd.Result))
}
func DeleteFolder(c *middleware.Context) Response {
func DeleteFolder(c *m.ReqContext) Response {
s := dashboards.NewFolderService(c.OrgId, c.SignedInUser)
f, err := s.DeleteFolder(c.Params(":uid"))
if err != nil {
return toFolderError(err)
}
return Json(200, util.DynMap{
return JSON(200, util.DynMap{
"title": f.Title,
"message": fmt.Sprintf("Folder %s deleted", f.Title),
})
@@ -128,20 +127,20 @@ func toFolderError(err error) Response {
err == m.ErrDashboardTypeMismatch ||
err == m.ErrDashboardInvalidUid ||
err == m.ErrDashboardUidToLong {
return ApiError(400, err.Error(), nil)
return Error(400, err.Error(), nil)
}
if err == m.ErrFolderAccessDenied {
return ApiError(403, "Access denied", err)
return Error(403, "Access denied", err)
}
if err == m.ErrFolderNotFound {
return Json(404, util.DynMap{"status": "not-found", "message": m.ErrFolderNotFound.Error()})
return JSON(404, util.DynMap{"status": "not-found", "message": m.ErrFolderNotFound.Error()})
}
if err == m.ErrFolderVersionMismatch {
return Json(412, util.DynMap{"status": "version-mismatch", "message": m.ErrFolderVersionMismatch.Error()})
return JSON(412, util.DynMap{"status": "version-mismatch", "message": m.ErrFolderVersionMismatch.Error()})
}
return ApiError(500, "Folder API error", err)
return Error(500, "Folder API error", err)
}
+18 -13
View File
@@ -5,15 +5,14 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian"
)
func GetFolderPermissionList(c *middleware.Context) Response {
func GetFolderPermissionList(c *m.ReqContext) Response {
s := dashboards.NewFolderService(c.OrgId, c.SignedInUser)
folder, err := s.GetFolderByUid(c.Params(":uid"))
folder, err := s.GetFolderByUID(c.Params(":uid"))
if err != nil {
return toFolderError(err)
@@ -27,24 +26,30 @@ func GetFolderPermissionList(c *middleware.Context) Response {
acl, err := g.GetAcl()
if err != nil {
return ApiError(500, "Failed to get folder permissions", err)
return Error(500, "Failed to get folder permissions", err)
}
for _, perm := range acl {
perm.FolderId = folder.Id
perm.DashboardId = 0
perm.UserAvatarUrl = dtos.GetGravatarUrl(perm.UserEmail)
if perm.TeamId > 0 {
perm.TeamAvatarUrl = dtos.GetGravatarUrlWithDefault(perm.TeamEmail, perm.Team)
}
if perm.Slug != "" {
perm.Url = m.GetDashboardFolderUrl(perm.IsFolder, perm.Uid, perm.Slug)
}
}
return Json(200, acl)
return JSON(200, acl)
}
func UpdateFolderPermissions(c *middleware.Context, apiCmd dtos.UpdateDashboardAclCommand) Response {
func UpdateFolderPermissions(c *m.ReqContext, apiCmd dtos.UpdateDashboardAclCommand) Response {
s := dashboards.NewFolderService(c.OrgId, c.SignedInUser)
folder, err := s.GetFolderByUid(c.Params(":uid"))
folder, err := s.GetFolderByUID(c.Params(":uid"))
if err != nil {
return toFolderError(err)
@@ -80,13 +85,13 @@ func UpdateFolderPermissions(c *middleware.Context, apiCmd dtos.UpdateDashboardA
if err != nil {
if err == guardian.ErrGuardianPermissionExists ||
err == guardian.ErrGuardianOverride {
return ApiError(400, err.Error(), err)
return Error(400, err.Error(), err)
}
return ApiError(500, "Error while checking folder permissions", err)
return Error(500, "Error while checking folder permissions", err)
}
return ApiError(403, "Cannot remove own admin permission for a folder", nil)
return Error(403, "Cannot remove own admin permission for a folder", nil)
}
if err := bus.Dispatch(&cmd); err != nil {
@@ -98,11 +103,11 @@ func UpdateFolderPermissions(c *middleware.Context, apiCmd dtos.UpdateDashboardA
}
if err == m.ErrFolderAclInfoMissing || err == m.ErrFolderPermissionFolderEmpty {
return ApiError(409, err.Error(), err)
return Error(409, err.Error(), err)
}
return ApiError(500, "Failed to create permission", err)
return Error(500, "Failed to create permission", err)
}
return ApiSuccess("Folder permissions updated")
return Success("Folder permissions updated")
}
+6 -7
View File
@@ -6,7 +6,6 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian"
@@ -18,7 +17,7 @@ func TestFolderPermissionApiEndpoint(t *testing.T) {
Convey("Folder permissions test", t, func() {
Convey("Given folder not exists", func() {
mock := &fakeFolderService{
GetFolderByUidError: m.ErrFolderNotFound,
GetFolderByUIDError: m.ErrFolderNotFound,
}
origNewFolderService := dashboards.NewFolderService
@@ -50,7 +49,7 @@ func TestFolderPermissionApiEndpoint(t *testing.T) {
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: false})
mock := &fakeFolderService{
GetFolderByUidResult: &m.Folder{
GetFolderByUIDResult: &m.Folder{
Id: 1,
Uid: "uid",
Title: "Folder",
@@ -97,7 +96,7 @@ func TestFolderPermissionApiEndpoint(t *testing.T) {
})
mock := &fakeFolderService{
GetFolderByUidResult: &m.Folder{
GetFolderByUIDResult: &m.Folder{
Id: 1,
Uid: "uid",
Title: "Folder",
@@ -143,7 +142,7 @@ func TestFolderPermissionApiEndpoint(t *testing.T) {
})
mock := &fakeFolderService{
GetFolderByUidResult: &m.Folder{
GetFolderByUIDResult: &m.Folder{
Id: 1,
Uid: "uid",
Title: "Folder",
@@ -179,7 +178,7 @@ func TestFolderPermissionApiEndpoint(t *testing.T) {
)
mock := &fakeFolderService{
GetFolderByUidResult: &m.Folder{
GetFolderByUIDResult: &m.Folder{
Id: 1,
Uid: "uid",
Title: "Folder",
@@ -227,7 +226,7 @@ func updateFolderPermissionScenario(desc string, url string, routePattern string
sc := setupScenarioContext(url)
sc.defaultHandler = wrap(func(c *middleware.Context) Response {
sc.defaultHandler = wrap(func(c *m.ReqContext) Response {
sc.context = c
sc.context.OrgId = TestOrgID
sc.context.UserId = TestUserID
+22 -25
View File
@@ -7,11 +7,8 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
. "github.com/smartystreets/goconvey/convey"
)
@@ -136,8 +133,8 @@ func TestFoldersApiEndpoint(t *testing.T) {
})
}
func callGetFolderByUid(sc *scenarioContext) {
sc.handlerFunc = GetFolderByUid
func callGetFolderByUID(sc *scenarioContext) {
sc.handlerFunc = GetFolderByUID
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
}
@@ -155,7 +152,7 @@ func createFolderScenario(desc string, url string, routePattern string, mock *fa
defer bus.ClearBusHandlers()
sc := setupScenarioContext(url)
sc.defaultHandler = wrap(func(c *middleware.Context) Response {
sc.defaultHandler = wrap(func(c *m.ReqContext) Response {
sc.context = c
sc.context.SignedInUser = &m.SignedInUser{OrgId: TestOrgID, UserId: TestUserID}
@@ -184,7 +181,7 @@ func updateFolderScenario(desc string, url string, routePattern string, mock *fa
defer bus.ClearBusHandlers()
sc := setupScenarioContext(url)
sc.defaultHandler = wrap(func(c *middleware.Context) Response {
sc.defaultHandler = wrap(func(c *m.ReqContext) Response {
sc.context = c
sc.context.SignedInUser = &m.SignedInUser{OrgId: TestOrgID, UserId: TestUserID}
@@ -205,50 +202,50 @@ func updateFolderScenario(desc string, url string, routePattern string, mock *fa
}
type fakeFolderService struct {
GetFoldersResult []*models.Folder
GetFoldersResult []*m.Folder
GetFoldersError error
GetFolderByUidResult *models.Folder
GetFolderByUidError error
GetFolderByIdResult *models.Folder
GetFolderByIdError error
CreateFolderResult *models.Folder
GetFolderByUIDResult *m.Folder
GetFolderByUIDError error
GetFolderByIDResult *m.Folder
GetFolderByIDError error
CreateFolderResult *m.Folder
CreateFolderError error
UpdateFolderResult *models.Folder
UpdateFolderResult *m.Folder
UpdateFolderError error
DeleteFolderResult *models.Folder
DeleteFolderResult *m.Folder
DeleteFolderError error
DeletedFolderUids []string
}
func (s *fakeFolderService) GetFolders(limit int) ([]*models.Folder, error) {
func (s *fakeFolderService) GetFolders(limit int) ([]*m.Folder, error) {
return s.GetFoldersResult, s.GetFoldersError
}
func (s *fakeFolderService) GetFolderById(id int64) (*models.Folder, error) {
return s.GetFolderByIdResult, s.GetFolderByIdError
func (s *fakeFolderService) GetFolderByID(id int64) (*m.Folder, error) {
return s.GetFolderByIDResult, s.GetFolderByIDError
}
func (s *fakeFolderService) GetFolderByUid(uid string) (*models.Folder, error) {
return s.GetFolderByUidResult, s.GetFolderByUidError
func (s *fakeFolderService) GetFolderByUID(uid string) (*m.Folder, error) {
return s.GetFolderByUIDResult, s.GetFolderByUIDError
}
func (s *fakeFolderService) CreateFolder(cmd *models.CreateFolderCommand) error {
func (s *fakeFolderService) CreateFolder(cmd *m.CreateFolderCommand) error {
cmd.Result = s.CreateFolderResult
return s.CreateFolderError
}
func (s *fakeFolderService) UpdateFolder(existingUid string, cmd *models.UpdateFolderCommand) error {
func (s *fakeFolderService) UpdateFolder(existingUID string, cmd *m.UpdateFolderCommand) error {
cmd.Result = s.UpdateFolderResult
return s.UpdateFolderError
}
func (s *fakeFolderService) DeleteFolder(uid string) (*models.Folder, error) {
func (s *fakeFolderService) DeleteFolder(uid string) (*m.Folder, error) {
s.DeletedFolderUids = append(s.DeletedFolderUids, uid)
return s.DeleteFolderResult, s.DeleteFolderError
}
func mockFolderService(mock *fakeFolderService) {
dashboards.NewFolderService = func(orgId int64, user *models.SignedInUser) dashboards.FolderService {
dashboards.NewFolderService = func(orgId int64, user *m.SignedInUser) dashboards.FolderService {
return mock
}
}
+2 -3
View File
@@ -5,14 +5,13 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, error) {
func getFrontendSettingsMap(c *m.ReqContext) (map[string]interface{}, error) {
orgDataSources := make([]*m.DataSource, 0)
if c.OrgId != 0 {
@@ -180,7 +179,7 @@ func getPanelSort(id string) int {
return sort
}
func GetFrontendSettings(c *middleware.Context) {
func GetFrontendSettings(c *m.ReqContext) {
settings, err := getFrontendSettingsMap(c)
if err != nil {
c.JsonApiErr(400, "Failed to get frontend settings", err)
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"net/url"
"time"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
@@ -41,7 +41,7 @@ func ReverseProxyGnetReq(proxyPath string) *httputil.ReverseProxy {
return &httputil.ReverseProxy{Director: director}
}
func ProxyGnetRequest(c *middleware.Context) {
func ProxyGnetRequest(c *m.ReqContext) {
proxyPath := c.Params("*")
proxy := ReverseProxyGnetReq(proxyPath)
proxy.Transport = grafanaComProxyTransport
+16 -13
View File
@@ -29,7 +29,7 @@ import (
"github.com/grafana/grafana/pkg/setting"
)
type HttpServer struct {
type HTTPServer struct {
log log.Logger
macaron *macaron.Macaron
context context.Context
@@ -39,14 +39,14 @@ type HttpServer struct {
httpSrv *http.Server
}
func NewHttpServer() *HttpServer {
return &HttpServer{
func NewHTTPServer() *HTTPServer {
return &HTTPServer{
log: log.New("http.server"),
cache: gocache.New(5*time.Minute, 10*time.Minute),
}
}
func (hs *HttpServer) Start(ctx context.Context) error {
func (hs *HTTPServer) Start(ctx context.Context) error {
var err error
hs.context = ctx
@@ -74,12 +74,15 @@ func (hs *HttpServer) Start(ctx context.Context) error {
return nil
}
case setting.SOCKET:
ln, err := net.Listen("unix", setting.SocketPath)
ln, err := net.ListenUnix("unix", &net.UnixAddr{Name: setting.SocketPath, Net: "unix"})
if err != nil {
hs.log.Debug("server was shutdown gracefully")
return nil
}
// Make socket writable by group
os.Chmod(setting.SocketPath, 0660)
err = hs.httpSrv.Serve(ln)
if err != nil {
hs.log.Debug("server was shutdown gracefully")
@@ -93,13 +96,13 @@ func (hs *HttpServer) Start(ctx context.Context) error {
return err
}
func (hs *HttpServer) Shutdown(ctx context.Context) error {
func (hs *HTTPServer) Shutdown(ctx context.Context) error {
err := hs.httpSrv.Shutdown(ctx)
hs.log.Info("Stopped HTTP server")
return err
}
func (hs *HttpServer) listenAndServeTLS(certfile, keyfile string) error {
func (hs *HTTPServer) listenAndServeTLS(certfile, keyfile string) error {
if certfile == "" {
return fmt.Errorf("cert_file cannot be empty when using HTTPS")
}
@@ -136,12 +139,12 @@ func (hs *HttpServer) listenAndServeTLS(certfile, keyfile string) error {
}
hs.httpSrv.TLSConfig = tlsCfg
hs.httpSrv.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0)
hs.httpSrv.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler))
return hs.httpSrv.ListenAndServeTLS(setting.CertFile, setting.KeyFile)
}
func (hs *HttpServer) newMacaron() *macaron.Macaron {
func (hs *HTTPServer) newMacaron() *macaron.Macaron {
macaron.Env = setting.Env
m := macaron.New()
@@ -175,7 +178,7 @@ func (hs *HttpServer) newMacaron() *macaron.Macaron {
m.Use(hs.healthHandler)
m.Use(hs.metricsEndpoint)
m.Use(middleware.GetContextHandler())
m.Use(middleware.Sessioner(&setting.SessionOptions))
m.Use(middleware.Sessioner(&setting.SessionOptions, setting.SessionConnMaxLifetime))
m.Use(middleware.OrgRedirect())
// needs to be after context handler
@@ -188,7 +191,7 @@ func (hs *HttpServer) newMacaron() *macaron.Macaron {
return m
}
func (hs *HttpServer) metricsEndpoint(ctx *macaron.Context) {
func (hs *HTTPServer) metricsEndpoint(ctx *macaron.Context) {
if ctx.Req.Method != "GET" || ctx.Req.URL.Path != "/metrics" {
return
}
@@ -197,7 +200,7 @@ func (hs *HttpServer) metricsEndpoint(ctx *macaron.Context) {
ServeHTTP(ctx.Resp, ctx.Req.Request)
}
func (hs *HttpServer) healthHandler(ctx *macaron.Context) {
func (hs *HTTPServer) healthHandler(ctx *macaron.Context) {
notHeadOrGet := ctx.Req.Method != http.MethodGet && ctx.Req.Method != http.MethodHead
if notHeadOrGet || ctx.Req.URL.Path != "/api/health" {
return
@@ -221,7 +224,7 @@ func (hs *HttpServer) healthHandler(ctx *macaron.Context) {
ctx.Resp.Write(dataBytes)
}
func (hs *HttpServer) mapStatic(m *macaron.Macaron, rootDir string, dir string, prefix string) {
func (hs *HTTPServer) mapStatic(m *macaron.Macaron, rootDir string, dir string, prefix string) {
headers := func(c *macaron.Context) {
c.Resp.Header().Set("Cache-Control", "public, max-age=3600")
}
+25 -19
View File
@@ -6,13 +6,12 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/setting"
)
func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
settings, err := getFrontendSettingsMap(c)
if err != nil {
return nil, err
@@ -33,13 +32,13 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
locale = parts[0]
}
appUrl := setting.AppUrl
appSubUrl := setting.AppSubUrl
appURL := setting.AppUrl
appSubURL := setting.AppSubUrl
// special case when doing localhost call from phantomjs
if c.IsRenderCall {
appUrl = fmt.Sprintf("%s://localhost:%s", setting.Protocol, setting.HttpPort)
appSubUrl = ""
appURL = fmt.Sprintf("%s://localhost:%s", setting.Protocol, setting.HttpPort)
appSubURL = ""
settings["appSubUrl"] = ""
}
@@ -63,8 +62,8 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
},
Settings: settings,
Theme: prefs.Theme,
AppUrl: appUrl,
AppSubUrl: appSubUrl,
AppUrl: appURL,
AppSubUrl: appSubURL,
GoogleAnalyticsId: setting.GoogleAnalyticsId,
GoogleTagManagerId: setting.GoogleTagManagerId,
BuildVersion: setting.BuildVersion,
@@ -81,8 +80,8 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
data.User.Name = data.User.Login
}
themeUrlParam := c.Query("theme")
if themeUrlParam == "light" {
themeURLParam := c.Query("theme")
if themeURLParam == "light" {
data.User.LightTheme = true
data.Theme = "light"
}
@@ -119,9 +118,14 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
})
if c.IsSignedIn {
// Only set login if it's different from the name
var login string
if c.SignedInUser.Login != c.SignedInUser.NameOrFallback() {
login = c.SignedInUser.Login
}
profileNode := &dtos.NavLink{
Text: c.SignedInUser.NameOrFallback(),
SubTitle: c.SignedInUser.Login,
SubTitle: login,
Id: "profile",
Img: data.User.GravatarUrl,
Url: setting.AppSubUrl + "/profile",
@@ -285,6 +289,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
data.NavTree = append(data.NavTree, &dtos.NavLink{
Text: "Help",
SubTitle: fmt.Sprintf(`Grafana v%s (%s)`, setting.BuildVersion, setting.BuildCommit),
Id: "help",
Url: "#",
Icon: "gicon gicon-question",
@@ -299,25 +304,26 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
return &data, nil
}
func Index(c *middleware.Context) {
if data, err := setIndexViewData(c); err != nil {
func Index(c *m.ReqContext) {
data, err := setIndexViewData(c)
if err != nil {
c.Handle(500, "Failed to get settings", err)
return
} else {
c.HTML(200, "index", data)
}
c.HTML(200, "index", data)
}
func NotFoundHandler(c *middleware.Context) {
func NotFoundHandler(c *m.ReqContext) {
if c.IsApiRequest() {
c.JsonApiErr(404, "Not found", nil)
return
}
if data, err := setIndexViewData(c); err != nil {
data, err := setIndexViewData(c)
if err != nil {
c.Handle(500, "Failed to get settings", err)
return
} else {
c.HTML(404, "index", data)
}
c.HTML(404, "index", data)
}
+22 -21
View File
@@ -8,16 +8,16 @@ import (
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/login"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/session"
"github.com/grafana/grafana/pkg/setting"
)
const (
VIEW_INDEX = "index"
ViewIndex = "index"
)
func LoginView(c *middleware.Context) {
func LoginView(c *m.ReqContext) {
viewData, err := setIndexViewData(c)
if err != nil {
c.Handle(500, "Failed to get settings", err)
@@ -40,7 +40,7 @@ func LoginView(c *middleware.Context) {
}
if !tryLoginUsingRememberCookie(c) {
c.HTML(200, VIEW_INDEX, viewData)
c.HTML(200, ViewIndex, viewData)
return
}
@@ -53,7 +53,7 @@ func LoginView(c *middleware.Context) {
c.Redirect(setting.AppSubUrl + "/")
}
func tryLoginUsingRememberCookie(c *middleware.Context) bool {
func tryLoginUsingRememberCookie(c *m.ReqContext) bool {
// Check auto-login.
uname := c.GetCookie(setting.CookieUserName)
if len(uname) == 0 {
@@ -87,7 +87,7 @@ func tryLoginUsingRememberCookie(c *middleware.Context) bool {
return true
}
func LoginApiPing(c *middleware.Context) {
func LoginAPIPing(c *m.ReqContext) {
if !tryLoginUsingRememberCookie(c) {
c.JsonApiErr(401, "Unauthorized", nil)
return
@@ -96,23 +96,24 @@ func LoginApiPing(c *middleware.Context) {
c.JsonOK("Logged in")
}
func LoginPost(c *middleware.Context, cmd dtos.LoginCommand) Response {
func LoginPost(c *m.ReqContext, cmd dtos.LoginCommand) Response {
if setting.DisableLoginForm {
return ApiError(401, "Login is disabled", nil)
return Error(401, "Login is disabled", nil)
}
authQuery := login.LoginUserQuery{
Username: cmd.User,
Password: cmd.Password,
IpAddress: c.Req.RemoteAddr,
authQuery := &m.LoginUserQuery{
ReqContext: c,
Username: cmd.User,
Password: cmd.Password,
IpAddress: c.Req.RemoteAddr,
}
if err := bus.Dispatch(&authQuery); err != nil {
if err := bus.Dispatch(authQuery); err != nil {
if err == login.ErrInvalidCredentials || err == login.ErrTooManyLoginAttempts {
return ApiError(401, "Invalid username or password", err)
return Error(401, "Invalid username or password", err)
}
return ApiError(500, "Error while trying to authenticate user", err)
return Error(500, "Error while trying to authenticate user", err)
}
user := authQuery.User
@@ -130,10 +131,10 @@ func LoginPost(c *middleware.Context, cmd dtos.LoginCommand) Response {
metrics.M_Api_Login_Post.Inc()
return Json(200, result)
return JSON(200, result)
}
func loginUserWithUser(user *m.User, c *middleware.Context) {
func loginUserWithUser(user *m.User, c *m.ReqContext) {
if user == nil {
log.Error(3, "User login with nil user")
}
@@ -146,13 +147,13 @@ func loginUserWithUser(user *m.User, c *middleware.Context) {
c.SetSuperSecureCookie(user.Rands+user.Password, setting.CookieRememberName, user.Login, days, setting.AppSubUrl+"/")
}
c.Session.RegenerateId(c)
c.Session.Set(middleware.SESS_KEY_USERID, user.Id)
c.Session.RegenerateId(c.Context)
c.Session.Set(session.SESS_KEY_USERID, user.Id)
}
func Logout(c *middleware.Context) {
func Logout(c *m.ReqContext) {
c.SetCookie(setting.CookieUserName, "", -1, setting.AppSubUrl+"/")
c.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubUrl+"/")
c.Session.Destory(c)
c.Session.Destory(c.Context)
c.Redirect(setting.AppSubUrl + "/login")
}
+32 -50
View File
@@ -6,7 +6,6 @@ import (
"crypto/tls"
"crypto/x509"
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
"net/http"
@@ -16,21 +15,15 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/login"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/session"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/social"
)
var (
ErrProviderDeniedRequest = errors.New("Login provider denied login request")
ErrEmailNotAllowed = errors.New("Required email domain not fulfilled")
ErrSignUpNotAllowed = errors.New("Signup is not allowed for this adapter")
ErrUsersQuotaReached = errors.New("Users quota reached")
ErrNoEmail = errors.New("Login provider didn't return an email address")
oauthLogger = log.New("oauth")
)
var oauthLogger = log.New("oauth")
func GenStateString() string {
rnd := make([]byte, 32)
@@ -38,7 +31,7 @@ func GenStateString() string {
return base64.URLEncoding.EncodeToString(rnd)
}
func OAuthLogin(ctx *middleware.Context) {
func OAuthLogin(ctx *m.ReqContext) {
if setting.OAuthService == nil {
ctx.Handle(404, "OAuth not enabled", nil)
return
@@ -55,14 +48,14 @@ func OAuthLogin(ctx *middleware.Context) {
if errorParam != "" {
errorDesc := ctx.Query("error_description")
oauthLogger.Error("failed to login ", "error", errorParam, "errorDesc", errorDesc)
redirectWithError(ctx, ErrProviderDeniedRequest, "error", errorParam, "errorDesc", errorDesc)
redirectWithError(ctx, login.ErrProviderDeniedRequest, "error", errorParam, "errorDesc", errorDesc)
return
}
code := ctx.Query("code")
if code == "" {
state := GenStateString()
ctx.Session.Set(middleware.SESS_KEY_OAUTH_STATE, state)
ctx.Session.Set(session.SESS_KEY_OAUTH_STATE, state)
if setting.OAuthService.OAuthInfos[name].HostedDomain == "" {
ctx.Redirect(connect.AuthCodeURL(state, oauth2.AccessTypeOnline))
} else {
@@ -71,7 +64,7 @@ func OAuthLogin(ctx *middleware.Context) {
return
}
savedState, ok := ctx.Session.Get(middleware.SESS_KEY_OAUTH_STATE).(string)
savedState, ok := ctx.Session.Get(session.SESS_KEY_OAUTH_STATE).(string)
if !ok {
ctx.Handle(500, "login.OAuthLogin(missing saved state)", nil)
return
@@ -148,54 +141,43 @@ func OAuthLogin(ctx *middleware.Context) {
// validate that we got at least an email address
if userInfo.Email == "" {
redirectWithError(ctx, ErrNoEmail)
redirectWithError(ctx, login.ErrNoEmail)
return
}
// validate that the email is allowed to login to grafana
if !connect.IsEmailAllowed(userInfo.Email) {
redirectWithError(ctx, ErrEmailNotAllowed)
redirectWithError(ctx, login.ErrEmailNotAllowed)
return
}
userQuery := m.GetUserByEmailQuery{Email: userInfo.Email}
err = bus.Dispatch(&userQuery)
extUser := &m.ExternalUserInfo{
AuthModule: "oauth_" + name,
AuthId: userInfo.Id,
Name: userInfo.Name,
Login: userInfo.Login,
Email: userInfo.Email,
OrgRoles: map[int64]m.RoleType{},
}
// create account if missing
if err == m.ErrUserNotFound {
if !connect.IsSignupAllowed() {
redirectWithError(ctx, ErrSignUpNotAllowed)
return
}
limitReached, err := middleware.QuotaReached(ctx, "user")
if err != nil {
ctx.Handle(500, "Failed to get user quota", err)
return
}
if limitReached {
redirectWithError(ctx, ErrUsersQuotaReached)
return
}
cmd := m.CreateUserCommand{
Login: userInfo.Login,
Email: userInfo.Email,
Name: userInfo.Name,
Company: userInfo.Company,
DefaultOrgRole: userInfo.Role,
}
if userInfo.Role != "" {
extUser.OrgRoles[1] = m.RoleType(userInfo.Role)
}
if err = bus.Dispatch(&cmd); err != nil {
ctx.Handle(500, "Failed to create account", err)
return
}
userQuery.Result = &cmd.Result
} else if err != nil {
ctx.Handle(500, "Unexpected error", err)
// add/update user in grafana
cmd := &m.UpsertUserCommand{
ReqContext: ctx,
ExternalUser: extUser,
SignupAllowed: connect.IsSignupAllowed(),
}
err = bus.Dispatch(cmd)
if err != nil {
redirectWithError(ctx, err)
return
}
// login
loginUserWithUser(userQuery.Result, ctx)
loginUserWithUser(cmd.Result, ctx)
metrics.M_Api_Login_OAuth.Inc()
@@ -208,7 +190,7 @@ func OAuthLogin(ctx *middleware.Context) {
ctx.Redirect(setting.AppSubUrl + "/")
}
func redirectWithError(ctx *middleware.Context, err error, v ...interface{}) {
func redirectWithError(ctx *m.ReqContext, err error, v ...interface{}) {
ctx.Logger.Error(err.Error(), v...)
ctx.Session.Set("loginError", err.Error())
ctx.Redirect(setting.AppSubUrl + "/login")
+22 -23
View File
@@ -6,29 +6,28 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/tsdb/testdata"
"github.com/grafana/grafana/pkg/util"
)
// POST /api/tsdb/query
func QueryMetrics(c *middleware.Context, reqDto dtos.MetricRequest) Response {
func QueryMetrics(c *m.ReqContext, reqDto dtos.MetricRequest) Response {
timeRange := tsdb.NewTimeRange(reqDto.From, reqDto.To)
if len(reqDto.Queries) == 0 {
return ApiError(400, "No queries found in query", nil)
return Error(400, "No queries found in query", nil)
}
dsId, err := reqDto.Queries[0].Get("datasourceId").Int64()
dsID, err := reqDto.Queries[0].Get("datasourceId").Int64()
if err != nil {
return ApiError(400, "Query missing datasourceId", nil)
return Error(400, "Query missing datasourceId", nil)
}
dsQuery := models.GetDataSourceByIdQuery{Id: dsId, OrgId: c.OrgId}
dsQuery := m.GetDataSourceByIdQuery{Id: dsID, OrgId: c.OrgId}
if err := bus.Dispatch(&dsQuery); err != nil {
return ApiError(500, "failed to fetch data source", err)
return Error(500, "failed to fetch data source", err)
}
request := &tsdb.TsdbQuery{TimeRange: timeRange}
@@ -45,7 +44,7 @@ func QueryMetrics(c *middleware.Context, reqDto dtos.MetricRequest) Response {
resp, err := tsdb.HandleRequest(context.Background(), dsQuery.Result, request)
if err != nil {
return ApiError(500, "Metric request error", err)
return Error(500, "Metric request error", err)
}
statusCode := 200
@@ -57,11 +56,11 @@ func QueryMetrics(c *middleware.Context, reqDto dtos.MetricRequest) Response {
}
}
return Json(statusCode, &resp)
return JSON(statusCode, &resp)
}
// GET /api/tsdb/testdata/scenarios
func GetTestDataScenarios(c *middleware.Context) Response {
func GetTestDataScenarios(c *m.ReqContext) Response {
result := make([]interface{}, 0)
for _, scenario := range testdata.ScenarioRegistry {
@@ -73,26 +72,26 @@ func GetTestDataScenarios(c *middleware.Context) Response {
})
}
return Json(200, &result)
return JSON(200, &result)
}
// Genereates a index out of range error
func GenerateError(c *middleware.Context) Response {
// Generates a index out of range error
func GenerateError(c *m.ReqContext) Response {
var array []string
return Json(200, array[20])
return JSON(200, array[20])
}
// GET /api/tsdb/testdata/gensql
func GenerateSqlTestData(c *middleware.Context) Response {
if err := bus.Dispatch(&models.InsertSqlTestDataCommand{}); err != nil {
return ApiError(500, "Failed to insert test data", err)
func GenerateSQLTestData(c *m.ReqContext) Response {
if err := bus.Dispatch(&m.InsertSqlTestDataCommand{}); err != nil {
return Error(500, "Failed to insert test data", err)
}
return Json(200, &util.DynMap{"message": "OK"})
return JSON(200, &util.DynMap{"message": "OK"})
}
// GET /api/tsdb/testdata/random-walk
func GetTestDataRandomWalk(c *middleware.Context) Response {
func GetTestDataRandomWalk(c *m.ReqContext) Response {
from := c.Query("from")
to := c.Query("to")
intervalMs := c.QueryInt64("intervalMs")
@@ -100,7 +99,7 @@ func GetTestDataRandomWalk(c *middleware.Context) Response {
timeRange := tsdb.NewTimeRange(from, to)
request := &tsdb.TsdbQuery{TimeRange: timeRange}
dsInfo := &models.DataSource{Type: "grafana-testdata-datasource"}
dsInfo := &m.DataSource{Type: "grafana-testdata-datasource"}
request.Queries = append(request.Queries, &tsdb.Query{
RefId: "A",
IntervalMs: intervalMs,
@@ -112,8 +111,8 @@ func GetTestDataRandomWalk(c *middleware.Context) Response {
resp, err := tsdb.HandleRequest(context.Background(), dsInfo, request)
if err != nil {
return ApiError(500, "Metric request error", err)
return Error(500, "Metric request error", err)
}
return Json(200, &resp)
return JSON(200, &resp)
}
+36 -37
View File
@@ -4,31 +4,30 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
// GET /api/org
func GetOrgCurrent(c *middleware.Context) Response {
func GetOrgCurrent(c *m.ReqContext) Response {
return getOrgHelper(c.OrgId)
}
// GET /api/orgs/:orgId
func GetOrgById(c *middleware.Context) Response {
func GetOrgByID(c *m.ReqContext) Response {
return getOrgHelper(c.ParamsInt64(":orgId"))
}
// Get /api/orgs/name/:name
func GetOrgByName(c *middleware.Context) Response {
func GetOrgByName(c *m.ReqContext) Response {
query := m.GetOrgByNameQuery{Name: c.Params(":name")}
if err := bus.Dispatch(&query); err != nil {
if err == m.ErrOrgNotFound {
return ApiError(404, "Organization not found", err)
return Error(404, "Organization not found", err)
}
return ApiError(500, "Failed to get organization", err)
return Error(500, "Failed to get organization", err)
}
org := query.Result
result := m.OrgDetailsDTO{
@@ -44,18 +43,18 @@ func GetOrgByName(c *middleware.Context) Response {
},
}
return Json(200, &result)
return JSON(200, &result)
}
func getOrgHelper(orgId int64) Response {
query := m.GetOrgByIdQuery{Id: orgId}
func getOrgHelper(orgID int64) Response {
query := m.GetOrgByIdQuery{Id: orgID}
if err := bus.Dispatch(&query); err != nil {
if err == m.ErrOrgNotFound {
return ApiError(404, "Organization not found", err)
return Error(404, "Organization not found", err)
}
return ApiError(500, "Failed to get organization", err)
return Error(500, "Failed to get organization", err)
}
org := query.Result
@@ -72,66 +71,66 @@ func getOrgHelper(orgId int64) Response {
},
}
return Json(200, &result)
return JSON(200, &result)
}
// POST /api/orgs
func CreateOrg(c *middleware.Context, cmd m.CreateOrgCommand) Response {
func CreateOrg(c *m.ReqContext, cmd m.CreateOrgCommand) Response {
if !c.IsSignedIn || (!setting.AllowUserOrgCreate && !c.IsGrafanaAdmin) {
return ApiError(403, "Access denied", nil)
return Error(403, "Access denied", nil)
}
cmd.UserId = c.UserId
if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrOrgNameTaken {
return ApiError(409, "Organization name taken", err)
return Error(409, "Organization name taken", err)
}
return ApiError(500, "Failed to create organization", err)
return Error(500, "Failed to create organization", err)
}
metrics.M_Api_Org_Create.Inc()
return Json(200, &util.DynMap{
return JSON(200, &util.DynMap{
"orgId": cmd.Result.Id,
"message": "Organization created",
})
}
// PUT /api/org
func UpdateOrgCurrent(c *middleware.Context, form dtos.UpdateOrgForm) Response {
func UpdateOrgCurrent(c *m.ReqContext, form dtos.UpdateOrgForm) Response {
return updateOrgHelper(form, c.OrgId)
}
// PUT /api/orgs/:orgId
func UpdateOrg(c *middleware.Context, form dtos.UpdateOrgForm) Response {
func UpdateOrg(c *m.ReqContext, form dtos.UpdateOrgForm) Response {
return updateOrgHelper(form, c.ParamsInt64(":orgId"))
}
func updateOrgHelper(form dtos.UpdateOrgForm, orgId int64) Response {
cmd := m.UpdateOrgCommand{Name: form.Name, OrgId: orgId}
func updateOrgHelper(form dtos.UpdateOrgForm, orgID int64) Response {
cmd := m.UpdateOrgCommand{Name: form.Name, OrgId: orgID}
if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrOrgNameTaken {
return ApiError(400, "Organization name taken", err)
return Error(400, "Organization name taken", err)
}
return ApiError(500, "Failed to update organization", err)
return Error(500, "Failed to update organization", err)
}
return ApiSuccess("Organization updated")
return Success("Organization updated")
}
// PUT /api/org/address
func UpdateOrgAddressCurrent(c *middleware.Context, form dtos.UpdateOrgAddressForm) Response {
func UpdateOrgAddressCurrent(c *m.ReqContext, form dtos.UpdateOrgAddressForm) Response {
return updateOrgAddressHelper(form, c.OrgId)
}
// PUT /api/orgs/:orgId/address
func UpdateOrgAddress(c *middleware.Context, form dtos.UpdateOrgAddressForm) Response {
func UpdateOrgAddress(c *m.ReqContext, form dtos.UpdateOrgAddressForm) Response {
return updateOrgAddressHelper(form, c.ParamsInt64(":orgId"))
}
func updateOrgAddressHelper(form dtos.UpdateOrgAddressForm, orgId int64) Response {
func updateOrgAddressHelper(form dtos.UpdateOrgAddressForm, orgID int64) Response {
cmd := m.UpdateOrgAddressCommand{
OrgId: orgId,
OrgId: orgID,
Address: m.Address{
Address1: form.Address1,
Address2: form.Address2,
@@ -143,24 +142,24 @@ func updateOrgAddressHelper(form dtos.UpdateOrgAddressForm, orgId int64) Respons
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to update org address", err)
return Error(500, "Failed to update org address", err)
}
return ApiSuccess("Address updated")
return Success("Address updated")
}
// GET /api/orgs/:orgId
func DeleteOrgById(c *middleware.Context) Response {
func DeleteOrgByID(c *m.ReqContext) Response {
if err := bus.Dispatch(&m.DeleteOrgCommand{Id: c.ParamsInt64(":orgId")}); err != nil {
if err == m.ErrOrgNotFound {
return ApiError(404, "Failed to delete organization. ID not found", nil)
return Error(404, "Failed to delete organization. ID not found", nil)
}
return ApiError(500, "Failed to update organization", err)
return Error(500, "Failed to update organization", err)
}
return ApiSuccess("Organization deleted")
return Success("Organization deleted")
}
func SearchOrgs(c *middleware.Context) Response {
func SearchOrgs(c *m.ReqContext) Response {
query := m.SearchOrgsQuery{
Query: c.Query("query"),
Name: c.Query("name"),
@@ -169,8 +168,8 @@ func SearchOrgs(c *middleware.Context) Response {
}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to search orgs", err)
return Error(500, "Failed to search orgs", err)
}
return Json(200, query.Result)
return JSON(200, query.Result)
}
+48 -50
View File
@@ -7,40 +7,39 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/events"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
func GetPendingOrgInvites(c *middleware.Context) Response {
func GetPendingOrgInvites(c *m.ReqContext) Response {
query := m.GetTempUsersQuery{OrgId: c.OrgId, Status: m.TmpUserInvitePending}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to get invites from db", err)
return Error(500, "Failed to get invites from db", err)
}
for _, invite := range query.Result {
invite.Url = setting.ToAbsUrl("invite/" + invite.Code)
}
return Json(200, query.Result)
return JSON(200, query.Result)
}
func AddOrgInvite(c *middleware.Context, inviteDto dtos.AddInviteForm) Response {
func AddOrgInvite(c *m.ReqContext, inviteDto dtos.AddInviteForm) Response {
if !inviteDto.Role.IsValid() {
return ApiError(400, "Invalid role specified", nil)
return Error(400, "Invalid role specified", nil)
}
// first try get existing user
userQuery := m.GetUserByLoginQuery{LoginOrEmail: inviteDto.LoginOrEmail}
if err := bus.Dispatch(&userQuery); err != nil {
if err != m.ErrUserNotFound {
return ApiError(500, "Failed to query db for existing user check", err)
return Error(500, "Failed to query db for existing user check", err)
}
if setting.DisableLoginForm {
return ApiError(401, "User could not be found", nil)
return Error(401, "User could not be found", nil)
}
} else {
return inviteExistingUserToOrg(c, userQuery.Result, &inviteDto)
@@ -57,7 +56,7 @@ func AddOrgInvite(c *middleware.Context, inviteDto dtos.AddInviteForm) Response
cmd.RemoteAddr = c.Req.RemoteAddr
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to save invite to database", err)
return Error(500, "Failed to save invite to database", err)
}
// send invite email
@@ -75,71 +74,70 @@ func AddOrgInvite(c *middleware.Context, inviteDto dtos.AddInviteForm) Response
}
if err := bus.Dispatch(&emailCmd); err != nil {
return ApiError(500, "Failed to send email invite", err)
return Error(500, "Failed to send email invite", err)
}
emailSentCmd := m.UpdateTempUserWithEmailSentCommand{Code: cmd.Result.Code}
if err := bus.Dispatch(&emailSentCmd); err != nil {
return ApiError(500, "Failed to update invite with email sent info", err)
return Error(500, "Failed to update invite with email sent info", err)
}
return ApiSuccess(fmt.Sprintf("Sent invite to %s", inviteDto.LoginOrEmail))
return Success(fmt.Sprintf("Sent invite to %s", inviteDto.LoginOrEmail))
}
return ApiSuccess(fmt.Sprintf("Created invite for %s", inviteDto.LoginOrEmail))
return Success(fmt.Sprintf("Created invite for %s", inviteDto.LoginOrEmail))
}
func inviteExistingUserToOrg(c *middleware.Context, user *m.User, inviteDto *dtos.AddInviteForm) Response {
func inviteExistingUserToOrg(c *m.ReqContext, user *m.User, inviteDto *dtos.AddInviteForm) Response {
// user exists, add org role
createOrgUserCmd := m.AddOrgUserCommand{OrgId: c.OrgId, UserId: user.Id, Role: inviteDto.Role}
if err := bus.Dispatch(&createOrgUserCmd); err != nil {
if err == m.ErrOrgUserAlreadyAdded {
return ApiError(412, fmt.Sprintf("User %s is already added to organization", inviteDto.LoginOrEmail), err)
return Error(412, fmt.Sprintf("User %s is already added to organization", inviteDto.LoginOrEmail), err)
}
return ApiError(500, "Error while trying to create org user", err)
} else {
if inviteDto.SendEmail && util.IsEmail(user.Email) {
emailCmd := m.SendEmailCommand{
To: []string{user.Email},
Template: "invited_to_org.html",
Data: map[string]interface{}{
"Name": user.NameOrFallback(),
"OrgName": c.OrgName,
"InvitedBy": util.StringsFallback3(c.Name, c.Email, c.Login),
},
}
if err := bus.Dispatch(&emailCmd); err != nil {
return ApiError(500, "Failed to send email invited_to_org", err)
}
}
return ApiSuccess(fmt.Sprintf("Existing Grafana user %s added to org %s", user.NameOrFallback(), c.OrgName))
return Error(500, "Error while trying to create org user", err)
}
if inviteDto.SendEmail && util.IsEmail(user.Email) {
emailCmd := m.SendEmailCommand{
To: []string{user.Email},
Template: "invited_to_org.html",
Data: map[string]interface{}{
"Name": user.NameOrFallback(),
"OrgName": c.OrgName,
"InvitedBy": util.StringsFallback3(c.Name, c.Email, c.Login),
},
}
if err := bus.Dispatch(&emailCmd); err != nil {
return Error(500, "Failed to send email invited_to_org", err)
}
}
return Success(fmt.Sprintf("Existing Grafana user %s added to org %s", user.NameOrFallback(), c.OrgName))
}
func RevokeInvite(c *middleware.Context) Response {
func RevokeInvite(c *m.ReqContext) Response {
if ok, rsp := updateTempUserStatus(c.Params(":code"), m.TmpUserRevoked); !ok {
return rsp
}
return ApiSuccess("Invite revoked")
return Success("Invite revoked")
}
func GetInviteInfoByCode(c *middleware.Context) Response {
func GetInviteInfoByCode(c *m.ReqContext) Response {
query := m.GetTempUserByCodeQuery{Code: c.Params(":code")}
if err := bus.Dispatch(&query); err != nil {
if err == m.ErrTempUserNotFound {
return ApiError(404, "Invite not found", nil)
return Error(404, "Invite not found", nil)
}
return ApiError(500, "Failed to get invite", err)
return Error(500, "Failed to get invite", err)
}
invite := query.Result
return Json(200, dtos.InviteInfo{
return JSON(200, dtos.InviteInfo{
Email: invite.Email,
Name: invite.Name,
Username: invite.Email,
@@ -147,19 +145,19 @@ func GetInviteInfoByCode(c *middleware.Context) Response {
})
}
func CompleteInvite(c *middleware.Context, completeInvite dtos.CompleteInviteForm) Response {
func CompleteInvite(c *m.ReqContext, completeInvite dtos.CompleteInviteForm) Response {
query := m.GetTempUserByCodeQuery{Code: completeInvite.InviteCode}
if err := bus.Dispatch(&query); err != nil {
if err == m.ErrTempUserNotFound {
return ApiError(404, "Invite not found", nil)
return Error(404, "Invite not found", nil)
}
return ApiError(500, "Failed to get invite", err)
return Error(500, "Failed to get invite", err)
}
invite := query.Result
if invite.Status != m.TmpUserInvitePending {
return ApiError(412, fmt.Sprintf("Invite cannot be used in status %s", invite.Status), nil)
return Error(412, fmt.Sprintf("Invite cannot be used in status %s", invite.Status), nil)
}
cmd := m.CreateUserCommand{
@@ -171,7 +169,7 @@ func CompleteInvite(c *middleware.Context, completeInvite dtos.CompleteInviteFor
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "failed to create user", err)
return Error(500, "failed to create user", err)
}
user := &cmd.Result
@@ -190,14 +188,14 @@ func CompleteInvite(c *middleware.Context, completeInvite dtos.CompleteInviteFor
metrics.M_Api_User_SignUpCompleted.Inc()
metrics.M_Api_User_SignUpInvite.Inc()
return ApiSuccess("User created and logged in")
return Success("User created and logged in")
}
func updateTempUserStatus(code string, status m.TempUserStatus) (bool, Response) {
// update temp user status
updateTmpUserCmd := m.UpdateTempUserStatusCommand{Code: code, Status: status}
if err := bus.Dispatch(&updateTmpUserCmd); err != nil {
return false, ApiError(500, "Failed to update invite status", err)
return false, Error(500, "Failed to update invite status", err)
}
return true, nil
@@ -208,7 +206,7 @@ func applyUserInvite(user *m.User, invite *m.TempUserDTO, setActive bool) (bool,
addOrgUserCmd := m.AddOrgUserCommand{OrgId: invite.OrgId, UserId: user.Id, Role: invite.Role}
if err := bus.Dispatch(&addOrgUserCmd); err != nil {
if err != m.ErrOrgUserAlreadyAdded {
return false, ApiError(500, "Error while trying to create org user", err)
return false, Error(500, "Error while trying to create org user", err)
}
}
@@ -220,7 +218,7 @@ func applyUserInvite(user *m.User, invite *m.TempUserDTO, setActive bool) (bool,
if setActive {
// set org to active
if err := bus.Dispatch(&m.SetUsingOrgCommand{OrgId: invite.OrgId, UserId: user.Id}); err != nil {
return false, ApiError(500, "Failed to set org as active", err)
return false, Error(500, "Failed to set org as active", err)
}
}
+31 -32
View File
@@ -3,31 +3,30 @@ package api
import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
)
// POST /api/org/users
func AddOrgUserToCurrentOrg(c *middleware.Context, cmd m.AddOrgUserCommand) Response {
func AddOrgUserToCurrentOrg(c *m.ReqContext, cmd m.AddOrgUserCommand) Response {
cmd.OrgId = c.OrgId
return addOrgUserHelper(cmd)
}
// POST /api/orgs/:orgId/users
func AddOrgUser(c *middleware.Context, cmd m.AddOrgUserCommand) Response {
func AddOrgUser(c *m.ReqContext, cmd m.AddOrgUserCommand) Response {
cmd.OrgId = c.ParamsInt64(":orgId")
return addOrgUserHelper(cmd)
}
func addOrgUserHelper(cmd m.AddOrgUserCommand) Response {
if !cmd.Role.IsValid() {
return ApiError(400, "Invalid role specified", nil)
return Error(400, "Invalid role specified", nil)
}
userQuery := m.GetUserByLoginQuery{LoginOrEmail: cmd.LoginOrEmail}
err := bus.Dispatch(&userQuery)
if err != nil {
return ApiError(404, "User not found", nil)
return Error(404, "User not found", nil)
}
userToAdd := userQuery.Result
@@ -36,51 +35,51 @@ func addOrgUserHelper(cmd m.AddOrgUserCommand) Response {
if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrOrgUserAlreadyAdded {
return ApiError(409, "User is already member of this organization", nil)
return Error(409, "User is already member of this organization", nil)
}
return ApiError(500, "Could not add user to organization", err)
return Error(500, "Could not add user to organization", err)
}
return ApiSuccess("User added to organization")
return Success("User added to organization")
}
// GET /api/org/users
func GetOrgUsersForCurrentOrg(c *middleware.Context) Response {
func GetOrgUsersForCurrentOrg(c *m.ReqContext) Response {
return getOrgUsersHelper(c.OrgId, c.Params("query"), c.ParamsInt("limit"))
}
// GET /api/orgs/:orgId/users
func GetOrgUsers(c *middleware.Context) Response {
func GetOrgUsers(c *m.ReqContext) Response {
return getOrgUsersHelper(c.ParamsInt64(":orgId"), "", 0)
}
func getOrgUsersHelper(orgId int64, query string, limit int) Response {
func getOrgUsersHelper(orgID int64, query string, limit int) Response {
q := m.GetOrgUsersQuery{
OrgId: orgId,
OrgId: orgID,
Query: query,
Limit: limit,
}
if err := bus.Dispatch(&q); err != nil {
return ApiError(500, "Failed to get account user", err)
return Error(500, "Failed to get account user", err)
}
for _, user := range q.Result {
user.AvatarUrl = dtos.GetGravatarUrl(user.Email)
}
return Json(200, q.Result)
return JSON(200, q.Result)
}
// PATCH /api/org/users/:userId
func UpdateOrgUserForCurrentOrg(c *middleware.Context, cmd m.UpdateOrgUserCommand) Response {
func UpdateOrgUserForCurrentOrg(c *m.ReqContext, cmd m.UpdateOrgUserCommand) Response {
cmd.OrgId = c.OrgId
cmd.UserId = c.ParamsInt64(":userId")
return updateOrgUserHelper(cmd)
}
// PATCH /api/orgs/:orgId/users/:userId
func UpdateOrgUser(c *middleware.Context, cmd m.UpdateOrgUserCommand) Response {
func UpdateOrgUser(c *m.ReqContext, cmd m.UpdateOrgUserCommand) Response {
cmd.OrgId = c.ParamsInt64(":orgId")
cmd.UserId = c.ParamsInt64(":userId")
return updateOrgUserHelper(cmd)
@@ -88,41 +87,41 @@ func UpdateOrgUser(c *middleware.Context, cmd m.UpdateOrgUserCommand) Response {
func updateOrgUserHelper(cmd m.UpdateOrgUserCommand) Response {
if !cmd.Role.IsValid() {
return ApiError(400, "Invalid role specified", nil)
return Error(400, "Invalid role specified", nil)
}
if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrLastOrgAdmin {
return ApiError(400, "Cannot change role so that there is no organization admin left", nil)
return Error(400, "Cannot change role so that there is no organization admin left", nil)
}
return ApiError(500, "Failed update org user", err)
return Error(500, "Failed update org user", err)
}
return ApiSuccess("Organization user updated")
return Success("Organization user updated")
}
// DELETE /api/org/users/:userId
func RemoveOrgUserForCurrentOrg(c *middleware.Context) Response {
userId := c.ParamsInt64(":userId")
return removeOrgUserHelper(c.OrgId, userId)
func RemoveOrgUserForCurrentOrg(c *m.ReqContext) Response {
userID := c.ParamsInt64(":userId")
return removeOrgUserHelper(c.OrgId, userID)
}
// DELETE /api/orgs/:orgId/users/:userId
func RemoveOrgUser(c *middleware.Context) Response {
userId := c.ParamsInt64(":userId")
orgId := c.ParamsInt64(":orgId")
return removeOrgUserHelper(orgId, userId)
func RemoveOrgUser(c *m.ReqContext) Response {
userID := c.ParamsInt64(":userId")
orgID := c.ParamsInt64(":orgId")
return removeOrgUserHelper(orgID, userID)
}
func removeOrgUserHelper(orgId int64, userId int64) Response {
cmd := m.RemoveOrgUserCommand{OrgId: orgId, UserId: userId}
func removeOrgUserHelper(orgID int64, userID int64) Response {
cmd := m.RemoveOrgUserCommand{OrgId: orgID, UserId: userID}
if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrLastOrgAdmin {
return ApiError(400, "Cannot remove last organization admin", nil)
return Error(400, "Cannot remove last organization admin", nil)
}
return ApiError(500, "Failed to remove user from organization", err)
return Error(500, "Failed to remove user from organization", err)
}
return ApiSuccess("User removed from organization")
return Success("User removed from organization")
}
+10 -11
View File
@@ -3,39 +3,38 @@ package api
import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util"
)
func SendResetPasswordEmail(c *middleware.Context, form dtos.SendResetPasswordEmailForm) Response {
func SendResetPasswordEmail(c *m.ReqContext, form dtos.SendResetPasswordEmailForm) Response {
userQuery := m.GetUserByLoginQuery{LoginOrEmail: form.UserOrEmail}
if err := bus.Dispatch(&userQuery); err != nil {
c.Logger.Info("Requested password reset for user that was not found", "user", userQuery.LoginOrEmail)
return ApiError(200, "Email sent", err)
return Error(200, "Email sent", err)
}
emailCmd := m.SendResetPasswordEmailCommand{User: userQuery.Result}
if err := bus.Dispatch(&emailCmd); err != nil {
return ApiError(500, "Failed to send email", err)
return Error(500, "Failed to send email", err)
}
return ApiSuccess("Email sent")
return Success("Email sent")
}
func ResetPassword(c *middleware.Context, form dtos.ResetUserPasswordForm) Response {
func ResetPassword(c *m.ReqContext, form dtos.ResetUserPasswordForm) Response {
query := m.ValidateResetPasswordCodeQuery{Code: form.Code}
if err := bus.Dispatch(&query); err != nil {
if err == m.ErrInvalidEmailCode {
return ApiError(400, "Invalid or expired reset password code", nil)
return Error(400, "Invalid or expired reset password code", nil)
}
return ApiError(500, "Unknown error validating email code", err)
return Error(500, "Unknown error validating email code", err)
}
if form.NewPassword != form.ConfirmPassword {
return ApiError(400, "Passwords do not match", nil)
return Error(400, "Passwords do not match", nil)
}
cmd := m.ChangeUserPasswordCommand{}
@@ -43,8 +42,8 @@ func ResetPassword(c *middleware.Context, form dtos.ResetUserPasswordForm) Respo
cmd.NewPassword = util.EncodePassword(form.NewPassword, query.Result.Salt)
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to change user password", err)
return Error(500, "Failed to change user password", err)
}
return ApiSuccess("User password changed")
return Success("User password changed")
}
+26 -27
View File
@@ -3,11 +3,10 @@ package api
import (
"github.com/grafana/grafana/pkg/bus"
_ "github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
)
func ValidateOrgPlaylist(c *middleware.Context) {
func ValidateOrgPlaylist(c *m.ReqContext) {
id := c.ParamsInt64(":id")
query := m.GetPlaylistByIdQuery{Id: id}
err := bus.Dispatch(&query)
@@ -34,13 +33,13 @@ func ValidateOrgPlaylist(c *middleware.Context) {
return
}
if len(items) == 0 {
if len(items) == 0 && c.Context.Req.Method != "DELETE" {
c.JsonApiErr(404, "Playlist is empty", itemsErr)
return
}
}
func SearchPlaylists(c *middleware.Context) Response {
func SearchPlaylists(c *m.ReqContext) Response {
query := c.Query("query")
limit := c.QueryInt("limit")
@@ -56,18 +55,18 @@ func SearchPlaylists(c *middleware.Context) Response {
err := bus.Dispatch(&searchQuery)
if err != nil {
return ApiError(500, "Search failed", err)
return Error(500, "Search failed", err)
}
return Json(200, searchQuery.Result)
return JSON(200, searchQuery.Result)
}
func GetPlaylist(c *middleware.Context) Response {
func GetPlaylist(c *m.ReqContext) Response {
id := c.ParamsInt64(":id")
cmd := m.GetPlaylistByIdQuery{Id: id}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Playlist not found", err)
return Error(500, "Playlist not found", err)
}
playlistDTOs, _ := LoadPlaylistItemDTOs(id)
@@ -80,7 +79,7 @@ func GetPlaylist(c *middleware.Context) Response {
Items: playlistDTOs,
}
return Json(200, dto)
return JSON(200, dto)
}
func LoadPlaylistItemDTOs(id int64) ([]m.PlaylistItemDTO, error) {
@@ -115,62 +114,62 @@ func LoadPlaylistItems(id int64) ([]m.PlaylistItem, error) {
return *itemQuery.Result, nil
}
func GetPlaylistItems(c *middleware.Context) Response {
func GetPlaylistItems(c *m.ReqContext) Response {
id := c.ParamsInt64(":id")
playlistDTOs, err := LoadPlaylistItemDTOs(id)
if err != nil {
return ApiError(500, "Could not load playlist items", err)
return Error(500, "Could not load playlist items", err)
}
return Json(200, playlistDTOs)
return JSON(200, playlistDTOs)
}
func GetPlaylistDashboards(c *middleware.Context) Response {
playlistId := c.ParamsInt64(":id")
func GetPlaylistDashboards(c *m.ReqContext) Response {
playlistID := c.ParamsInt64(":id")
playlists, err := LoadPlaylistDashboards(c.OrgId, c.SignedInUser, playlistId)
playlists, err := LoadPlaylistDashboards(c.OrgId, c.SignedInUser, playlistID)
if err != nil {
return ApiError(500, "Could not load dashboards", err)
return Error(500, "Could not load dashboards", err)
}
return Json(200, playlists)
return JSON(200, playlists)
}
func DeletePlaylist(c *middleware.Context) Response {
func DeletePlaylist(c *m.ReqContext) Response {
id := c.ParamsInt64(":id")
cmd := m.DeletePlaylistCommand{Id: id, OrgId: c.OrgId}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to delete playlist", err)
return Error(500, "Failed to delete playlist", err)
}
return Json(200, "")
return JSON(200, "")
}
func CreatePlaylist(c *middleware.Context, cmd m.CreatePlaylistCommand) Response {
func CreatePlaylist(c *m.ReqContext, cmd m.CreatePlaylistCommand) Response {
cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to create playlist", err)
return Error(500, "Failed to create playlist", err)
}
return Json(200, cmd.Result)
return JSON(200, cmd.Result)
}
func UpdatePlaylist(c *middleware.Context, cmd m.UpdatePlaylistCommand) Response {
func UpdatePlaylist(c *m.ReqContext, cmd m.UpdatePlaylistCommand) Response {
cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to save playlist", err)
return Error(500, "Failed to save playlist", err)
}
playlistDTOs, err := LoadPlaylistItemDTOs(cmd.Id)
if err != nil {
return ApiError(500, "Failed to save playlist", err)
return Error(500, "Failed to save playlist", err)
}
cmd.Result.Items = playlistDTOs
return Json(200, cmd.Result)
return JSON(200, cmd.Result)
}
+31 -33
View File
@@ -11,11 +11,11 @@ import (
"github.com/grafana/grafana/pkg/services/search"
)
func populateDashboardsById(dashboardByIds []int64, dashboardIdOrder map[int64]int) (dtos.PlaylistDashboardsSlice, error) {
func populateDashboardsByID(dashboardByIDs []int64, dashboardIDOrder map[int64]int) (dtos.PlaylistDashboardsSlice, error) {
result := make(dtos.PlaylistDashboardsSlice, 0)
if len(dashboardByIds) > 0 {
dashboardQuery := m.GetDashboardsQuery{DashboardIds: dashboardByIds}
if len(dashboardByIDs) > 0 {
dashboardQuery := m.GetDashboardsQuery{DashboardIds: dashboardByIDs}
if err := bus.Dispatch(&dashboardQuery); err != nil {
return result, err
}
@@ -26,7 +26,7 @@ func populateDashboardsById(dashboardByIds []int64, dashboardIdOrder map[int64]i
Slug: item.Slug,
Title: item.Title,
Uri: "db/" + item.Slug,
Order: dashboardIdOrder[item.Id],
Order: dashboardIDOrder[item.Id],
})
}
}
@@ -34,29 +34,27 @@ func populateDashboardsById(dashboardByIds []int64, dashboardIdOrder map[int64]i
return result, nil
}
func populateDashboardsByTag(orgId int64, signedInUser *m.SignedInUser, dashboardByTag []string, dashboardTagOrder map[string]int) dtos.PlaylistDashboardsSlice {
func populateDashboardsByTag(orgID int64, signedInUser *m.SignedInUser, dashboardByTag []string, dashboardTagOrder map[string]int) dtos.PlaylistDashboardsSlice {
result := make(dtos.PlaylistDashboardsSlice, 0)
if len(dashboardByTag) > 0 {
for _, tag := range dashboardByTag {
searchQuery := search.Query{
Title: "",
Tags: []string{tag},
SignedInUser: signedInUser,
Limit: 100,
IsStarred: false,
OrgId: orgId,
}
for _, tag := range dashboardByTag {
searchQuery := search.Query{
Title: "",
Tags: []string{tag},
SignedInUser: signedInUser,
Limit: 100,
IsStarred: false,
OrgId: orgID,
}
if err := bus.Dispatch(&searchQuery); err == nil {
for _, item := range searchQuery.Result {
result = append(result, dtos.PlaylistDashboard{
Id: item.Id,
Title: item.Title,
Uri: item.Uri,
Order: dashboardTagOrder[tag],
})
}
if err := bus.Dispatch(&searchQuery); err == nil {
for _, item := range searchQuery.Result {
result = append(result, dtos.PlaylistDashboard{
Id: item.Id,
Title: item.Title,
Uri: item.Uri,
Order: dashboardTagOrder[tag],
})
}
}
}
@@ -64,19 +62,19 @@ func populateDashboardsByTag(orgId int64, signedInUser *m.SignedInUser, dashboar
return result
}
func LoadPlaylistDashboards(orgId int64, signedInUser *m.SignedInUser, playlistId int64) (dtos.PlaylistDashboardsSlice, error) {
playlistItems, _ := LoadPlaylistItems(playlistId)
func LoadPlaylistDashboards(orgID int64, signedInUser *m.SignedInUser, playlistID int64) (dtos.PlaylistDashboardsSlice, error) {
playlistItems, _ := LoadPlaylistItems(playlistID)
dashboardByIds := make([]int64, 0)
dashboardByIDs := make([]int64, 0)
dashboardByTag := make([]string, 0)
dashboardIdOrder := make(map[int64]int)
dashboardIDOrder := make(map[int64]int)
dashboardTagOrder := make(map[string]int)
for _, i := range playlistItems {
if i.Type == "dashboard_by_id" {
dashboardId, _ := strconv.ParseInt(i.Value, 10, 64)
dashboardByIds = append(dashboardByIds, dashboardId)
dashboardIdOrder[dashboardId] = i.Order
dashboardID, _ := strconv.ParseInt(i.Value, 10, 64)
dashboardByIDs = append(dashboardByIDs, dashboardID)
dashboardIDOrder[dashboardID] = i.Order
}
if i.Type == "dashboard_by_tag" {
@@ -87,9 +85,9 @@ func LoadPlaylistDashboards(orgId int64, signedInUser *m.SignedInUser, playlistI
result := make(dtos.PlaylistDashboardsSlice, 0)
var k, _ = populateDashboardsById(dashboardByIds, dashboardIdOrder)
var k, _ = populateDashboardsByID(dashboardByIDs, dashboardIDOrder)
result = append(result, k...)
result = append(result, populateDashboardsByTag(orgId, signedInUser, dashboardByTag, dashboardTagOrder)...)
result = append(result, populateDashboardsByTag(orgID, signedInUser, dashboardByTag, dashboardTagOrder)...)
sort.Sort(result)
return result, nil
+36 -26
View File
@@ -18,7 +18,6 @@ import (
"github.com/opentracing/opentracing-go"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/setting"
@@ -26,8 +25,8 @@ import (
)
var (
logger log.Logger = log.New("data-proxy-log")
client *http.Client = &http.Client{
logger = log.New("data-proxy-log")
client = &http.Client{
Timeout: time.Second * 30,
Transport: &http.Transport{Proxy: http.ProxyFromEnvironment},
}
@@ -42,22 +41,22 @@ type jwtToken struct {
type DataSourceProxy struct {
ds *m.DataSource
ctx *middleware.Context
ctx *m.ReqContext
targetUrl *url.URL
proxyPath string
route *plugins.AppPluginRoute
plugin *plugins.DataSourcePlugin
}
func NewDataSourceProxy(ds *m.DataSource, plugin *plugins.DataSourcePlugin, ctx *middleware.Context, proxyPath string) *DataSourceProxy {
targetUrl, _ := url.Parse(ds.Url)
func NewDataSourceProxy(ds *m.DataSource, plugin *plugins.DataSourcePlugin, ctx *m.ReqContext, proxyPath string) *DataSourceProxy {
targetURL, _ := url.Parse(ds.Url)
return &DataSourceProxy{
ds: ds,
plugin: plugin,
ctx: ctx,
proxyPath: proxyPath,
targetUrl: targetUrl,
targetUrl: targetURL,
}
}
@@ -90,6 +89,9 @@ func (proxy *DataSourceProxy) HandleRequest() {
span.SetTag("user_id", proxy.ctx.SignedInUser.UserId)
span.SetTag("org_id", proxy.ctx.SignedInUser.OrgId)
proxy.addTraceFromHeaderValue(span, "X-Panel-Id", "panel_id")
proxy.addTraceFromHeaderValue(span, "X-Dashboard-Id", "dashboard_id")
opentracing.GlobalTracer().Inject(
span.Context(),
opentracing.HTTPHeaders,
@@ -99,6 +101,14 @@ func (proxy *DataSourceProxy) HandleRequest() {
proxy.ctx.Resp.Header().Del("Set-Cookie")
}
func (proxy *DataSourceProxy) addTraceFromHeaderValue(span opentracing.Span, headerName string, tagName string) {
panelId := proxy.ctx.Req.Header.Get(headerName)
dashId, err := strconv.Atoi(panelId)
if err == nil {
span.SetTag(tagName, dashId)
}
}
func (proxy *DataSourceProxy) getDirector() func(req *http.Request) {
return func(req *http.Request) {
req.URL.Scheme = proxy.targetUrl.Scheme
@@ -179,19 +189,19 @@ func (proxy *DataSourceProxy) getDirector() func(req *http.Request) {
}
func (proxy *DataSourceProxy) validateRequest() error {
if proxy.ds.Type == m.DS_INFLUXDB {
if proxy.ctx.Query("db") != proxy.ds.Database {
return errors.New("Datasource is not configured to allow this database")
}
}
if !checkWhiteList(proxy.ctx, proxy.targetUrl.Host) {
return errors.New("Target url is not a valid target")
}
if proxy.ds.Type == m.DS_PROMETHEUS {
if proxy.ctx.Req.Request.Method != http.MethodGet || !strings.HasPrefix(proxy.proxyPath, "api/") {
return errors.New("GET is only allowed on proxied Prometheus datasource")
if proxy.ctx.Req.Request.Method == "DELETE" {
return errors.New("Deletes not allowed on proxied Prometheus datasource")
}
if proxy.ctx.Req.Request.Method == "PUT" {
return errors.New("Puts not allowed on proxied Prometheus datasource")
}
if proxy.ctx.Req.Request.Method == "POST" && !(proxy.proxyPath == "api/v1/query" || proxy.proxyPath == "api/v1/query_range") {
return errors.New("Posts not allowed on proxied Prometheus datasource except on /query and /query_range")
}
}
@@ -255,7 +265,7 @@ func (proxy *DataSourceProxy) logRequest() {
"body", body)
}
func checkWhiteList(c *middleware.Context, host string) bool {
func checkWhiteList(c *m.ReqContext, host string) bool {
if host != "" && len(setting.DataProxyWhiteList) > 0 {
if _, exists := setting.DataProxyWhiteList[host]; !exists {
c.JsonApiErr(403, "Data proxy hostname and ip are not included in whitelist", nil)
@@ -274,16 +284,16 @@ func (proxy *DataSourceProxy) applyRoute(req *http.Request) {
SecureJsonData: proxy.ds.SecureJsonData.Decrypt(),
}
routeUrl, err := url.Parse(proxy.route.Url)
routeURL, err := url.Parse(proxy.route.Url)
if err != nil {
logger.Error("Error parsing plugin route url")
return
}
req.URL.Scheme = routeUrl.Scheme
req.URL.Host = routeUrl.Host
req.Host = routeUrl.Host
req.URL.Path = util.JoinUrlFragments(routeUrl.Path, proxy.proxyPath)
req.URL.Scheme = routeURL.Scheme
req.URL.Host = routeURL.Host
req.Host = routeURL.Host
req.URL.Path = util.JoinUrlFragments(routeURL.Path, proxy.proxyPath)
if err := addHeaders(&req.Header, proxy.route, data); err != nil {
logger.Error("Failed to render plugin headers", "error", err)
@@ -315,11 +325,11 @@ func (proxy *DataSourceProxy) getAccessToken(data templateData) (string, error)
params := make(url.Values)
for key, value := range proxy.route.TokenAuth.Params {
if interpolatedParam, err := interpolateString(value, data); err != nil {
interpolatedParam, err := interpolateString(value, data)
if err != nil {
return "", err
} else {
params.Add(key, interpolatedParam)
}
params.Add(key, interpolatedParam)
}
getTokenReq, _ := http.NewRequest("POST", urlInterpolated, bytes.NewBufferString(params.Encode()))
@@ -349,13 +359,13 @@ func (proxy *DataSourceProxy) getAccessToken(data templateData) (string, error)
func interpolateString(text string, data templateData) (string, error) {
t, err := template.New("content").Parse(text)
if err != nil {
return "", errors.New(fmt.Sprintf("Could not parse template %s.", text))
return "", fmt.Errorf("could not parse template %s", text)
}
var contentBuf bytes.Buffer
err = t.Execute(&contentBuf, data)
if err != nil {
return "", errors.New(fmt.Sprintf("Failed to execute template %s.", text))
return "", fmt.Errorf("failed to execute template %s", text)
}
return contentBuf.String(), nil
+13 -14
View File
@@ -8,7 +8,6 @@ import (
macaron "gopkg.in/macaron.v1"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/setting"
@@ -61,7 +60,7 @@ func TestDSRouteRule(t *testing.T) {
}
req, _ := http.NewRequest("GET", "http://localhost/asd", nil)
ctx := &middleware.Context{
ctx := &m.ReqContext{
Context: &macaron.Context{
Req: macaron.Request{Request: req},
},
@@ -104,12 +103,12 @@ func TestDSRouteRule(t *testing.T) {
Convey("When proxying graphite", func() {
plugin := &plugins.DataSourcePlugin{}
ds := &m.DataSource{Url: "htttp://graphite:8080", Type: m.DS_GRAPHITE}
ctx := &middleware.Context{}
ctx := &m.ReqContext{}
proxy := NewDataSourceProxy(ds, plugin, ctx, "/render")
requestUrl, _ := url.Parse("http://grafana.com/sub")
req := http.Request{URL: requestUrl}
requestURL, _ := url.Parse("http://grafana.com/sub")
req := http.Request{URL: requestURL}
proxy.getDirector()(&req)
@@ -130,11 +129,11 @@ func TestDSRouteRule(t *testing.T) {
Password: "password",
}
ctx := &middleware.Context{}
ctx := &m.ReqContext{}
proxy := NewDataSourceProxy(ds, plugin, ctx, "")
requestUrl, _ := url.Parse("http://grafana.com/sub")
req := http.Request{URL: requestUrl}
requestURL, _ := url.Parse("http://grafana.com/sub")
req := http.Request{URL: requestURL}
proxy.getDirector()(&req)
@@ -160,11 +159,11 @@ func TestDSRouteRule(t *testing.T) {
JsonData: json,
}
ctx := &middleware.Context{}
ctx := &m.ReqContext{}
proxy := NewDataSourceProxy(ds, plugin, ctx, "")
requestUrl, _ := url.Parse("http://grafana.com/sub")
req := http.Request{URL: requestUrl, Header: make(http.Header)}
requestURL, _ := url.Parse("http://grafana.com/sub")
req := http.Request{URL: requestURL, Header: make(http.Header)}
cookies := "grafana_user=admin; grafana_remember=99; grafana_sess=11; JSESSION_ID=test"
req.Header.Set("Cookie", cookies)
@@ -186,11 +185,11 @@ func TestDSRouteRule(t *testing.T) {
JsonData: json,
}
ctx := &middleware.Context{}
ctx := &m.ReqContext{}
proxy := NewDataSourceProxy(ds, plugin, ctx, "")
requestUrl, _ := url.Parse("http://grafana.com/sub")
req := http.Request{URL: requestUrl, Header: make(http.Header)}
requestURL, _ := url.Parse("http://grafana.com/sub")
req := http.Request{URL: requestURL, Header: make(http.Header)}
cookies := "grafana_user=admin; grafana_remember=99; grafana_sess=11; JSESSION_ID=test"
req.Header.Set("Cookie", cookies)
+9 -10
View File
@@ -9,7 +9,6 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/util"
@@ -20,10 +19,10 @@ type templateData struct {
SecureJsonData map[string]string
}
func getHeaders(route *plugins.AppPluginRoute, orgId int64, appId string) (http.Header, error) {
func getHeaders(route *plugins.AppPluginRoute, orgId int64, appID string) (http.Header, error) {
result := http.Header{}
query := m.GetPluginSettingByIdQuery{OrgId: orgId, PluginId: appId}
query := m.GetPluginSettingByIdQuery{OrgId: orgId, PluginId: appID}
if err := bus.Dispatch(&query); err != nil {
return nil, err
@@ -38,16 +37,16 @@ func getHeaders(route *plugins.AppPluginRoute, orgId int64, appId string) (http.
return result, err
}
func NewApiPluginProxy(ctx *middleware.Context, proxyPath string, route *plugins.AppPluginRoute, appId string) *httputil.ReverseProxy {
targetUrl, _ := url.Parse(route.Url)
func NewApiPluginProxy(ctx *m.ReqContext, proxyPath string, route *plugins.AppPluginRoute, appID string) *httputil.ReverseProxy {
targetURL, _ := url.Parse(route.Url)
director := func(req *http.Request) {
req.URL.Scheme = targetUrl.Scheme
req.URL.Host = targetUrl.Host
req.Host = targetUrl.Host
req.URL.Scheme = targetURL.Scheme
req.URL.Host = targetURL.Host
req.Host = targetURL.Host
req.URL.Path = util.JoinUrlFragments(targetUrl.Path, proxyPath)
req.URL.Path = util.JoinUrlFragments(targetURL.Path, proxyPath)
// clear cookie headers
req.Header.Del("Cookie")
@@ -81,7 +80,7 @@ func NewApiPluginProxy(ctx *middleware.Context, proxyPath string, route *plugins
req.Header.Add("X-Grafana-Context", string(ctxJson))
if len(route.Headers) > 0 {
headers, err := getHeaders(route, ctx.OrgId, appId)
headers, err := getHeaders(route, ctx.OrgId, appID)
if err != nil {
ctx.JsonApiErr(500, "Could not generate plugin route header", err)
return
+63 -62
View File
@@ -5,13 +5,12 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/setting"
)
func GetPluginList(c *middleware.Context) Response {
func GetPluginList(c *m.ReqContext) Response {
typeFilter := c.Query("type")
enabledFilter := c.Query("enabled")
embeddedFilter := c.Query("embedded")
@@ -20,7 +19,7 @@ func GetPluginList(c *middleware.Context) Response {
pluginSettingsMap, err := plugins.GetPluginSettings(c.OrgId)
if err != nil {
return ApiError(500, "Failed to get list of plugins", err)
return Error(500, "Failed to get list of plugins", err)
}
result := make(dtos.PluginList, 0)
@@ -76,95 +75,97 @@ func GetPluginList(c *middleware.Context) Response {
}
sort.Sort(result)
return Json(200, result)
return JSON(200, result)
}
func GetPluginSettingById(c *middleware.Context) Response {
pluginId := c.Params(":pluginId")
func GetPluginSettingByID(c *m.ReqContext) Response {
pluginID := c.Params(":pluginId")
if def, exists := plugins.Plugins[pluginId]; !exists {
return ApiError(404, "Plugin not found, no installed plugin with that id", nil)
} else {
dto := &dtos.PluginSetting{
Type: def.Type,
Id: def.Id,
Name: def.Name,
Info: &def.Info,
Dependencies: &def.Dependencies,
Includes: def.Includes,
BaseUrl: def.BaseUrl,
Module: def.Module,
DefaultNavUrl: def.DefaultNavUrl,
LatestVersion: def.GrafanaNetVersion,
HasUpdate: def.GrafanaNetHasUpdate,
State: def.State,
}
query := m.GetPluginSettingByIdQuery{PluginId: pluginId, OrgId: c.OrgId}
if err := bus.Dispatch(&query); err != nil {
if err != m.ErrPluginSettingNotFound {
return ApiError(500, "Failed to get login settings", nil)
}
} else {
dto.Enabled = query.Result.Enabled
dto.Pinned = query.Result.Pinned
dto.JsonData = query.Result.JsonData
}
return Json(200, dto)
def, exists := plugins.Plugins[pluginID]
if !exists {
return Error(404, "Plugin not found, no installed plugin with that id", nil)
}
dto := &dtos.PluginSetting{
Type: def.Type,
Id: def.Id,
Name: def.Name,
Info: &def.Info,
Dependencies: &def.Dependencies,
Includes: def.Includes,
BaseUrl: def.BaseUrl,
Module: def.Module,
DefaultNavUrl: def.DefaultNavUrl,
LatestVersion: def.GrafanaNetVersion,
HasUpdate: def.GrafanaNetHasUpdate,
State: def.State,
}
query := m.GetPluginSettingByIdQuery{PluginId: pluginID, OrgId: c.OrgId}
if err := bus.Dispatch(&query); err != nil {
if err != m.ErrPluginSettingNotFound {
return Error(500, "Failed to get login settings", nil)
}
} else {
dto.Enabled = query.Result.Enabled
dto.Pinned = query.Result.Pinned
dto.JsonData = query.Result.JsonData
}
return JSON(200, dto)
}
func UpdatePluginSetting(c *middleware.Context, cmd m.UpdatePluginSettingCmd) Response {
pluginId := c.Params(":pluginId")
func UpdatePluginSetting(c *m.ReqContext, cmd m.UpdatePluginSettingCmd) Response {
pluginID := c.Params(":pluginId")
cmd.OrgId = c.OrgId
cmd.PluginId = pluginId
cmd.PluginId = pluginID
if _, ok := plugins.Apps[cmd.PluginId]; !ok {
return ApiError(404, "Plugin not installed.", nil)
return Error(404, "Plugin not installed.", nil)
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to update plugin setting", err)
return Error(500, "Failed to update plugin setting", err)
}
return ApiSuccess("Plugin settings updated")
return Success("Plugin settings updated")
}
func GetPluginDashboards(c *middleware.Context) Response {
pluginId := c.Params(":pluginId")
func GetPluginDashboards(c *m.ReqContext) Response {
pluginID := c.Params(":pluginId")
if list, err := plugins.GetPluginDashboards(c.OrgId, pluginId); err != nil {
list, err := plugins.GetPluginDashboards(c.OrgId, pluginID)
if err != nil {
if notfound, ok := err.(plugins.PluginNotFoundError); ok {
return ApiError(404, notfound.Error(), nil)
return Error(404, notfound.Error(), nil)
}
return ApiError(500, "Failed to get plugin dashboards", err)
} else {
return Json(200, list)
return Error(500, "Failed to get plugin dashboards", err)
}
return JSON(200, list)
}
func GetPluginMarkdown(c *middleware.Context) Response {
pluginId := c.Params(":pluginId")
func GetPluginMarkdown(c *m.ReqContext) Response {
pluginID := c.Params(":pluginId")
name := c.Params(":name")
if content, err := plugins.GetPluginMarkdown(pluginId, name); err != nil {
content, err := plugins.GetPluginMarkdown(pluginID, name)
if err != nil {
if notfound, ok := err.(plugins.PluginNotFoundError); ok {
return ApiError(404, notfound.Error(), nil)
return Error(404, notfound.Error(), nil)
}
return ApiError(500, "Could not get markdown file", err)
} else {
resp := Respond(200, content)
resp.Header("Content-Type", "text/plain; charset=utf-8")
return resp
return Error(500, "Could not get markdown file", err)
}
resp := Respond(200, content)
resp.Header("Content-Type", "text/plain; charset=utf-8")
return resp
}
func ImportDashboard(c *middleware.Context, apiCmd dtos.ImportDashboardCommand) Response {
func ImportDashboard(c *m.ReqContext, apiCmd dtos.ImportDashboardCommand) Response {
cmd := plugins.ImportDashboardCommand{
OrgId: c.OrgId,
@@ -177,8 +178,8 @@ func ImportDashboard(c *middleware.Context, apiCmd dtos.ImportDashboardCommand)
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to import dashboard", err)
return Error(500, "Failed to import dashboard", err)
}
return Json(200, cmd.Result)
return JSON(200, cmd.Result)
}
+18 -19
View File
@@ -3,71 +3,70 @@ package api
import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
)
// POST /api/preferences/set-home-dash
func SetHomeDashboard(c *middleware.Context, cmd m.SavePreferencesCommand) Response {
func SetHomeDashboard(c *m.ReqContext, cmd m.SavePreferencesCommand) Response {
cmd.UserId = c.UserId
cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to set home dashboard", err)
return Error(500, "Failed to set home dashboard", err)
}
return ApiSuccess("Home dashboard set")
return Success("Home dashboard set")
}
// GET /api/user/preferences
func GetUserPreferences(c *middleware.Context) Response {
func GetUserPreferences(c *m.ReqContext) Response {
return getPreferencesFor(c.OrgId, c.UserId)
}
func getPreferencesFor(orgId int64, userId int64) Response {
prefsQuery := m.GetPreferencesQuery{UserId: userId, OrgId: orgId}
func getPreferencesFor(orgID int64, userID int64) Response {
prefsQuery := m.GetPreferencesQuery{UserId: userID, OrgId: orgID}
if err := bus.Dispatch(&prefsQuery); err != nil {
return ApiError(500, "Failed to get preferences", err)
return Error(500, "Failed to get preferences", err)
}
dto := dtos.Prefs{
Theme: prefsQuery.Result.Theme,
HomeDashboardId: prefsQuery.Result.HomeDashboardId,
HomeDashboardID: prefsQuery.Result.HomeDashboardId,
Timezone: prefsQuery.Result.Timezone,
}
return Json(200, &dto)
return JSON(200, &dto)
}
// PUT /api/user/preferences
func UpdateUserPreferences(c *middleware.Context, dtoCmd dtos.UpdatePrefsCmd) Response {
func UpdateUserPreferences(c *m.ReqContext, dtoCmd dtos.UpdatePrefsCmd) Response {
return updatePreferencesFor(c.OrgId, c.UserId, &dtoCmd)
}
func updatePreferencesFor(orgId int64, userId int64, dtoCmd *dtos.UpdatePrefsCmd) Response {
func updatePreferencesFor(orgID int64, userID int64, dtoCmd *dtos.UpdatePrefsCmd) Response {
saveCmd := m.SavePreferencesCommand{
UserId: userId,
OrgId: orgId,
UserId: userID,
OrgId: orgID,
Theme: dtoCmd.Theme,
Timezone: dtoCmd.Timezone,
HomeDashboardId: dtoCmd.HomeDashboardId,
HomeDashboardId: dtoCmd.HomeDashboardID,
}
if err := bus.Dispatch(&saveCmd); err != nil {
return ApiError(500, "Failed to save preferences", err)
return Error(500, "Failed to save preferences", err)
}
return ApiSuccess("Preferences updated")
return Success("Preferences updated")
}
// GET /api/org/preferences
func GetOrgPreferences(c *middleware.Context) Response {
func GetOrgPreferences(c *m.ReqContext) Response {
return getPreferencesFor(c.OrgId, 0)
}
// PUT /api/org/preferences
func UpdateOrgPreferences(c *middleware.Context, dtoCmd dtos.UpdatePrefsCmd) Response {
func UpdateOrgPreferences(c *m.ReqContext, dtoCmd dtos.UpdatePrefsCmd) Response {
return updatePreferencesFor(c.OrgId, 0, &dtoCmd)
}
+18 -19
View File
@@ -2,67 +2,66 @@ package api
import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
)
func GetOrgQuotas(c *middleware.Context) Response {
func GetOrgQuotas(c *m.ReqContext) Response {
if !setting.Quota.Enabled {
return ApiError(404, "Quotas not enabled", nil)
return Error(404, "Quotas not enabled", nil)
}
query := m.GetOrgQuotasQuery{OrgId: c.ParamsInt64(":orgId")}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to get org quotas", err)
return Error(500, "Failed to get org quotas", err)
}
return Json(200, query.Result)
return JSON(200, query.Result)
}
func UpdateOrgQuota(c *middleware.Context, cmd m.UpdateOrgQuotaCmd) Response {
func UpdateOrgQuota(c *m.ReqContext, cmd m.UpdateOrgQuotaCmd) Response {
if !setting.Quota.Enabled {
return ApiError(404, "Quotas not enabled", nil)
return Error(404, "Quotas not enabled", nil)
}
cmd.OrgId = c.ParamsInt64(":orgId")
cmd.Target = c.Params(":target")
if _, ok := setting.Quota.Org.ToMap()[cmd.Target]; !ok {
return ApiError(404, "Invalid quota target", nil)
return Error(404, "Invalid quota target", nil)
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to update org quotas", err)
return Error(500, "Failed to update org quotas", err)
}
return ApiSuccess("Organization quota updated")
return Success("Organization quota updated")
}
func GetUserQuotas(c *middleware.Context) Response {
func GetUserQuotas(c *m.ReqContext) Response {
if !setting.Quota.Enabled {
return ApiError(404, "Quotas not enabled", nil)
return Error(404, "Quotas not enabled", nil)
}
query := m.GetUserQuotasQuery{UserId: c.ParamsInt64(":id")}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to get org quotas", err)
return Error(500, "Failed to get org quotas", err)
}
return Json(200, query.Result)
return JSON(200, query.Result)
}
func UpdateUserQuota(c *middleware.Context, cmd m.UpdateUserQuotaCmd) Response {
func UpdateUserQuota(c *m.ReqContext, cmd m.UpdateUserQuotaCmd) Response {
if !setting.Quota.Enabled {
return ApiError(404, "Quotas not enabled", nil)
return Error(404, "Quotas not enabled", nil)
}
cmd.UserId = c.ParamsInt64(":id")
cmd.Target = c.Params(":target")
if _, ok := setting.Quota.User.ToMap()[cmd.Target]; !ok {
return ApiError(404, "Invalid quota target", nil)
return Error(404, "Invalid quota target", nil)
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to update org quotas", err)
return Error(500, "Failed to update org quotas", err)
}
return ApiSuccess("Organization quota updated")
return Success("Organization quota updated")
}
+2 -2
View File
@@ -5,11 +5,11 @@ import (
"net/http"
"github.com/grafana/grafana/pkg/components/renderer"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util"
)
func RenderToPng(c *middleware.Context) {
func RenderToPng(c *m.ReqContext) {
queryReader, err := util.NewUrlQueryReader(c.Req.URL)
if err != nil {
c.Handle(400, "Render parameters error", err)
+12 -13
View File
@@ -5,40 +5,39 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/search"
)
func Search(c *middleware.Context) {
func Search(c *m.ReqContext) {
query := c.Query("query")
tags := c.QueryStrings("tag")
starred := c.Query("starred")
limit := c.QueryInt("limit")
dashboardType := c.Query("type")
permission := models.PERMISSION_VIEW
permission := m.PERMISSION_VIEW
if limit == 0 {
limit = 1000
}
if c.Query("permission") == "Edit" {
permission = models.PERMISSION_EDIT
permission = m.PERMISSION_EDIT
}
dbids := make([]int64, 0)
dbIDs := make([]int64, 0)
for _, id := range c.QueryStrings("dashboardIds") {
dashboardId, err := strconv.ParseInt(id, 10, 64)
dashboardID, err := strconv.ParseInt(id, 10, 64)
if err == nil {
dbids = append(dbids, dashboardId)
dbIDs = append(dbIDs, dashboardID)
}
}
folderIds := make([]int64, 0)
folderIDs := make([]int64, 0)
for _, id := range c.QueryStrings("folderIds") {
folderId, err := strconv.ParseInt(id, 10, 64)
folderID, err := strconv.ParseInt(id, 10, 64)
if err == nil {
folderIds = append(folderIds, folderId)
folderIDs = append(folderIDs, folderID)
}
}
@@ -49,9 +48,9 @@ func Search(c *middleware.Context) {
Limit: limit,
IsStarred: starred == "true",
OrgId: c.OrgId,
DashboardIds: dbids,
DashboardIds: dbIDs,
Type: dashboardType,
FolderIds: folderIds,
FolderIds: folderIDs,
Permission: permission,
}
+16 -17
View File
@@ -5,29 +5,28 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/events"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
// GET /api/user/signup/options
func GetSignUpOptions(c *middleware.Context) Response {
return Json(200, util.DynMap{
func GetSignUpOptions(c *m.ReqContext) Response {
return JSON(200, util.DynMap{
"verifyEmailEnabled": setting.VerifyEmailEnabled,
"autoAssignOrg": setting.AutoAssignOrg,
})
}
// POST /api/user/signup
func SignUp(c *middleware.Context, form dtos.SignUpForm) Response {
func SignUp(c *m.ReqContext, form dtos.SignUpForm) Response {
if !setting.AllowUserSignUp {
return ApiError(401, "User signup is disabled", nil)
return Error(401, "User signup is disabled", nil)
}
existing := m.GetUserByLoginQuery{LoginOrEmail: form.Email}
if err := bus.Dispatch(&existing); err == nil {
return ApiError(422, "User with same email address already exists", nil)
return Error(422, "User with same email address already exists", nil)
}
cmd := m.CreateTempUserCommand{}
@@ -39,7 +38,7 @@ func SignUp(c *middleware.Context, form dtos.SignUpForm) Response {
cmd.RemoteAddr = c.Req.RemoteAddr
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to create signup", err)
return Error(500, "Failed to create signup", err)
}
bus.Publish(&events.SignUpStarted{
@@ -49,12 +48,12 @@ func SignUp(c *middleware.Context, form dtos.SignUpForm) Response {
metrics.M_Api_User_SignUpStarted.Inc()
return Json(200, util.DynMap{"status": "SignUpCreated"})
return JSON(200, util.DynMap{"status": "SignUpCreated"})
}
func SignUpStep2(c *middleware.Context, form dtos.SignUpStep2Form) Response {
func SignUpStep2(c *m.ReqContext, form dtos.SignUpStep2Form) Response {
if !setting.AllowUserSignUp {
return ApiError(401, "User signup is disabled", nil)
return Error(401, "User signup is disabled", nil)
}
createUserCmd := m.CreateUserCommand{
@@ -76,12 +75,12 @@ func SignUpStep2(c *middleware.Context, form dtos.SignUpStep2Form) Response {
// check if user exists
existing := m.GetUserByLoginQuery{LoginOrEmail: form.Email}
if err := bus.Dispatch(&existing); err == nil {
return ApiError(401, "User with same email address already exists", nil)
return Error(401, "User with same email address already exists", nil)
}
// dispatch create command
if err := bus.Dispatch(&createUserCmd); err != nil {
return ApiError(500, "Failed to create user", err)
return Error(500, "Failed to create user", err)
}
// publish signup event
@@ -99,7 +98,7 @@ func SignUpStep2(c *middleware.Context, form dtos.SignUpStep2Form) Response {
// check for pending invites
invitesQuery := m.GetTempUsersQuery{Email: form.Email, Status: m.TmpUserInvitePending}
if err := bus.Dispatch(&invitesQuery); err != nil {
return ApiError(500, "Failed to query database for invites", err)
return Error(500, "Failed to query database for invites", err)
}
apiResponse := util.DynMap{"message": "User sign up completed successfully", "code": "redirect-to-landing-page"}
@@ -113,7 +112,7 @@ func SignUpStep2(c *middleware.Context, form dtos.SignUpStep2Form) Response {
loginUserWithUser(user, c)
metrics.M_Api_User_SignUpCompleted.Inc()
return Json(200, apiResponse)
return JSON(200, apiResponse)
}
func verifyUserSignUpEmail(email string, code string) (bool, Response) {
@@ -121,14 +120,14 @@ func verifyUserSignUpEmail(email string, code string) (bool, Response) {
if err := bus.Dispatch(&query); err != nil {
if err == m.ErrTempUserNotFound {
return false, ApiError(404, "Invalid email verification code", nil)
return false, Error(404, "Invalid email verification code", nil)
}
return false, ApiError(500, "Failed to read temp user", err)
return false, Error(500, "Failed to read temp user", err)
}
tempUser := query.Result
if tempUser.Email != email {
return false, ApiError(404, "Email verification code does not match email", nil)
return false, Error(404, "Email verification code does not match email", nil)
}
return true, nil
+9 -10
View File
@@ -2,39 +2,38 @@ package api
import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
)
func StarDashboard(c *middleware.Context) Response {
func StarDashboard(c *m.ReqContext) Response {
if !c.IsSignedIn {
return ApiError(412, "You need to sign in to star dashboards", nil)
return Error(412, "You need to sign in to star dashboards", nil)
}
cmd := m.StarDashboardCommand{UserId: c.UserId, DashboardId: c.ParamsInt64(":id")}
if cmd.DashboardId <= 0 {
return ApiError(400, "Missing dashboard id", nil)
return Error(400, "Missing dashboard id", nil)
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to star dashboard", err)
return Error(500, "Failed to star dashboard", err)
}
return ApiSuccess("Dashboard starred!")
return Success("Dashboard starred!")
}
func UnstarDashboard(c *middleware.Context) Response {
func UnstarDashboard(c *m.ReqContext) Response {
cmd := m.UnstarDashboardCommand{UserId: c.UserId, DashboardId: c.ParamsInt64(":id")}
if cmd.DashboardId <= 0 {
return ApiError(400, "Missing dashboard id", nil)
return Error(400, "Missing dashboard id", nil)
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to unstar dashboard", err)
return Error(500, "Failed to unstar dashboard", err)
}
return ApiSuccess("Dashboard unstarred")
return Success("Dashboard unstarred")
}
+1 -1
View File
@@ -48,7 +48,7 @@ type StaticOptions struct {
// Expires defines which user-defined function to use for producing a HTTP Expires Header
// https://developers.google.com/speed/docs/insights/LeverageBrowserCaching
AddHeaders func(ctx *macaron.Context)
// FileSystem is the interface for supporting any implmentation of file system.
// FileSystem is the interface for supporting any implementation of file system.
FileSystem http.FileSystem
}
+19 -20
View File
@@ -3,54 +3,53 @@ package api
import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util"
)
// POST /api/teams
func CreateTeam(c *middleware.Context, cmd m.CreateTeamCommand) Response {
func CreateTeam(c *m.ReqContext, cmd m.CreateTeamCommand) Response {
cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrTeamNameTaken {
return ApiError(409, "Team name taken", err)
return Error(409, "Team name taken", err)
}
return ApiError(500, "Failed to create Team", err)
return Error(500, "Failed to create Team", err)
}
return Json(200, &util.DynMap{
return JSON(200, &util.DynMap{
"teamId": cmd.Result.Id,
"message": "Team created",
})
}
// PUT /api/teams/:teamId
func UpdateTeam(c *middleware.Context, cmd m.UpdateTeamCommand) Response {
func UpdateTeam(c *m.ReqContext, cmd m.UpdateTeamCommand) Response {
cmd.OrgId = c.OrgId
cmd.Id = c.ParamsInt64(":teamId")
if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrTeamNameTaken {
return ApiError(400, "Team name taken", err)
return Error(400, "Team name taken", err)
}
return ApiError(500, "Failed to update Team", err)
return Error(500, "Failed to update Team", err)
}
return ApiSuccess("Team updated")
return Success("Team updated")
}
// DELETE /api/teams/:teamId
func DeleteTeamById(c *middleware.Context) Response {
func DeleteTeamByID(c *m.ReqContext) Response {
if err := bus.Dispatch(&m.DeleteTeamCommand{OrgId: c.OrgId, Id: c.ParamsInt64(":teamId")}); err != nil {
if err == m.ErrTeamNotFound {
return ApiError(404, "Failed to delete Team. ID not found", nil)
return Error(404, "Failed to delete Team. ID not found", nil)
}
return ApiError(500, "Failed to update Team", err)
return Error(500, "Failed to update Team", err)
}
return ApiSuccess("Team deleted")
return Success("Team deleted")
}
// GET /api/teams/search
func SearchTeams(c *middleware.Context) Response {
func SearchTeams(c *m.ReqContext) Response {
perPage := c.QueryInt("perpage")
if perPage <= 0 {
perPage = 1000
@@ -69,7 +68,7 @@ func SearchTeams(c *middleware.Context) Response {
}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to search Teams", err)
return Error(500, "Failed to search Teams", err)
}
for _, team := range query.Result.Teams {
@@ -79,20 +78,20 @@ func SearchTeams(c *middleware.Context) Response {
query.Result.Page = page
query.Result.PerPage = perPage
return Json(200, query.Result)
return JSON(200, query.Result)
}
// GET /api/teams/:teamId
func GetTeamById(c *middleware.Context) Response {
func GetTeamByID(c *m.ReqContext) Response {
query := m.GetTeamByIdQuery{OrgId: c.OrgId, Id: c.ParamsInt64(":teamId")}
if err := bus.Dispatch(&query); err != nil {
if err == m.ErrTeamNotFound {
return ApiError(404, "Team not found", err)
return Error(404, "Team not found", err)
}
return ApiError(500, "Failed to get Team", err)
return Error(500, "Failed to get Team", err)
}
return Json(200, &query.Result)
return JSON(200, &query.Result)
}
+13 -14
View File
@@ -3,60 +3,59 @@ package api
import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util"
)
// GET /api/teams/:teamId/members
func GetTeamMembers(c *middleware.Context) Response {
func GetTeamMembers(c *m.ReqContext) Response {
query := m.GetTeamMembersQuery{OrgId: c.OrgId, TeamId: c.ParamsInt64(":teamId")}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to get Team Members", err)
return Error(500, "Failed to get Team Members", err)
}
for _, member := range query.Result {
member.AvatarUrl = dtos.GetGravatarUrl(member.Email)
}
return Json(200, query.Result)
return JSON(200, query.Result)
}
// POST /api/teams/:teamId/members
func AddTeamMember(c *middleware.Context, cmd m.AddTeamMemberCommand) Response {
func AddTeamMember(c *m.ReqContext, cmd m.AddTeamMemberCommand) Response {
cmd.TeamId = c.ParamsInt64(":teamId")
cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrTeamNotFound {
return ApiError(404, "Team not found", nil)
return Error(404, "Team not found", nil)
}
if err == m.ErrTeamMemberAlreadyAdded {
return ApiError(400, "User is already added to this team", nil)
return Error(400, "User is already added to this team", nil)
}
return ApiError(500, "Failed to add Member to Team", err)
return Error(500, "Failed to add Member to Team", err)
}
return Json(200, &util.DynMap{
return JSON(200, &util.DynMap{
"message": "Member added to Team",
})
}
// DELETE /api/teams/:teamId/members/:userId
func RemoveTeamMember(c *middleware.Context) Response {
func RemoveTeamMember(c *m.ReqContext) Response {
if err := bus.Dispatch(&m.RemoveTeamMemberCommand{OrgId: c.OrgId, TeamId: c.ParamsInt64(":teamId"), UserId: c.ParamsInt64(":userId")}); err != nil {
if err == m.ErrTeamNotFound {
return ApiError(404, "Team not found", nil)
return Error(404, "Team not found", nil)
}
if err == m.ErrTeamMemberNotFound {
return ApiError(404, "Team member not found", nil)
return Error(404, "Team member not found", nil)
}
return ApiError(500, "Failed to remove Member from Team", err)
return Error(500, "Failed to remove Member from Team", err)
}
return ApiSuccess("Team Member removed")
return Success("Team Member removed")
}
+66 -67
View File
@@ -3,43 +3,42 @@ package api
import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
// GET /api/user (current authenticated user)
func GetSignedInUser(c *middleware.Context) Response {
func GetSignedInUser(c *m.ReqContext) Response {
return getUserUserProfile(c.UserId)
}
// GET /api/users/:id
func GetUserById(c *middleware.Context) Response {
func GetUserByID(c *m.ReqContext) Response {
return getUserUserProfile(c.ParamsInt64(":id"))
}
func getUserUserProfile(userId int64) Response {
query := m.GetUserProfileQuery{UserId: userId}
func getUserUserProfile(userID int64) Response {
query := m.GetUserProfileQuery{UserId: userID}
if err := bus.Dispatch(&query); err != nil {
if err == m.ErrUserNotFound {
return ApiError(404, m.ErrUserNotFound.Error(), nil)
return Error(404, m.ErrUserNotFound.Error(), nil)
}
return ApiError(500, "Failed to get user", err)
return Error(500, "Failed to get user", err)
}
return Json(200, query.Result)
return JSON(200, query.Result)
}
// GET /api/users/lookup
func GetUserByLoginOrEmail(c *middleware.Context) Response {
func GetUserByLoginOrEmail(c *m.ReqContext) Response {
query := m.GetUserByLoginQuery{LoginOrEmail: c.Query("loginOrEmail")}
if err := bus.Dispatch(&query); err != nil {
if err == m.ErrUserNotFound {
return ApiError(404, m.ErrUserNotFound.Error(), nil)
return Error(404, m.ErrUserNotFound.Error(), nil)
}
return ApiError(500, "Failed to get user", err)
return Error(500, "Failed to get user", err)
}
user := query.Result
result := m.UserProfileDTO{
@@ -51,17 +50,17 @@ func GetUserByLoginOrEmail(c *middleware.Context) Response {
IsGrafanaAdmin: user.IsAdmin,
OrgId: user.OrgId,
}
return Json(200, &result)
return JSON(200, &result)
}
// POST /api/user
func UpdateSignedInUser(c *middleware.Context, cmd m.UpdateUserCommand) Response {
func UpdateSignedInUser(c *m.ReqContext, cmd m.UpdateUserCommand) Response {
if setting.AuthProxyEnabled {
if setting.AuthProxyHeaderProperty == "email" && cmd.Email != c.Email {
return ApiError(400, "Not allowed to change email when auth proxy is using email property", nil)
return Error(400, "Not allowed to change email when auth proxy is using email property", nil)
}
if setting.AuthProxyHeaderProperty == "username" && cmd.Login != c.Login {
return ApiError(400, "Not allowed to change username when auth proxy is using username property", nil)
return Error(400, "Not allowed to change username when auth proxy is using username property", nil)
}
}
cmd.UserId = c.UserId
@@ -69,66 +68,66 @@ func UpdateSignedInUser(c *middleware.Context, cmd m.UpdateUserCommand) Response
}
// POST /api/users/:id
func UpdateUser(c *middleware.Context, cmd m.UpdateUserCommand) Response {
func UpdateUser(c *m.ReqContext, cmd m.UpdateUserCommand) Response {
cmd.UserId = c.ParamsInt64(":id")
return handleUpdateUser(cmd)
}
//POST /api/users/:id/using/:orgId
func UpdateUserActiveOrg(c *middleware.Context) Response {
userId := c.ParamsInt64(":id")
orgId := c.ParamsInt64(":orgId")
func UpdateUserActiveOrg(c *m.ReqContext) Response {
userID := c.ParamsInt64(":id")
orgID := c.ParamsInt64(":orgId")
if !validateUsingOrg(userId, orgId) {
return ApiError(401, "Not a valid organization", nil)
if !validateUsingOrg(userID, orgID) {
return Error(401, "Not a valid organization", nil)
}
cmd := m.SetUsingOrgCommand{UserId: userId, OrgId: orgId}
cmd := m.SetUsingOrgCommand{UserId: userID, OrgId: orgID}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to change active organization", err)
return Error(500, "Failed to change active organization", err)
}
return ApiSuccess("Active organization changed")
return Success("Active organization changed")
}
func handleUpdateUser(cmd m.UpdateUserCommand) Response {
if len(cmd.Login) == 0 {
cmd.Login = cmd.Email
if len(cmd.Login) == 0 {
return ApiError(400, "Validation error, need to specify either username or email", nil)
return Error(400, "Validation error, need to specify either username or email", nil)
}
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to update user", err)
return Error(500, "Failed to update user", err)
}
return ApiSuccess("User updated")
return Success("User updated")
}
// GET /api/user/orgs
func GetSignedInUserOrgList(c *middleware.Context) Response {
func GetSignedInUserOrgList(c *m.ReqContext) Response {
return getUserOrgList(c.UserId)
}
// GET /api/user/:id/orgs
func GetUserOrgList(c *middleware.Context) Response {
func GetUserOrgList(c *m.ReqContext) Response {
return getUserOrgList(c.ParamsInt64(":id"))
}
func getUserOrgList(userId int64) Response {
query := m.GetUserOrgListQuery{UserId: userId}
func getUserOrgList(userID int64) Response {
query := m.GetUserOrgListQuery{UserId: userID}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to get user organizations", err)
return Error(500, "Failed to get user organizations", err)
}
return Json(200, query.Result)
return JSON(200, query.Result)
}
func validateUsingOrg(userId int64, orgId int64) bool {
query := m.GetUserOrgListQuery{UserId: userId}
func validateUsingOrg(userID int64, orgID int64) bool {
query := m.GetUserOrgListQuery{UserId: userID}
if err := bus.Dispatch(&query); err != nil {
return false
@@ -137,7 +136,7 @@ func validateUsingOrg(userId int64, orgId int64) bool {
// validate that the org id in the list
valid := false
for _, other := range query.Result {
if other.OrgId == orgId {
if other.OrgId == orgID {
valid = true
}
}
@@ -146,31 +145,31 @@ func validateUsingOrg(userId int64, orgId int64) bool {
}
// POST /api/user/using/:id
func UserSetUsingOrg(c *middleware.Context) Response {
orgId := c.ParamsInt64(":id")
func UserSetUsingOrg(c *m.ReqContext) Response {
orgID := c.ParamsInt64(":id")
if !validateUsingOrg(c.UserId, orgId) {
return ApiError(401, "Not a valid organization", nil)
if !validateUsingOrg(c.UserId, orgID) {
return Error(401, "Not a valid organization", nil)
}
cmd := m.SetUsingOrgCommand{UserId: c.UserId, OrgId: orgId}
cmd := m.SetUsingOrgCommand{UserId: c.UserId, OrgId: orgID}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to change active organization", err)
return Error(500, "Failed to change active organization", err)
}
return ApiSuccess("Active organization changed")
return Success("Active organization changed")
}
// GET /profile/switch-org/:id
func ChangeActiveOrgAndRedirectToHome(c *middleware.Context) {
orgId := c.ParamsInt64(":id")
func ChangeActiveOrgAndRedirectToHome(c *m.ReqContext) {
orgID := c.ParamsInt64(":id")
if !validateUsingOrg(c.UserId, orgId) {
if !validateUsingOrg(c.UserId, orgID) {
NotFoundHandler(c)
}
cmd := m.SetUsingOrgCommand{UserId: c.UserId, OrgId: orgId}
cmd := m.SetUsingOrgCommand{UserId: c.UserId, OrgId: orgID}
if err := bus.Dispatch(&cmd); err != nil {
NotFoundHandler(c)
@@ -179,58 +178,58 @@ func ChangeActiveOrgAndRedirectToHome(c *middleware.Context) {
c.Redirect(setting.AppSubUrl + "/")
}
func ChangeUserPassword(c *middleware.Context, cmd m.ChangeUserPasswordCommand) Response {
func ChangeUserPassword(c *m.ReqContext, cmd m.ChangeUserPasswordCommand) Response {
if setting.LdapEnabled || setting.AuthProxyEnabled {
return ApiError(400, "Not allowed to change password when LDAP or Auth Proxy is enabled", nil)
return Error(400, "Not allowed to change password when LDAP or Auth Proxy is enabled", nil)
}
userQuery := m.GetUserByIdQuery{Id: c.UserId}
if err := bus.Dispatch(&userQuery); err != nil {
return ApiError(500, "Could not read user from database", err)
return Error(500, "Could not read user from database", err)
}
passwordHashed := util.EncodePassword(cmd.OldPassword, userQuery.Result.Salt)
if passwordHashed != userQuery.Result.Password {
return ApiError(401, "Invalid old password", nil)
return Error(401, "Invalid old password", nil)
}
password := m.Password(cmd.NewPassword)
if password.IsWeak() {
return ApiError(400, "New password is too short", nil)
return Error(400, "New password is too short", nil)
}
cmd.UserId = c.UserId
cmd.NewPassword = util.EncodePassword(cmd.NewPassword, userQuery.Result.Salt)
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to change user password", err)
return Error(500, "Failed to change user password", err)
}
return ApiSuccess("User password changed")
return Success("User password changed")
}
// GET /api/users
func SearchUsers(c *middleware.Context) Response {
func SearchUsers(c *m.ReqContext) Response {
query, err := searchUser(c)
if err != nil {
return ApiError(500, "Failed to fetch users", err)
return Error(500, "Failed to fetch users", err)
}
return Json(200, query.Result.Users)
return JSON(200, query.Result.Users)
}
// GET /api/users/search
func SearchUsersWithPaging(c *middleware.Context) Response {
func SearchUsersWithPaging(c *m.ReqContext) Response {
query, err := searchUser(c)
if err != nil {
return ApiError(500, "Failed to fetch users", err)
return Error(500, "Failed to fetch users", err)
}
return Json(200, query.Result)
return JSON(200, query.Result)
}
func searchUser(c *middleware.Context) (*m.SearchUsersQuery, error) {
func searchUser(c *m.ReqContext) (*m.SearchUsersQuery, error) {
perPage := c.QueryInt("perpage")
if perPage <= 0 {
perPage = 1000
@@ -258,7 +257,7 @@ func searchUser(c *middleware.Context) (*m.SearchUsersQuery, error) {
return query, nil
}
func SetHelpFlag(c *middleware.Context) Response {
func SetHelpFlag(c *m.ReqContext) Response {
flag := c.ParamsInt64(":id")
bitmask := &c.HelpFlags1
@@ -270,21 +269,21 @@ func SetHelpFlag(c *middleware.Context) Response {
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to update help flag", err)
return Error(500, "Failed to update help flag", err)
}
return Json(200, &util.DynMap{"message": "Help flag set", "helpFlags1": cmd.HelpFlags1})
return JSON(200, &util.DynMap{"message": "Help flag set", "helpFlags1": cmd.HelpFlags1})
}
func ClearHelpFlags(c *middleware.Context) Response {
func ClearHelpFlags(c *m.ReqContext) Response {
cmd := m.SetUserHelpFlagCommand{
UserId: c.UserId,
HelpFlags1: m.HelpFlags1(0),
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to update help flag", err)
return Error(500, "Failed to update help flag", err)
}
return Json(200, &util.DynMap{"message": "Help flag set", "helpFlags1": cmd.HelpFlags1})
return JSON(200, &util.DynMap{"message": "Help flag set", "helpFlags1": cmd.HelpFlags1})
}
@@ -33,7 +33,7 @@ func validateInput(c CommandLine, pluginFolder string) error {
fileInfo, err := os.Stat(pluginsDir)
if err != nil {
if err = os.MkdirAll(pluginsDir, os.ModePerm); err != nil {
return errors.New(fmt.Sprintf("pluginsDir (%s) is not a directory", pluginsDir))
return fmt.Errorf("pluginsDir (%s) is not a writable directory", pluginsDir)
}
return nil
}
+1 -1
View File
@@ -24,7 +24,7 @@ var validateLsCommand = func(pluginDir string) error {
return fmt.Errorf("error: %s", err)
}
if pluginDirInfo.IsDir() == false {
if !pluginDirInfo.IsDir() {
return errors.New("plugin path is not a directory")
}
@@ -3,12 +3,11 @@ package commands
import (
"errors"
"fmt"
m "github.com/grafana/grafana/pkg/cmd/grafana-cli/models"
services "github.com/grafana/grafana/pkg/cmd/grafana-cli/services"
"strings"
services "github.com/grafana/grafana/pkg/cmd/grafana-cli/services"
)
var getPluginss func(path string) []m.InstalledPlugin = services.GetLocalPlugins
var removePlugin func(pluginPath, id string) error = services.RemoveInstalledPlugin
func removeCommand(c CommandLine) error {
@@ -53,8 +53,7 @@ func upgradeAllCommand(c CommandLine) error {
for _, p := range pluginsToUpgrade {
logger.Infof("Updating %v \n", p.Id)
var err error
err = s.RemoveInstalledPlugin(pluginsDir, p.Id)
err := s.RemoveInstalledPlugin(pluginsDir, p.Id)
if err != nil {
return err
}
+1 -1
View File
@@ -42,7 +42,7 @@ func Init(version string, skipTLSVerify bool) {
}
HttpClient = http.Client{
Timeout: time.Duration(10 * time.Second),
Timeout: 10 * time.Second,
Transport: tr,
}
}
-1
View File
@@ -33,7 +33,6 @@ import (
var version = "5.0.0"
var commit = "NA"
var buildstamp string
var build_date string
var configFile = flag.String("config", "", "path to config file")
var homePath = flag.String("homepath", "", "path to grafana install/home path, defaults to working directory")
+3 -3
View File
@@ -49,7 +49,7 @@ type GrafanaServerImpl struct {
childRoutines *errgroup.Group
log log.Logger
httpServer *api.HttpServer
httpServer *api.HTTPServer
}
func (g *GrafanaServerImpl) Start() error {
@@ -111,7 +111,7 @@ func (g *GrafanaServerImpl) initLogging() {
})
if err != nil {
g.log.Error(err.Error())
fmt.Fprintf(os.Stderr, "Failed to start grafana. error: %s\n", err.Error())
os.Exit(1)
}
@@ -120,7 +120,7 @@ func (g *GrafanaServerImpl) initLogging() {
}
func (g *GrafanaServerImpl) startHttpServer() error {
g.httpServer = api.NewHttpServer()
g.httpServer = api.NewHTTPServer()
err := g.httpServer.Start(g.context)
+2 -2
View File
@@ -33,7 +33,7 @@ func New(orgId int64, name string) KeyGenResult {
jsonString, _ := json.Marshal(jsonKey)
result.ClientSecret = base64.StdEncoding.EncodeToString([]byte(jsonString))
result.ClientSecret = base64.StdEncoding.EncodeToString(jsonString)
return result
}
@@ -44,7 +44,7 @@ func Decode(keyString string) (*ApiKeyJson, error) {
}
var keyObj ApiKeyJson
err = json.Unmarshal([]byte(jsonString), &keyObj)
err = json.Unmarshal(jsonString, &keyObj)
if err != nil {
return nil, ErrInvalidApiKey
}
-4
View File
@@ -6,7 +6,6 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/models"
diff "github.com/yudai/gojsondiff"
deltaFormatter "github.com/yudai/gojsondiff/formatter"
@@ -15,11 +14,8 @@ import (
var (
// ErrUnsupportedDiffType occurs when an invalid diff type is used.
ErrUnsupportedDiffType = errors.New("dashdiff: unsupported diff type")
// ErrNilDiff occurs when two compared interfaces are identical.
ErrNilDiff = errors.New("dashdiff: diff is nil")
diffLogger = log.New("dashdiffs")
)
type DiffType int
+1 -1
View File
@@ -22,7 +22,7 @@ const (
)
var (
// changeTypeToSymbol is used for populating the terminating characer in
// changeTypeToSymbol is used for populating the terminating character in
// the diff
changeTypeToSymbol = map[ChangeType]string{
ChangeNil: "",
-7
View File
@@ -585,7 +585,6 @@ func (v *Value) Null() error {
switch v.data.(type) {
case nil:
valid = v.exists // Valid only if j also exists, since other values could possibly also be nil
break
}
if valid {
@@ -607,7 +606,6 @@ func (v *Value) Array() ([]*Value, error) {
switch v.data.(type) {
case []interface{}:
valid = true
break
}
// Unsure if this is a good way to use slices, it's probably not
@@ -638,7 +636,6 @@ func (v *Value) Number() (json.Number, error) {
switch v.data.(type) {
case json.Number:
valid = true
break
}
if valid {
@@ -687,7 +684,6 @@ func (v *Value) Boolean() (bool, error) {
switch v.data.(type) {
case bool:
valid = true
break
}
if valid {
@@ -709,7 +705,6 @@ func (v *Value) Object() (*Object, error) {
switch v.data.(type) {
case map[string]interface{}:
valid = true
break
}
if valid {
@@ -746,7 +741,6 @@ func (v *Value) ObjectArray() ([]*Object, error) {
switch v.data.(type) {
case []interface{}:
valid = true
break
}
// Unsure if this is a good way to use slices, it's probably not
@@ -782,7 +776,6 @@ func (v *Value) String() (string, error) {
switch v.data.(type) {
case string:
valid = true
break
}
if valid {
+6 -6
View File
@@ -21,7 +21,7 @@ func NewAssert(t *testing.T) *Assert {
}
func (assert *Assert) True(value bool, message string) {
if value == false {
if !value {
log.Panicln("Assert: ", message)
}
}
@@ -76,10 +76,10 @@ func TestFirst(t *testing.T) {
assert.True(s == "fallback", "must get string return fallback")
s, err = j.GetString("name")
assert.True(s == "anton" && err == nil, "name shoud match")
assert.True(s == "anton" && err == nil, "name should match")
s, err = j.GetString("address", "street")
assert.True(s == "Street 42" && err == nil, "street shoud match")
assert.True(s == "Street 42" && err == nil, "street should match")
//log.Println("s: ", s.String())
_, err = j.GetNumber("age")
@@ -119,13 +119,13 @@ func TestFirst(t *testing.T) {
assert.True(s == "" && err != nil, "nonexistent string fail")
b, err := j.GetBoolean("true")
assert.True(b == true && err == nil, "bool true test")
assert.True(b && err == nil, "bool true test")
b, err = j.GetBoolean("false")
assert.True(b == false && err == nil, "bool false test")
assert.True(!b && err == nil, "bool false test")
b, err = j.GetBoolean("invalid_field")
assert.True(b == false && err != nil, "bool invalid test")
assert.True(!b && err != nil, "bool invalid test")
list, err := j.GetValueArray("list")
assert.True(list != nil && err == nil, "list should be an array")
@@ -225,7 +225,7 @@ func (a *Auth) SignRequest(req *http.Request) {
)
decodedKey, _ := base64.StdEncoding.DecodeString(a.Key)
sha256 := hmac.New(sha256.New, []byte(decodedKey))
sha256 := hmac.New(sha256.New, decodedKey)
sha256.Write([]byte(strToSign))
signature := base64.StdEncoding.EncodeToString(sha256.Sum(nil))
+1 -1
View File
@@ -50,7 +50,7 @@ func (f *Float) UnmarshalJSON(data []byte) error {
}
switch x := v.(type) {
case float64:
f.Float64 = float64(x)
f.Float64 = x
case map[string]interface{}:
err = json.Unmarshal(data, &f.NullFloat64)
case nil:
+3 -1
View File
@@ -72,7 +72,9 @@ func RenderToPng(params *RenderOpts) (string, error) {
localDomain = setting.HttpAddr
}
url := fmt.Sprintf("%s://%s:%s/%s", setting.Protocol, localDomain, setting.HttpPort, params.Path)
// &render=1 signals to the legacy redirect layer to
// avoid redirect these requests.
url := fmt.Sprintf("%s://%s:%s/%s&render=1", setting.Protocol, localDomain, setting.HttpPort, params.Path)
binPath, _ := filepath.Abs(filepath.Join(setting.PhantomDir, executable))
scriptPath, _ := filepath.Abs(filepath.Join(setting.PhantomDir, "render.js"))
+1 -4
View File
@@ -99,10 +99,7 @@ func (w *FileLogWriter) StartLogger() error {
return err
}
w.mw.SetFd(fd)
if err = w.initFd(); err != nil {
return err
}
return nil
return w.initFd()
}
func (w *FileLogWriter) docheck(size int) {
+9 -10
View File
@@ -8,23 +8,22 @@ import (
)
var (
ErrInvalidCredentials = errors.New("Invalid Username or Password")
ErrTooManyLoginAttempts = errors.New("Too many consecutive incorrect login attempts for user. Login for user temporarily blocked")
ErrEmailNotAllowed = errors.New("Required email domain not fulfilled")
ErrInvalidCredentials = errors.New("Invalid Username or Password")
ErrNoEmail = errors.New("Login provider didn't return an email address")
ErrProviderDeniedRequest = errors.New("Login provider denied login request")
ErrSignUpNotAllowed = errors.New("Signup is not allowed for this adapter")
ErrTooManyLoginAttempts = errors.New("Too many consecutive incorrect login attempts for user. Login for user temporarily blocked")
ErrUsersQuotaReached = errors.New("Users quota reached")
ErrGettingUserQuota = errors.New("Error getting user quota")
)
type LoginUserQuery struct {
Username string
Password string
User *m.User
IpAddress string
}
func Init() {
bus.AddHandler("auth", AuthenticateUser)
loadLdapConfig()
}
func AuthenticateUser(query *LoginUserQuery) error {
func AuthenticateUser(query *m.LoginUserQuery) error {
if err := validateLoginAttempts(query.Username); err != nil {
return err
}
+5 -5
View File
@@ -151,7 +151,7 @@ func TestAuthenticateUser(t *testing.T) {
}
type authScenarioContext struct {
loginUserQuery *LoginUserQuery
loginUserQuery *m.LoginUserQuery
grafanaLoginWasCalled bool
ldapLoginWasCalled bool
loginAttemptValidationWasCalled bool
@@ -161,14 +161,14 @@ type authScenarioContext struct {
type authScenarioFunc func(sc *authScenarioContext)
func mockLoginUsingGrafanaDB(err error, sc *authScenarioContext) {
loginUsingGrafanaDB = func(query *LoginUserQuery) error {
loginUsingGrafanaDB = func(query *m.LoginUserQuery) error {
sc.grafanaLoginWasCalled = true
return err
}
}
func mockLoginUsingLdap(enabled bool, err error, sc *authScenarioContext) {
loginUsingLdap = func(query *LoginUserQuery) (bool, error) {
loginUsingLdap = func(query *m.LoginUserQuery) (bool, error) {
sc.ldapLoginWasCalled = true
return enabled, err
}
@@ -182,7 +182,7 @@ func mockLoginAttemptValidation(err error, sc *authScenarioContext) {
}
func mockSaveInvalidLoginAttempt(sc *authScenarioContext) {
saveInvalidLoginAttempt = func(query *LoginUserQuery) {
saveInvalidLoginAttempt = func(query *m.LoginUserQuery) {
sc.saveInvalidLoginAttemptWasCalled = true
}
}
@@ -195,7 +195,7 @@ func authScenario(desc string, fn authScenarioFunc) {
origSaveInvalidLoginAttempt := saveInvalidLoginAttempt
sc := &authScenarioContext{
loginUserQuery: &LoginUserQuery{
loginUserQuery: &m.LoginUserQuery{
Username: "user",
Password: "pwd",
IpAddress: "192.168.1.1:56433",
+1 -1
View File
@@ -34,7 +34,7 @@ var validateLoginAttempts = func(username string) error {
return nil
}
var saveInvalidLoginAttempt = func(query *LoginUserQuery) {
var saveInvalidLoginAttempt = func(query *m.LoginUserQuery) {
if setting.DisableBruteForceLoginProtection {
return
}
@@ -50,7 +50,7 @@ func TestLoginAttemptsValidation(t *testing.T) {
return nil
})
saveInvalidLoginAttempt(&LoginUserQuery{
saveInvalidLoginAttempt(&m.LoginUserQuery{
Username: "user",
Password: "pwd",
IpAddress: "192.168.1.1:56433",
@@ -103,7 +103,7 @@ func TestLoginAttemptsValidation(t *testing.T) {
return nil
})
saveInvalidLoginAttempt(&LoginUserQuery{
saveInvalidLoginAttempt(&m.LoginUserQuery{
Username: "user",
Password: "pwd",
IpAddress: "192.168.1.1:56433",
+184
View File
@@ -0,0 +1,184 @@
package login
import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/log"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/quota"
)
func init() {
bus.AddHandler("auth", UpsertUser)
}
func UpsertUser(cmd *m.UpsertUserCommand) error {
extUser := cmd.ExternalUser
userQuery := &m.GetUserByAuthInfoQuery{
AuthModule: extUser.AuthModule,
AuthId: extUser.AuthId,
UserId: extUser.UserId,
Email: extUser.Email,
Login: extUser.Login,
}
err := bus.Dispatch(userQuery)
if err != m.ErrUserNotFound && err != nil {
return err
}
if err != nil {
if !cmd.SignupAllowed {
log.Warn("Not allowing %s login, user not found in internal user database and allow signup = false", extUser.AuthModule)
return ErrInvalidCredentials
}
limitReached, err := quota.QuotaReached(cmd.ReqContext, "user")
if err != nil {
log.Warn("Error getting user quota", "err", err)
return ErrGettingUserQuota
}
if limitReached {
return ErrUsersQuotaReached
}
cmd.Result, err = createUser(extUser)
if err != nil {
return err
}
if extUser.AuthModule != "" && extUser.AuthId != "" {
cmd2 := &m.SetAuthInfoCommand{
UserId: cmd.Result.Id,
AuthModule: extUser.AuthModule,
AuthId: extUser.AuthId,
}
if err := bus.Dispatch(cmd2); err != nil {
return err
}
}
} else {
cmd.Result = userQuery.Result
err = updateUser(cmd.Result, extUser)
if err != nil {
return err
}
}
return syncOrgRoles(cmd.Result, extUser)
}
func createUser(extUser *m.ExternalUserInfo) (*m.User, error) {
cmd := &m.CreateUserCommand{
Login: extUser.Login,
Email: extUser.Email,
Name: extUser.Name,
SkipOrgSetup: len(extUser.OrgRoles) > 0,
}
if err := bus.Dispatch(cmd); err != nil {
return nil, err
}
return &cmd.Result, nil
}
func updateUser(user *m.User, extUser *m.ExternalUserInfo) error {
// sync user info
updateCmd := &m.UpdateUserCommand{
UserId: user.Id,
}
needsUpdate := false
if extUser.Login != "" && extUser.Login != user.Login {
updateCmd.Login = extUser.Login
user.Login = extUser.Login
needsUpdate = true
}
if extUser.Email != "" && extUser.Email != user.Email {
updateCmd.Email = extUser.Email
user.Email = extUser.Email
needsUpdate = true
}
if extUser.Name != "" && extUser.Name != user.Name {
updateCmd.Name = extUser.Name
user.Name = extUser.Name
needsUpdate = true
}
if !needsUpdate {
return nil
}
log.Debug("Syncing user info", "id", user.Id, "update", updateCmd)
return bus.Dispatch(updateCmd)
}
func syncOrgRoles(user *m.User, extUser *m.ExternalUserInfo) error {
// don't sync org roles if none are specified
if len(extUser.OrgRoles) == 0 {
return nil
}
orgsQuery := &m.GetUserOrgListQuery{UserId: user.Id}
if err := bus.Dispatch(orgsQuery); err != nil {
return err
}
handledOrgIds := map[int64]bool{}
deleteOrgIds := []int64{}
// update existing org roles
for _, org := range orgsQuery.Result {
handledOrgIds[org.OrgId] = true
if extUser.OrgRoles[org.OrgId] == "" {
deleteOrgIds = append(deleteOrgIds, org.OrgId)
} else if extUser.OrgRoles[org.OrgId] != org.Role {
// update role
cmd := &m.UpdateOrgUserCommand{OrgId: org.OrgId, UserId: user.Id, Role: extUser.OrgRoles[org.OrgId]}
if err := bus.Dispatch(cmd); err != nil {
return err
}
}
}
// add any new org roles
for orgId, orgRole := range extUser.OrgRoles {
if _, exists := handledOrgIds[orgId]; exists {
continue
}
// add role
cmd := &m.AddOrgUserCommand{UserId: user.Id, Role: orgRole, OrgId: orgId}
err := bus.Dispatch(cmd)
if err != nil && err != m.ErrOrgNotFound {
return err
}
}
// delete any removed org roles
for _, orgId := range deleteOrgIds {
cmd := &m.RemoveOrgUserCommand{OrgId: orgId, UserId: user.Id}
if err := bus.Dispatch(cmd); err != nil {
return err
}
}
// update user's default org if needed
if _, ok := extUser.OrgRoles[user.OrgId]; !ok {
for orgId := range extUser.OrgRoles {
user.OrgId = orgId
break
}
return bus.Dispatch(&m.SetUsingOrgCommand{
UserId: user.Id,
OrgId: user.OrgId,
})
}
return nil
}
+1 -1
View File
@@ -17,7 +17,7 @@ var validatePassword = func(providedPassword string, userPassword string, userSa
return nil
}
var loginUsingGrafanaDB = func(query *LoginUserQuery) error {
var loginUsingGrafanaDB = func(query *m.LoginUserQuery) error {
userQuery := m.GetUserByLoginQuery{LoginOrEmail: query.Username}
if err := bus.Dispatch(&userQuery); err != nil {
+2 -2
View File
@@ -66,7 +66,7 @@ func TestGrafanaLogin(t *testing.T) {
}
type grafanaLoginScenarioContext struct {
loginUserQuery *LoginUserQuery
loginUserQuery *m.LoginUserQuery
validatePasswordCalled bool
}
@@ -77,7 +77,7 @@ func grafanaLoginScenario(desc string, fn grafanaLoginScenarioFunc) {
origValidatePassword := validatePassword
sc := &grafanaLoginScenarioContext{
loginUserQuery: &LoginUserQuery{
loginUserQuery: &m.LoginUserQuery{
Username: "user",
Password: "pwd",
IpAddress: "192.168.1.1:56433",
+74 -180
View File
@@ -24,10 +24,9 @@ type ILdapConn interface {
}
type ILdapAuther interface {
Login(query *LoginUserQuery) error
SyncSignedInUser(signedInUser *m.SignedInUser) error
GetGrafanaUserFor(ldapUser *LdapUserInfo) (*m.User, error)
SyncOrgRoles(user *m.User, ldapUser *LdapUserInfo) error
Login(query *m.LoginUserQuery) error
SyncUser(query *m.LoginUserQuery) error
GetGrafanaUserFor(ctx *m.ReqContext, ldapUser *LdapUserInfo) (*m.User, error)
}
type ldapAuther struct {
@@ -89,7 +88,8 @@ func (a *ldapAuther) Dial() error {
return err
}
func (a *ldapAuther) Login(query *LoginUserQuery) error {
func (a *ldapAuther) Login(query *m.LoginUserQuery) error {
// connect to ldap server
if err := a.Dial(); err != nil {
return err
}
@@ -101,206 +101,105 @@ func (a *ldapAuther) Login(query *LoginUserQuery) error {
}
// find user entry & attributes
if ldapUser, err := a.searchForUser(query.Username); err != nil {
ldapUser, err := a.searchForUser(query.Username)
if err != nil {
return err
} else {
a.log.Debug("Ldap User found", "info", spew.Sdump(ldapUser))
}
// check if a second user bind is needed
if a.requireSecondBind {
if err := a.secondBind(ldapUser, query.Password); err != nil {
return err
}
}
a.log.Debug("Ldap User found", "info", spew.Sdump(ldapUser))
if grafanaUser, err := a.GetGrafanaUserFor(ldapUser); err != nil {
// check if a second user bind is needed
if a.requireSecondBind {
err = a.secondBind(ldapUser, query.Password)
if err != nil {
return err
} else {
if syncErr := a.syncInfoAndOrgRoles(grafanaUser, ldapUser); syncErr != nil {
return syncErr
}
query.User = grafanaUser
return nil
}
}
grafanaUser, err := a.GetGrafanaUserFor(query.ReqContext, ldapUser)
if err != nil {
return err
}
query.User = grafanaUser
return nil
}
func (a *ldapAuther) SyncSignedInUser(signedInUser *m.SignedInUser) error {
grafanaUser := m.User{
Id: signedInUser.UserId,
Login: signedInUser.Login,
Email: signedInUser.Email,
Name: signedInUser.Name,
}
if err := a.Dial(); err != nil {
func (a *ldapAuther) SyncUser(query *m.LoginUserQuery) error {
// connect to ldap server
err := a.Dial()
if err != nil {
return err
}
defer a.conn.Close()
if err := a.serverBind(); err != nil {
err = a.serverBind()
if err != nil {
return err
}
if ldapUser, err := a.searchForUser(signedInUser.Login); err != nil {
// find user entry & attributes
ldapUser, err := a.searchForUser(query.Username)
if err != nil {
a.log.Error("Failed searching for user in ldap", "error", err)
return err
} else {
if err := a.syncInfoAndOrgRoles(&grafanaUser, ldapUser); err != nil {
return err
}
a.log.Debug("Ldap User found", "info", spew.Sdump(ldapUser))
grafanaUser, err := a.GetGrafanaUserFor(query.ReqContext, ldapUser)
if err != nil {
return err
}
query.User = grafanaUser
return nil
}
func (a *ldapAuther) GetGrafanaUserFor(ctx *m.ReqContext, ldapUser *LdapUserInfo) (*m.User, error) {
extUser := &m.ExternalUserInfo{
AuthModule: "ldap",
AuthId: ldapUser.DN,
Name: fmt.Sprintf("%s %s", ldapUser.FirstName, ldapUser.LastName),
Login: ldapUser.Username,
Email: ldapUser.Email,
OrgRoles: map[int64]m.RoleType{},
}
for _, group := range a.server.LdapGroups {
// only use the first match for each org
if extUser.OrgRoles[group.OrgId] != "" {
continue
}
a.log.Debug("Got Ldap User Info", "user", spew.Sdump(ldapUser))
if ldapUser.isMemberOf(group.GroupDN) {
extUser.OrgRoles[group.OrgId] = group.OrgRole
}
}
return nil
}
// Sync info for ldap user and grafana user
func (a *ldapAuther) syncInfoAndOrgRoles(user *m.User, ldapUser *LdapUserInfo) error {
// sync user details
if err := a.syncUserInfo(user, ldapUser); err != nil {
return err
}
// sync org roles
if err := a.SyncOrgRoles(user, ldapUser); err != nil {
return err
}
return nil
}
func (a *ldapAuther) GetGrafanaUserFor(ldapUser *LdapUserInfo) (*m.User, error) {
// validate that the user has access
// if there are no ldap group mappings access is true
// otherwise a single group must match
access := len(a.server.LdapGroups) == 0
for _, ldapGroup := range a.server.LdapGroups {
if ldapUser.isMemberOf(ldapGroup.GroupDN) {
access = true
break
}
}
if !access {
a.log.Info("Ldap Auth: user does not belong in any of the specified ldap groups", "username", ldapUser.Username, "groups", ldapUser.MemberOf)
if len(a.server.LdapGroups) > 0 && len(extUser.OrgRoles) < 1 {
a.log.Info(
"Ldap Auth: user does not belong in any of the specified ldap groups",
"username", ldapUser.Username,
"groups", ldapUser.MemberOf)
return nil, ErrInvalidCredentials
}
// get user from grafana db
userQuery := m.GetUserByLoginQuery{LoginOrEmail: ldapUser.Username}
if err := bus.Dispatch(&userQuery); err != nil {
if err == m.ErrUserNotFound && setting.LdapAllowSignup {
return a.createGrafanaUser(ldapUser)
} else if err == m.ErrUserNotFound {
a.log.Warn("Not allowing LDAP login, user not found in internal user database, and ldap allow signup = false")
return nil, ErrInvalidCredentials
} else {
return nil, err
}
// add/update user in grafana
userQuery := &m.UpsertUserCommand{
ReqContext: ctx,
ExternalUser: extUser,
SignupAllowed: setting.LdapAllowSignup,
}
return userQuery.Result, nil
}
func (a *ldapAuther) createGrafanaUser(ldapUser *LdapUserInfo) (*m.User, error) {
cmd := m.CreateUserCommand{
Login: ldapUser.Username,
Email: ldapUser.Email,
Name: fmt.Sprintf("%s %s", ldapUser.FirstName, ldapUser.LastName),
}
if err := bus.Dispatch(&cmd); err != nil {
err := bus.Dispatch(userQuery)
if err != nil {
return nil, err
}
return &cmd.Result, nil
}
func (a *ldapAuther) syncUserInfo(user *m.User, ldapUser *LdapUserInfo) error {
var name = fmt.Sprintf("%s %s", ldapUser.FirstName, ldapUser.LastName)
if user.Email == ldapUser.Email && user.Name == name {
return nil
}
a.log.Debug("Syncing user info", "username", ldapUser.Username)
updateCmd := m.UpdateUserCommand{}
updateCmd.UserId = user.Id
updateCmd.Login = user.Login
updateCmd.Email = ldapUser.Email
updateCmd.Name = fmt.Sprintf("%s %s", ldapUser.FirstName, ldapUser.LastName)
return bus.Dispatch(&updateCmd)
}
func (a *ldapAuther) SyncOrgRoles(user *m.User, ldapUser *LdapUserInfo) error {
if len(a.server.LdapGroups) == 0 {
a.log.Warn("No group mappings defined")
return nil
}
orgsQuery := m.GetUserOrgListQuery{UserId: user.Id}
if err := bus.Dispatch(&orgsQuery); err != nil {
return err
}
handledOrgIds := map[int64]bool{}
// update or remove org roles
for _, org := range orgsQuery.Result {
match := false
handledOrgIds[org.OrgId] = true
for _, group := range a.server.LdapGroups {
if org.OrgId != group.OrgId {
continue
}
if ldapUser.isMemberOf(group.GroupDN) {
match = true
if org.Role != group.OrgRole {
// update role
cmd := m.UpdateOrgUserCommand{OrgId: org.OrgId, UserId: user.Id, Role: group.OrgRole}
if err := bus.Dispatch(&cmd); err != nil {
return err
}
}
// ignore subsequent ldap group mapping matches
break
}
}
// remove role if no mappings match
if !match {
cmd := m.RemoveOrgUserCommand{OrgId: org.OrgId, UserId: user.Id}
if err := bus.Dispatch(&cmd); err != nil {
return err
}
}
}
// add missing org roles
for _, group := range a.server.LdapGroups {
if !ldapUser.isMemberOf(group.GroupDN) {
continue
}
if _, exists := handledOrgIds[group.OrgId]; exists {
continue
}
// add role
cmd := m.AddOrgUserCommand{UserId: user.Id, Role: group.OrgRole, OrgId: group.OrgId}
err := bus.Dispatch(&cmd)
if err != nil && err != m.ErrOrgNotFound {
return err
}
// mark this group has handled so we do not process it again
handledOrgIds[group.OrgId] = true
}
return nil
return userQuery.Result, nil
}
func (a *ldapAuther) serverBind() error {
@@ -404,7 +303,6 @@ func (a *ldapAuther) searchForUser(username string) (*LdapUserInfo, error) {
var groupSearchResult *ldap.SearchResult
for _, groupSearchBase := range a.server.GroupSearchBaseDNs {
var filter_replace string
if a.server.GroupSearchFilterUserAttribute == "" {
filter_replace = getLdapAttr(a.server.Attr.Username, searchResult)
} else {
@@ -475,7 +373,3 @@ func getLdapAttrArray(name string, result *ldap.SearchResult) []string {
}
return []string{}
}
func createUserFromLdapInfo() error {
return nil
}
+2 -1
View File
@@ -1,10 +1,11 @@
package login
import (
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
)
var loginUsingLdap = func(query *LoginUserQuery) (bool, error) {
var loginUsingLdap = func(query *m.LoginUserQuery) (bool, error) {
if !setting.LdapEnabled {
return false, nil
}
+6 -10
View File
@@ -79,7 +79,7 @@ func TestLdapLogin(t *testing.T) {
ldapLoginScenario("When login", func(sc *ldapLoginScenarioContext) {
sc.withLoginResult(false)
enabled, err := loginUsingLdap(&LoginUserQuery{
enabled, err := loginUsingLdap(&m.LoginUserQuery{
Username: "user",
Password: "pwd",
})
@@ -117,7 +117,7 @@ type mockLdapAuther struct {
loginCalled bool
}
func (a *mockLdapAuther) Login(query *LoginUserQuery) error {
func (a *mockLdapAuther) Login(query *m.LoginUserQuery) error {
a.loginCalled = true
if !a.validLogin {
@@ -127,20 +127,16 @@ func (a *mockLdapAuther) Login(query *LoginUserQuery) error {
return nil
}
func (a *mockLdapAuther) SyncSignedInUser(signedInUser *m.SignedInUser) error {
func (a *mockLdapAuther) SyncUser(query *m.LoginUserQuery) error {
return nil
}
func (a *mockLdapAuther) GetGrafanaUserFor(ldapUser *LdapUserInfo) (*m.User, error) {
func (a *mockLdapAuther) GetGrafanaUserFor(ctx *m.ReqContext, ldapUser *LdapUserInfo) (*m.User, error) {
return nil, nil
}
func (a *mockLdapAuther) SyncOrgRoles(user *m.User, ldapUser *LdapUserInfo) error {
return nil
}
type ldapLoginScenarioContext struct {
loginUserQuery *LoginUserQuery
loginUserQuery *m.LoginUserQuery
ldapAuthenticatorMock *mockLdapAuther
}
@@ -151,7 +147,7 @@ func ldapLoginScenario(desc string, fn ldapLoginScenarioFunc) {
origNewLdapAuthenticator := NewLdapAuthenticator
sc := &ldapLoginScenarioContext{
loginUserQuery: &LoginUserQuery{
loginUserQuery: &m.LoginUserQuery{
Username: "user",
Password: "pwd",
IpAddress: "192.168.1.1:56433",
+62 -31
View File
@@ -18,7 +18,7 @@ func TestLdapAuther(t *testing.T) {
ldapAuther := NewLdapAuthenticator(&LdapServerConf{
LdapGroups: []*LdapGroupToOrgRole{{}},
})
_, err := ldapAuther.GetGrafanaUserFor(&LdapUserInfo{})
_, err := ldapAuther.GetGrafanaUserFor(nil, &LdapUserInfo{})
So(err, ShouldEqual, ErrInvalidCredentials)
})
@@ -34,7 +34,7 @@ func TestLdapAuther(t *testing.T) {
sc.userQueryReturns(user1)
result, err := ldapAuther.GetGrafanaUserFor(&LdapUserInfo{})
result, err := ldapAuther.GetGrafanaUserFor(nil, &LdapUserInfo{})
So(err, ShouldBeNil)
So(result, ShouldEqual, user1)
})
@@ -48,7 +48,7 @@ func TestLdapAuther(t *testing.T) {
sc.userQueryReturns(user1)
result, err := ldapAuther.GetGrafanaUserFor(&LdapUserInfo{MemberOf: []string{"cn=users"}})
result, err := ldapAuther.GetGrafanaUserFor(nil, &LdapUserInfo{MemberOf: []string{"cn=users"}})
So(err, ShouldBeNil)
So(result, ShouldEqual, user1)
})
@@ -64,7 +64,8 @@ func TestLdapAuther(t *testing.T) {
sc.userQueryReturns(nil)
result, err := ldapAuther.GetGrafanaUserFor(&LdapUserInfo{
result, err := ldapAuther.GetGrafanaUserFor(nil, &LdapUserInfo{
DN: "torkelo",
Username: "torkelo",
Email: "my@email.com",
MemberOf: []string{"cn=editor"},
@@ -72,11 +73,6 @@ func TestLdapAuther(t *testing.T) {
So(err, ShouldBeNil)
Convey("Should create new user", func() {
So(sc.createUserCmd.Login, ShouldEqual, "torkelo")
So(sc.createUserCmd.Email, ShouldEqual, "my@email.com")
})
Convey("Should return new user", func() {
So(result.Login, ShouldEqual, "torkelo")
})
@@ -95,7 +91,7 @@ func TestLdapAuther(t *testing.T) {
})
sc.userOrgsQueryReturns([]*m.UserOrgDTO{})
err := ldapAuther.SyncOrgRoles(&m.User{}, &LdapUserInfo{
_, err := ldapAuther.GetGrafanaUserFor(nil, &LdapUserInfo{
MemberOf: []string{"cn=users"},
})
@@ -114,7 +110,7 @@ func TestLdapAuther(t *testing.T) {
})
sc.userOrgsQueryReturns([]*m.UserOrgDTO{{OrgId: 1, Role: m.ROLE_EDITOR}})
err := ldapAuther.SyncOrgRoles(&m.User{}, &LdapUserInfo{
_, err := ldapAuther.GetGrafanaUserFor(nil, &LdapUserInfo{
MemberOf: []string{"cn=users"},
})
@@ -122,24 +118,29 @@ func TestLdapAuther(t *testing.T) {
So(err, ShouldBeNil)
So(sc.updateOrgUserCmd, ShouldNotBeNil)
So(sc.updateOrgUserCmd.Role, ShouldEqual, m.ROLE_ADMIN)
So(sc.setUsingOrgCmd.OrgId, ShouldEqual, 1)
})
})
ldapAutherScenario("given current org role is removed in ldap", func(sc *scenarioContext) {
ldapAuther := NewLdapAuthenticator(&LdapServerConf{
LdapGroups: []*LdapGroupToOrgRole{
{GroupDN: "cn=users", OrgId: 1, OrgRole: "Admin"},
{GroupDN: "cn=users", OrgId: 2, OrgRole: "Admin"},
},
})
sc.userOrgsQueryReturns([]*m.UserOrgDTO{{OrgId: 1, Role: m.ROLE_EDITOR}})
err := ldapAuther.SyncOrgRoles(&m.User{}, &LdapUserInfo{
MemberOf: []string{"cn=other"},
sc.userOrgsQueryReturns([]*m.UserOrgDTO{
{OrgId: 1, Role: m.ROLE_EDITOR},
{OrgId: 2, Role: m.ROLE_EDITOR},
})
_, err := ldapAuther.GetGrafanaUserFor(nil, &LdapUserInfo{
MemberOf: []string{"cn=users"},
})
Convey("Should remove org role", func() {
So(err, ShouldBeNil)
So(sc.removeOrgUserCmd, ShouldNotBeNil)
So(sc.setUsingOrgCmd.OrgId, ShouldEqual, 2)
})
})
@@ -152,7 +153,7 @@ func TestLdapAuther(t *testing.T) {
})
sc.userOrgsQueryReturns([]*m.UserOrgDTO{{OrgId: 1, Role: m.ROLE_EDITOR}})
err := ldapAuther.SyncOrgRoles(&m.User{}, &LdapUserInfo{
_, err := ldapAuther.GetGrafanaUserFor(nil, &LdapUserInfo{
MemberOf: []string{"cn=users"},
})
@@ -160,6 +161,7 @@ func TestLdapAuther(t *testing.T) {
So(err, ShouldBeNil)
So(sc.removeOrgUserCmd, ShouldBeNil)
So(sc.updateOrgUserCmd, ShouldNotBeNil)
So(sc.setUsingOrgCmd.OrgId, ShouldEqual, 1)
})
})
@@ -172,13 +174,14 @@ func TestLdapAuther(t *testing.T) {
})
sc.userOrgsQueryReturns([]*m.UserOrgDTO{{OrgId: 1, Role: m.ROLE_ADMIN}})
err := ldapAuther.SyncOrgRoles(&m.User{}, &LdapUserInfo{
_, err := ldapAuther.GetGrafanaUserFor(nil, &LdapUserInfo{
MemberOf: []string{"cn=admins"},
})
Convey("Should take first match, and ignore subsequent matches", func() {
So(err, ShouldBeNil)
So(sc.updateOrgUserCmd, ShouldBeNil)
So(sc.setUsingOrgCmd.OrgId, ShouldEqual, 1)
})
})
@@ -191,19 +194,20 @@ func TestLdapAuther(t *testing.T) {
})
sc.userOrgsQueryReturns([]*m.UserOrgDTO{})
err := ldapAuther.SyncOrgRoles(&m.User{}, &LdapUserInfo{
_, err := ldapAuther.GetGrafanaUserFor(nil, &LdapUserInfo{
MemberOf: []string{"cn=admins"},
})
Convey("Should take first match, and ignore subsequent matches", func() {
So(err, ShouldBeNil)
So(sc.addOrgUserCmd.Role, ShouldEqual, m.ROLE_ADMIN)
So(sc.setUsingOrgCmd.OrgId, ShouldEqual, 1)
})
})
})
Convey("When calling SyncSignedInUser", t, func() {
Convey("When calling SyncUser", t, func() {
mockLdapConnection := &mockLdapConn{}
ldapAuther := NewLdapAuthenticator(
@@ -243,17 +247,20 @@ func TestLdapAuther(t *testing.T) {
ldapAutherScenario("When ldapUser found call syncInfo and orgRoles", func(sc *scenarioContext) {
// arrange
signedInUser := &m.SignedInUser{
Email: "roel@test.net",
UserId: 1,
Name: "Roel Gerrits",
Login: "roelgerrits",
query := &m.LoginUserQuery{
Username: "roelgerrits",
}
sc.userQueryReturns(&m.User{
Id: 1,
Email: "roel@test.net",
Name: "Roel Gerrits",
Login: "roelgerrits",
})
sc.userOrgsQueryReturns([]*m.UserOrgDTO{})
// act
syncErrResult := ldapAuther.SyncSignedInUser(signedInUser)
syncErrResult := ldapAuther.SyncUser(query)
// assert
So(dialCalled, ShouldBeTrue)
@@ -299,6 +306,19 @@ func ldapAutherScenario(desc string, fn scenarioFunc) {
sc := &scenarioContext{}
bus.AddHandler("test", UpsertUser)
bus.AddHandler("test", func(cmd *m.GetUserByAuthInfoQuery) error {
sc.getUserByAuthInfoQuery = cmd
sc.getUserByAuthInfoQuery.Result = &m.User{Login: cmd.Login}
return nil
})
bus.AddHandler("test", func(cmd *m.GetUserOrgListQuery) error {
sc.getUserOrgListQuery = cmd
return nil
})
bus.AddHandler("test", func(cmd *m.CreateUserCommand) error {
sc.createUserCmd = cmd
sc.createUserCmd.Result = m.User{Login: cmd.Login}
@@ -325,20 +345,28 @@ func ldapAutherScenario(desc string, fn scenarioFunc) {
return nil
})
bus.AddHandler("test", func(cmd *m.SetUsingOrgCommand) error {
sc.setUsingOrgCmd = cmd
return nil
})
fn(sc)
})
}
type scenarioContext struct {
createUserCmd *m.CreateUserCommand
addOrgUserCmd *m.AddOrgUserCommand
updateOrgUserCmd *m.UpdateOrgUserCommand
removeOrgUserCmd *m.RemoveOrgUserCommand
updateUserCmd *m.UpdateUserCommand
getUserByAuthInfoQuery *m.GetUserByAuthInfoQuery
getUserOrgListQuery *m.GetUserOrgListQuery
createUserCmd *m.CreateUserCommand
addOrgUserCmd *m.AddOrgUserCommand
updateOrgUserCmd *m.UpdateOrgUserCommand
removeOrgUserCmd *m.RemoveOrgUserCommand
updateUserCmd *m.UpdateUserCommand
setUsingOrgCmd *m.SetUsingOrgCommand
}
func (sc *scenarioContext) userQueryReturns(user *m.User) {
bus.AddHandler("test", func(query *m.GetUserByLoginQuery) error {
bus.AddHandler("test", func(query *m.GetUserByAuthInfoQuery) error {
if user == nil {
return m.ErrUserNotFound
} else {
@@ -346,6 +374,9 @@ func (sc *scenarioContext) userQueryReturns(user *m.User) {
return nil
}
})
bus.AddHandler("test", func(query *m.SetAuthInfoCommand) error {
return nil
})
}
func (sc *scenarioContext) userOrgsQueryReturns(orgs []*m.UserOrgDTO) {
+1 -5
View File
@@ -295,11 +295,7 @@ func writeMetric(buf *bufio.Writer, m model.Metric, mf *dto.MetricFamily) error
}
}
if err = addExtentionConventionForRollups(buf, mf, m); err != nil {
return err
}
return nil
return addExtentionConventionForRollups(buf, mf, m)
}
func addExtentionConventionForRollups(buf *bufio.Writer, mf *dto.MetricFamily, m model.Metric) error {
+26 -18
View File
@@ -54,6 +54,7 @@ var (
M_Alerting_Active_Alerts prometheus.Gauge
M_StatTotal_Dashboards prometheus.Gauge
M_StatTotal_Users prometheus.Gauge
M_StatActive_Users prometheus.Gauge
M_StatTotal_Orgs prometheus.Gauge
M_StatTotal_Playlists prometheus.Gauge
M_Grafana_Version *prometheus.GaugeVec
@@ -253,6 +254,12 @@ func init() {
Namespace: exporterName,
})
M_StatActive_Users = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "stat_active_users",
Help: "number of active users",
Namespace: exporterName,
})
M_StatTotal_Orgs = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "stat_total_orgs",
Help: "total amount of orgs",
@@ -270,7 +277,6 @@ func init() {
Help: "Information about the Grafana",
Namespace: exporterName,
}, []string{"version"})
}
func initMetricVars(settings *MetricSettings) {
@@ -305,6 +311,7 @@ func initMetricVars(settings *MetricSettings) {
M_Alerting_Active_Alerts,
M_StatTotal_Dashboards,
M_StatTotal_Users,
M_StatActive_Users,
M_StatTotal_Orgs,
M_StatTotal_Playlists,
M_Grafana_Version)
@@ -315,35 +322,36 @@ func initMetricVars(settings *MetricSettings) {
func instrumentationLoop(settings *MetricSettings) chan struct{} {
M_Instance_Start.Inc()
// set the total stats gauges before we publishing metrics
updateTotalStats()
onceEveryDayTick := time.NewTicker(time.Hour * 24)
secondTicker := time.NewTicker(time.Second * time.Duration(settings.IntervalSeconds))
everyMinuteTicker := time.NewTicker(time.Minute)
defer onceEveryDayTick.Stop()
defer everyMinuteTicker.Stop()
for {
select {
case <-onceEveryDayTick.C:
sendUsageStats()
case <-secondTicker.C:
case <-everyMinuteTicker.C:
updateTotalStats()
}
}
}
var metricPublishCounter int64 = 0
func updateTotalStats() {
metricPublishCounter++
if metricPublishCounter == 1 || metricPublishCounter%10 == 0 {
statsQuery := models.GetSystemStatsQuery{}
if err := bus.Dispatch(&statsQuery); err != nil {
metricsLogger.Error("Failed to get system stats", "error", err)
return
}
M_StatTotal_Dashboards.Set(float64(statsQuery.Result.Dashboards))
M_StatTotal_Users.Set(float64(statsQuery.Result.Users))
M_StatTotal_Playlists.Set(float64(statsQuery.Result.Playlists))
M_StatTotal_Orgs.Set(float64(statsQuery.Result.Orgs))
statsQuery := models.GetSystemStatsQuery{}
if err := bus.Dispatch(&statsQuery); err != nil {
metricsLogger.Error("Failed to get system stats", "error", err)
return
}
M_StatTotal_Dashboards.Set(float64(statsQuery.Result.Dashboards))
M_StatTotal_Users.Set(float64(statsQuery.Result.Users))
M_StatActive_Users.Set(float64(statsQuery.Result.ActiveUsers))
M_StatTotal_Playlists.Set(float64(statsQuery.Result.Playlists))
M_StatTotal_Orgs.Set(float64(statsQuery.Result.Orgs))
}
func sendUsageStats() {
@@ -403,6 +411,6 @@ func sendUsageStats() {
out, _ := json.MarshalIndent(report, "", " ")
data := bytes.NewBuffer(out)
client := http.Client{Timeout: time.Duration(5 * time.Second)}
client := http.Client{Timeout: 5 * time.Second}
go client.Post("https://stats.grafana.org/grafana-usage-report", "application/json", data)
}
+10 -9
View File
@@ -7,6 +7,7 @@ import (
"gopkg.in/macaron.v1"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/session"
"github.com/grafana/grafana/pkg/setting"
)
@@ -15,17 +16,17 @@ type AuthOptions struct {
ReqSignedIn bool
}
func getRequestUserId(c *Context) int64 {
userId := c.Session.Get(SESS_KEY_USERID)
func getRequestUserId(c *m.ReqContext) int64 {
userID := c.Session.Get(session.SESS_KEY_USERID)
if userId != nil {
return userId.(int64)
if userID != nil {
return userID.(int64)
}
return 0
}
func getApiKey(c *Context) string {
func getApiKey(c *m.ReqContext) string {
header := c.Req.Header.Get("Authorization")
parts := strings.SplitN(header, " ", 2)
if len(parts) == 2 && parts[0] == "Bearer" {
@@ -36,7 +37,7 @@ func getApiKey(c *Context) string {
return ""
}
func accessForbidden(c *Context) {
func accessForbidden(c *m.ReqContext) {
if c.IsApiRequest() {
c.JsonApiErr(403, "Permission denied", nil)
return
@@ -45,7 +46,7 @@ func accessForbidden(c *Context) {
c.Redirect(setting.AppSubUrl + "/")
}
func notAuthorized(c *Context) {
func notAuthorized(c *m.ReqContext) {
if c.IsApiRequest() {
c.JsonApiErr(401, "Unauthorized", nil)
return
@@ -57,7 +58,7 @@ func notAuthorized(c *Context) {
}
func RoleAuth(roles ...m.RoleType) macaron.Handler {
return func(c *Context) {
return func(c *m.ReqContext) {
ok := false
for _, role := range roles {
if role == c.OrgRole {
@@ -72,7 +73,7 @@ func RoleAuth(roles ...m.RoleType) macaron.Handler {
}
func Auth(options *AuthOptions) macaron.Handler {
return func(c *Context) {
return func(c *m.ReqContext) {
if !c.IsSignedIn && options.ReqSignedIn && !c.AllowAnonymous {
notAuthorized(c)
return
+133 -101
View File
@@ -1,8 +1,9 @@
package middleware
import (
"errors"
"fmt"
"net"
"net/mail"
"strings"
"time"
@@ -10,10 +11,13 @@ import (
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/login"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/session"
"github.com/grafana/grafana/pkg/setting"
)
func initContextWithAuthProxy(ctx *Context, orgId int64) bool {
var AUTH_PROXY_SESSION_VAR = "authProxyHeaderValue"
func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool {
if !setting.AuthProxyEnabled {
return false
}
@@ -24,148 +28,176 @@ func initContextWithAuthProxy(ctx *Context, orgId int64) bool {
}
// if auth proxy ip(s) defined, check if request comes from one of those
if err := checkAuthenticationProxy(ctx, proxyHeaderValue); err != nil {
if err := checkAuthenticationProxy(ctx.Req.RemoteAddr, proxyHeaderValue); err != nil {
ctx.Handle(407, "Proxy authentication required", err)
return true
}
query := getSignedInUserQueryForProxyAuth(proxyHeaderValue)
query.OrgId = orgId
if err := bus.Dispatch(query); err != nil {
if err != m.ErrUserNotFound {
ctx.Handle(500, "Failed to find user specified in auth proxy header", err)
// initialize session
if err := ctx.Session.Start(ctx.Context); err != nil {
log.Error(3, "Failed to start session", err)
return false
}
query := &m.GetSignedInUserQuery{OrgId: orgID}
// if this session has already been authenticated by authProxy just load the user
sessProxyValue := ctx.Session.Get(AUTH_PROXY_SESSION_VAR)
if sessProxyValue != nil && sessProxyValue.(string) == proxyHeaderValue && getRequestUserId(ctx) > 0 {
// if we're using ldap, sync user periodically
if setting.LdapEnabled {
syncQuery := &m.LoginUserQuery{
ReqContext: ctx,
Username: proxyHeaderValue,
}
if err := syncGrafanaUserWithLdapUser(syncQuery); err != nil {
if err == login.ErrInvalidCredentials {
ctx.Handle(500, "Unable to authenticate user", err)
return false
}
ctx.Handle(500, "Failed to sync user", err)
return false
}
}
query.UserId = getRequestUserId(ctx)
// if we're using ldap, pass authproxy login name to ldap user sync
} else if setting.LdapEnabled {
ctx.Session.Delete(session.SESS_KEY_LASTLDAPSYNC)
syncQuery := &m.LoginUserQuery{
ReqContext: ctx,
Username: proxyHeaderValue,
}
if err := syncGrafanaUserWithLdapUser(syncQuery); err != nil {
if err == login.ErrInvalidCredentials {
ctx.Handle(500, "Unable to authenticate user", err)
return false
}
ctx.Handle(500, "Failed to sync user", err)
return false
}
if syncQuery.User == nil {
ctx.Handle(500, "Failed to sync user", nil)
return false
}
query.UserId = syncQuery.User.Id
// no ldap, just use the info we have
} else {
extUser := &m.ExternalUserInfo{
AuthModule: "authproxy",
AuthId: proxyHeaderValue,
}
if setting.AuthProxyHeaderProperty == "username" {
extUser.Login = proxyHeaderValue
// only set Email if it can be parsed as an email address
emailAddr, emailErr := mail.ParseAddress(proxyHeaderValue)
if emailErr == nil {
extUser.Email = emailAddr.Address
}
} else if setting.AuthProxyHeaderProperty == "email" {
extUser.Email = proxyHeaderValue
extUser.Login = proxyHeaderValue
} else {
ctx.Handle(500, "Auth proxy header property invalid", nil)
return true
}
if setting.AuthProxyAutoSignUp {
cmd := getCreateUserCommandForProxyAuth(proxyHeaderValue)
if setting.LdapEnabled {
cmd.SkipOrgSetup = true
}
if err := bus.Dispatch(cmd); err != nil {
ctx.Handle(500, "Failed to create user specified in auth proxy header", err)
return true
}
query = &m.GetSignedInUserQuery{UserId: cmd.Result.Id, OrgId: orgId}
if err := bus.Dispatch(query); err != nil {
ctx.Handle(500, "Failed find user after creation", err)
return true
}
} else {
return false
// add/update user in grafana
cmd := &m.UpsertUserCommand{
ReqContext: ctx,
ExternalUser: extUser,
SignupAllowed: setting.AuthProxyAutoSignUp,
}
err := bus.Dispatch(cmd)
if err != nil {
ctx.Handle(500, "Failed to login as user specified in auth proxy header", err)
return true
}
query.UserId = cmd.Result.Id
}
// initialize session
if err := ctx.Session.Start(ctx); err != nil {
log.Error(3, "Failed to start session", err)
return false
if err := bus.Dispatch(query); err != nil {
ctx.Handle(500, "Failed to find user", err)
return true
}
// Make sure that we cannot share a session between different users!
if getRequestUserId(ctx) > 0 && getRequestUserId(ctx) != query.Result.UserId {
// remove session
if err := ctx.Session.Destory(ctx); err != nil {
if err := ctx.Session.Destory(ctx.Context); err != nil {
log.Error(3, "Failed to destroy session, err")
}
// initialize a new session
if err := ctx.Session.Start(ctx); err != nil {
if err := ctx.Session.Start(ctx.Context); err != nil {
log.Error(3, "Failed to start session", err)
}
}
// When ldap is enabled, sync userinfo and org roles
if err := syncGrafanaUserWithLdapUser(ctx, query); err != nil {
if err == login.ErrInvalidCredentials {
ctx.Handle(500, "Unable to authenticate user", err)
return false
}
ctx.Handle(500, "Failed to sync user", err)
return false
}
ctx.Session.Set(AUTH_PROXY_SESSION_VAR, proxyHeaderValue)
ctx.SignedInUser = query.Result
ctx.IsSignedIn = true
ctx.Session.Set(SESS_KEY_USERID, ctx.UserId)
ctx.Session.Set(session.SESS_KEY_USERID, ctx.UserId)
return true
}
var syncGrafanaUserWithLdapUser = func(ctx *Context, query *m.GetSignedInUserQuery) error {
if setting.LdapEnabled {
expireEpoch := time.Now().Add(time.Duration(-setting.AuthProxyLdapSyncTtl) * time.Minute).Unix()
var syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error {
expireEpoch := time.Now().Add(time.Duration(-setting.AuthProxyLdapSyncTtl) * time.Minute).Unix()
var lastLdapSync int64
if lastLdapSyncInSession := ctx.Session.Get(SESS_KEY_LASTLDAPSYNC); lastLdapSyncInSession != nil {
lastLdapSync = lastLdapSyncInSession.(int64)
var lastLdapSync int64
if lastLdapSyncInSession := query.ReqContext.Session.Get(session.SESS_KEY_LASTLDAPSYNC); lastLdapSyncInSession != nil {
lastLdapSync = lastLdapSyncInSession.(int64)
}
if lastLdapSync < expireEpoch {
ldapCfg := login.LdapCfg
if len(ldapCfg.Servers) < 1 {
return fmt.Errorf("No LDAP servers available")
}
if lastLdapSync < expireEpoch {
ldapCfg := login.LdapCfg
for _, server := range ldapCfg.Servers {
author := login.NewLdapAuthenticator(server)
if err := author.SyncSignedInUser(query.Result); err != nil {
return err
}
for _, server := range ldapCfg.Servers {
author := login.NewLdapAuthenticator(server)
if err := author.SyncUser(query); err != nil {
return err
}
ctx.Session.Set(SESS_KEY_LASTLDAPSYNC, time.Now().Unix())
}
query.ReqContext.Session.Set(session.SESS_KEY_LASTLDAPSYNC, time.Now().Unix())
}
return nil
}
func checkAuthenticationProxy(ctx *Context, proxyHeaderValue string) error {
if len(strings.TrimSpace(setting.AuthProxyWhitelist)) > 0 {
proxies := strings.Split(setting.AuthProxyWhitelist, ",")
remoteAddrSplit := strings.Split(ctx.Req.RemoteAddr, ":")
sourceIP := remoteAddrSplit[0]
func checkAuthenticationProxy(remoteAddr string, proxyHeaderValue string) error {
if len(strings.TrimSpace(setting.AuthProxyWhitelist)) == 0 {
return nil
}
found := false
for _, proxyIP := range proxies {
if sourceIP == strings.TrimSpace(proxyIP) {
found = true
break
}
}
proxies := strings.Split(setting.AuthProxyWhitelist, ",")
sourceIP, _, err := net.SplitHostPort(remoteAddr)
if err != nil {
return err
}
if !found {
msg := fmt.Sprintf("Request for user (%s) is not from the authentication proxy", proxyHeaderValue)
err := errors.New(msg)
return err
// Compare allowed IP addresses to actual address
for _, proxyIP := range proxies {
if sourceIP == strings.TrimSpace(proxyIP) {
return nil
}
}
return nil
}
func getSignedInUserQueryForProxyAuth(headerVal string) *m.GetSignedInUserQuery {
query := m.GetSignedInUserQuery{}
if setting.AuthProxyHeaderProperty == "username" {
query.Login = headerVal
} else if setting.AuthProxyHeaderProperty == "email" {
query.Email = headerVal
} else {
panic("Auth proxy header property invalid")
}
return &query
}
func getCreateUserCommandForProxyAuth(headerVal string) *m.CreateUserCommand {
cmd := m.CreateUserCommand{}
if setting.AuthProxyHeaderProperty == "username" {
cmd.Login = headerVal
cmd.Email = headerVal
} else if setting.AuthProxyHeaderProperty == "email" {
cmd.Email = headerVal
cmd.Login = headerVal
} else {
panic("Auth proxy header property invalid")
}
return &cmd
return fmt.Errorf("Request for user (%s) from %s is not from the authentication proxy", proxyHeaderValue, sourceIP)
}
+50 -36
View File
@@ -6,8 +6,10 @@ import (
"github.com/grafana/grafana/pkg/login"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/session"
"github.com/grafana/grafana/pkg/setting"
. "github.com/smartystreets/goconvey/convey"
"gopkg.in/macaron.v1"
)
func TestAuthProxyWithLdapEnabled(t *testing.T) {
@@ -24,73 +26,88 @@ func TestAuthProxyWithLdapEnabled(t *testing.T) {
return &mockLdapAuther
}
signedInUser := m.SignedInUser{}
query := m.GetSignedInUserQuery{Result: &signedInUser}
Convey("When session variable lastLdapSync not set, call syncSignedInUser and set lastLdapSync", func() {
Convey("When user logs in, call SyncUser", func() {
// arrange
session := mockSession{}
ctx := Context{Session: &session}
So(session.Get(SESS_KEY_LASTLDAPSYNC), ShouldBeNil)
sess := newMockSession()
ctx := m.ReqContext{Session: &sess}
So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldBeNil)
// act
syncGrafanaUserWithLdapUser(&ctx, &query)
syncGrafanaUserWithLdapUser(&m.LoginUserQuery{
ReqContext: &ctx,
Username: "test",
})
// assert
So(mockLdapAuther.syncSignedInUserCalled, ShouldBeTrue)
So(session.Get(SESS_KEY_LASTLDAPSYNC), ShouldBeGreaterThan, 0)
So(mockLdapAuther.syncUserCalled, ShouldBeTrue)
So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldBeGreaterThan, 0)
})
Convey("When session variable not expired, don't sync and don't change session var", func() {
// arrange
session := mockSession{}
ctx := Context{Session: &session}
sess := newMockSession()
ctx := m.ReqContext{Session: &sess}
now := time.Now().Unix()
session.Set(SESS_KEY_LASTLDAPSYNC, now)
sess.Set(session.SESS_KEY_LASTLDAPSYNC, now)
sess.Set(AUTH_PROXY_SESSION_VAR, "test")
// act
syncGrafanaUserWithLdapUser(&ctx, &query)
syncGrafanaUserWithLdapUser(&m.LoginUserQuery{
ReqContext: &ctx,
Username: "test",
})
// assert
So(session.Get(SESS_KEY_LASTLDAPSYNC), ShouldEqual, now)
So(mockLdapAuther.syncSignedInUserCalled, ShouldBeFalse)
So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldEqual, now)
So(mockLdapAuther.syncUserCalled, ShouldBeFalse)
})
Convey("When lastldapsync is expired, session variable should be updated", func() {
// arrange
session := mockSession{}
ctx := Context{Session: &session}
sess := newMockSession()
ctx := m.ReqContext{Session: &sess}
expiredTime := time.Now().Add(time.Duration(-120) * time.Minute).Unix()
session.Set(SESS_KEY_LASTLDAPSYNC, expiredTime)
sess.Set(session.SESS_KEY_LASTLDAPSYNC, expiredTime)
sess.Set(AUTH_PROXY_SESSION_VAR, "test")
// act
syncGrafanaUserWithLdapUser(&ctx, &query)
syncGrafanaUserWithLdapUser(&m.LoginUserQuery{
ReqContext: &ctx,
Username: "test",
})
// assert
So(session.Get(SESS_KEY_LASTLDAPSYNC), ShouldBeGreaterThan, expiredTime)
So(mockLdapAuther.syncSignedInUserCalled, ShouldBeTrue)
So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldBeGreaterThan, expiredTime)
So(mockLdapAuther.syncUserCalled, ShouldBeTrue)
})
})
}
type mockSession struct {
value interface{}
value map[interface{}]interface{}
}
func (s *mockSession) Start(c *Context) error {
func newMockSession() mockSession {
session := mockSession{}
session.value = make(map[interface{}]interface{})
return session
}
func (s *mockSession) Start(c *macaron.Context) error {
return nil
}
func (s *mockSession) Set(k interface{}, v interface{}) error {
s.value = v
s.value[k] = v
return nil
}
func (s *mockSession) Get(k interface{}) interface{} {
return s.value
return s.value[k]
}
func (s *mockSession) Delete(k interface{}) interface{} {
delete(s.value, k)
return nil
}
@@ -102,30 +119,27 @@ func (s *mockSession) Release() error {
return nil
}
func (s *mockSession) Destory(c *Context) error {
func (s *mockSession) Destory(c *macaron.Context) error {
return nil
}
func (s *mockSession) RegenerateId(c *Context) error {
func (s *mockSession) RegenerateId(c *macaron.Context) error {
return nil
}
type mockLdapAuthenticator struct {
syncSignedInUserCalled bool
syncUserCalled bool
}
func (a *mockLdapAuthenticator) Login(query *login.LoginUserQuery) error {
func (a *mockLdapAuthenticator) Login(query *m.LoginUserQuery) error {
return nil
}
func (a *mockLdapAuthenticator) SyncSignedInUser(signedInUser *m.SignedInUser) error {
a.syncSignedInUserCalled = true
func (a *mockLdapAuthenticator) SyncUser(query *m.LoginUserQuery) error {
a.syncUserCalled = true
return nil
}
func (a *mockLdapAuthenticator) GetGrafanaUserFor(ldapUser *login.LdapUserInfo) (*m.User, error) {
func (a *mockLdapAuthenticator) GetGrafanaUserFor(ctx *m.ReqContext, ldapUser *login.LdapUserInfo) (*m.User, error) {
return nil, nil
}
func (a *mockLdapAuthenticator) SyncOrgRoles(user *m.User, ldapUser *login.LdapUserInfo) error {
return nil
}
+14 -8
View File
@@ -6,11 +6,12 @@ import (
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"gopkg.in/macaron.v1"
)
func getDashboardUrlBySlug(orgId int64, slug string) (string, error) {
query := m.GetDashboardQuery{Slug: slug, OrgId: orgId}
func getDashboardURLBySlug(orgID int64, slug string) (string, error) {
query := m.GetDashboardQuery{Slug: slug, OrgId: orgID}
if err := bus.Dispatch(&query); err != nil {
return "", m.ErrDashboardNotFound
@@ -19,12 +20,12 @@ func getDashboardUrlBySlug(orgId int64, slug string) (string, error) {
return m.GetDashboardUrl(query.Result.Uid, query.Result.Slug), nil
}
func RedirectFromLegacyDashboardUrl() macaron.Handler {
return func(c *Context) {
func RedirectFromLegacyDashboardURL() macaron.Handler {
return func(c *m.ReqContext) {
slug := c.Params("slug")
if slug != "" {
if url, err := getDashboardUrlBySlug(c.OrgId, slug); err == nil {
if url, err := getDashboardURLBySlug(c.OrgId, slug); err == nil {
url = fmt.Sprintf("%s?%s", url, c.Req.URL.RawQuery)
c.Redirect(url, 301)
return
@@ -33,12 +34,17 @@ func RedirectFromLegacyDashboardUrl() macaron.Handler {
}
}
func RedirectFromLegacyDashboardSoloUrl() macaron.Handler {
return func(c *Context) {
func RedirectFromLegacyDashboardSoloURL() macaron.Handler {
return func(c *m.ReqContext) {
slug := c.Params("slug")
renderRequest := c.QueryBool("render")
if slug != "" {
if url, err := getDashboardUrlBySlug(c.OrgId, slug); err == nil {
if url, err := getDashboardURLBySlug(c.OrgId, slug); err == nil {
if renderRequest && strings.Contains(url, setting.AppSubUrl) {
url = strings.Replace(url, setting.AppSubUrl, "", 1)
}
url = strings.Replace(url, "/d/", "/d-solo/", 1)
url = fmt.Sprintf("%s?%s", url, c.Req.URL.RawQuery)
c.Redirect(url, 301)
+10 -10
View File
@@ -13,8 +13,8 @@ import (
func TestMiddlewareDashboardRedirect(t *testing.T) {
Convey("Given the dashboard redirect middleware", t, func() {
bus.ClearBusHandlers()
redirectFromLegacyDashboardUrl := RedirectFromLegacyDashboardUrl()
redirectFromLegacyDashboardSoloUrl := RedirectFromLegacyDashboardSoloUrl()
redirectFromLegacyDashboardUrl := RedirectFromLegacyDashboardURL()
redirectFromLegacyDashboardSoloUrl := RedirectFromLegacyDashboardSoloURL()
fakeDash := m.NewDashboard("Child dash")
fakeDash.Id = 1
@@ -34,9 +34,9 @@ func TestMiddlewareDashboardRedirect(t *testing.T) {
Convey("Should redirect to new dashboard url with a 301 Moved Permanently", func() {
So(sc.resp.Code, ShouldEqual, 301)
redirectUrl, _ := sc.resp.Result().Location()
So(redirectUrl.Path, ShouldEqual, m.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug))
So(len(redirectUrl.Query()), ShouldEqual, 2)
redirectURL, _ := sc.resp.Result().Location()
So(redirectURL.Path, ShouldEqual, m.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug))
So(len(redirectURL.Query()), ShouldEqual, 2)
})
})
@@ -47,11 +47,11 @@ func TestMiddlewareDashboardRedirect(t *testing.T) {
Convey("Should redirect to new dashboard url with a 301 Moved Permanently", func() {
So(sc.resp.Code, ShouldEqual, 301)
redirectUrl, _ := sc.resp.Result().Location()
expectedUrl := m.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug)
expectedUrl = strings.Replace(expectedUrl, "/d/", "/d-solo/", 1)
So(redirectUrl.Path, ShouldEqual, expectedUrl)
So(len(redirectUrl.Query()), ShouldEqual, 2)
redirectURL, _ := sc.resp.Result().Location()
expectedURL := m.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug)
expectedURL = strings.Replace(expectedURL, "/d/", "/d-solo/", 1)
So(redirectURL.Path, ShouldEqual, expectedURL)
So(len(redirectURL.Query()), ShouldEqual, 2)
})
})
})
+2 -1
View File
@@ -19,6 +19,7 @@ import (
"net/http"
"time"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"github.com/prometheus/client_golang/prometheus"
"gopkg.in/macaron.v1"
@@ -47,7 +48,7 @@ func Logger() macaron.Handler {
}
if ctx, ok := c.Data["ctx"]; ok {
ctxTyped := ctx.(*Context)
ctxTyped := ctx.(*m.ReqContext)
if status == 500 {
ctxTyped.Logger.Error("Request Completed", "method", req.Method, "path", req.URL.Path, "status", status, "remote_addr", c.RemoteAddr(), "time_ms", int64(timeTakenMs), "size", rw.Size(), "referer", req.Referer())
} else {
+10 -86
View File
@@ -2,38 +2,24 @@ package middleware
import (
"strconv"
"strings"
"gopkg.in/macaron.v1"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/apikeygen"
"github.com/grafana/grafana/pkg/log"
l "github.com/grafana/grafana/pkg/login"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/session"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
"github.com/prometheus/client_golang/prometheus"
)
type Context struct {
*macaron.Context
*m.SignedInUser
Session SessionStore
IsSignedIn bool
IsRenderCall bool
AllowAnonymous bool
Logger log.Logger
}
func GetContextHandler() macaron.Handler {
return func(c *macaron.Context) {
ctx := &Context{
ctx := &m.ReqContext{
Context: c,
SignedInUser: &m.SignedInUser{},
Session: GetSession(),
Session: session.GetSession(),
IsSignedIn: false,
AllowAnonymous: false,
Logger: log.New("context"),
@@ -74,7 +60,7 @@ func GetContextHandler() macaron.Handler {
}
}
func initContextWithAnonymousUser(ctx *Context) bool {
func initContextWithAnonymousUser(ctx *m.ReqContext) bool {
if !setting.AnonymousEnabled {
return false
}
@@ -94,9 +80,9 @@ func initContextWithAnonymousUser(ctx *Context) bool {
return true
}
func initContextWithUserSessionCookie(ctx *Context, orgId int64) bool {
func initContextWithUserSessionCookie(ctx *m.ReqContext, orgId int64) bool {
// initialize session
if err := ctx.Session.Start(ctx); err != nil {
if err := ctx.Session.Start(ctx.Context); err != nil {
ctx.Logger.Error("Failed to start session", "error", err)
return false
}
@@ -117,7 +103,7 @@ func initContextWithUserSessionCookie(ctx *Context, orgId int64) bool {
return true
}
func initContextWithApiKey(ctx *Context) bool {
func initContextWithApiKey(ctx *m.ReqContext) bool {
var keyString string
if keyString = getApiKey(ctx); keyString == "" {
return false
@@ -153,7 +139,7 @@ func initContextWithApiKey(ctx *Context) bool {
return true
}
func initContextWithBasicAuth(ctx *Context, orgId int64) bool {
func initContextWithBasicAuth(ctx *m.ReqContext, orgId int64) bool {
if !setting.BasicAuthEnabled {
return false
@@ -178,7 +164,7 @@ func initContextWithBasicAuth(ctx *Context, orgId int64) bool {
user := loginQuery.Result
loginUserQuery := l.LoginUserQuery{Username: username, Password: password, User: user}
loginUserQuery := m.LoginUserQuery{Username: username, Password: password, User: user}
if err := bus.Dispatch(&loginUserQuery); err != nil {
ctx.JsonApiErr(401, "Invalid username or password", err)
return true
@@ -195,70 +181,8 @@ func initContextWithBasicAuth(ctx *Context, orgId int64) bool {
return true
}
// Handle handles and logs error by given status.
func (ctx *Context) Handle(status int, title string, err error) {
if err != nil {
ctx.Logger.Error(title, "error", err)
if setting.Env != setting.PROD {
ctx.Data["ErrorMsg"] = err
}
}
ctx.Data["Title"] = title
ctx.Data["AppSubUrl"] = setting.AppSubUrl
ctx.Data["Theme"] = "dark"
ctx.HTML(status, "error")
}
func (ctx *Context) JsonOK(message string) {
resp := make(map[string]interface{})
resp["message"] = message
ctx.JSON(200, resp)
}
func (ctx *Context) IsApiRequest() bool {
return strings.HasPrefix(ctx.Req.URL.Path, "/api")
}
func (ctx *Context) JsonApiErr(status int, message string, err error) {
resp := make(map[string]interface{})
if err != nil {
ctx.Logger.Error(message, "error", err)
if setting.Env != setting.PROD {
resp["error"] = err.Error()
}
}
switch status {
case 404:
resp["message"] = "Not Found"
case 500:
resp["message"] = "Internal Server Error"
}
if message != "" {
resp["message"] = message
}
ctx.JSON(status, resp)
}
func (ctx *Context) HasUserRole(role m.RoleType) bool {
return ctx.OrgRole.Includes(role)
}
func (ctx *Context) HasHelpFlag(flag m.HelpFlags1) bool {
return ctx.HelpFlags1.HasFlag(flag)
}
func (ctx *Context) TimeRequest(timer prometheus.Summary) {
ctx.Data["perfmon.timer"] = timer
}
func AddDefaultResponseHeaders() macaron.Handler {
return func(ctx *Context) {
return func(ctx *m.ReqContext) {
if ctx.IsApiRequest() && ctx.Req.Method == "GET" {
ctx.Resp.Header().Add("Cache-Control", "no-cache")
ctx.Resp.Header().Add("Pragma", "no-cache")
+60 -19
View File
@@ -7,10 +7,10 @@ import (
"path/filepath"
"testing"
"github.com/go-macaron/session"
ms "github.com/go-macaron/session"
"github.com/grafana/grafana/pkg/bus"
l "github.com/grafana/grafana/pkg/login"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/session"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
. "github.com/smartystreets/goconvey/convey"
@@ -71,7 +71,7 @@ func TestMiddlewareContext(t *testing.T) {
return nil
})
bus.AddHandler("test", func(loginUserQuery *l.LoginUserQuery) error {
bus.AddHandler("test", func(loginUserQuery *m.LoginUserQuery) error {
return nil
})
@@ -130,8 +130,8 @@ func TestMiddlewareContext(t *testing.T) {
middlewareScenario("UserId in session", func(sc *scenarioContext) {
sc.fakeReq("GET", "/").handler(func(c *Context) {
c.Session.Set(SESS_KEY_USERID, int64(12))
sc.fakeReq("GET", "/").handler(func(c *m.ReqContext) {
c.Session.Set(session.SESS_KEY_USERID, int64(12))
}).exec()
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
@@ -176,12 +176,18 @@ func TestMiddlewareContext(t *testing.T) {
setting.AuthProxyEnabled = true
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
setting.AuthProxyHeaderProperty = "username"
setting.LdapEnabled = false
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
return nil
})
bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
cmd.Result = &m.User{Id: 12}
return nil
})
sc.fakeReq("GET", "/")
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
sc.exec()
@@ -198,6 +204,7 @@ func TestMiddlewareContext(t *testing.T) {
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
setting.AuthProxyHeaderProperty = "username"
setting.AuthProxyAutoSignUp = true
setting.LdapEnabled = false
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
if query.UserId > 0 {
@@ -208,8 +215,8 @@ func TestMiddlewareContext(t *testing.T) {
}
})
bus.AddHandler("test", func(cmd *m.CreateUserCommand) error {
cmd.Result = m.User{Id: 33}
bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
cmd.Result = &m.User{Id: 33}
return nil
})
@@ -225,11 +232,11 @@ func TestMiddlewareContext(t *testing.T) {
})
})
middlewareScenario("When auth_proxy is enabled and request RemoteAddr is not trusted", func(sc *scenarioContext) {
middlewareScenario("When auth_proxy is enabled and IPv4 request RemoteAddr is not trusted", func(sc *scenarioContext) {
setting.AuthProxyEnabled = true
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
setting.AuthProxyHeaderProperty = "username"
setting.AuthProxyWhitelist = "192.168.1.1, 192.168.2.1"
setting.AuthProxyWhitelist = "192.168.1.1, 2001::23"
sc.fakeReq("GET", "/")
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
@@ -238,6 +245,24 @@ func TestMiddlewareContext(t *testing.T) {
Convey("should return 407 status code", func() {
So(sc.resp.Code, ShouldEqual, 407)
So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 192.168.3.1 is not from the authentication proxy")
})
})
middlewareScenario("When auth_proxy is enabled and IPv6 request RemoteAddr is not trusted", func(sc *scenarioContext) {
setting.AuthProxyEnabled = true
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
setting.AuthProxyHeaderProperty = "username"
setting.AuthProxyWhitelist = "192.168.1.1, 2001::23"
sc.fakeReq("GET", "/")
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
sc.req.RemoteAddr = "[2001:23]:12345"
sc.exec()
Convey("should return 407 status code", func() {
So(sc.resp.Code, ShouldEqual, 407)
So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 2001:23 is not from the authentication proxy")
})
})
@@ -245,16 +270,21 @@ func TestMiddlewareContext(t *testing.T) {
setting.AuthProxyEnabled = true
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
setting.AuthProxyHeaderProperty = "username"
setting.AuthProxyWhitelist = "192.168.1.1, 192.168.2.1"
setting.AuthProxyWhitelist = "192.168.1.1, 2001::23"
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
return nil
})
bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
cmd.Result = &m.User{Id: 33}
return nil
})
sc.fakeReq("GET", "/")
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
sc.req.RemoteAddr = "192.168.2.1:12345"
sc.req.RemoteAddr = "[2001::23]:12345"
sc.exec()
Convey("Should init context with user info", func() {
@@ -270,14 +300,19 @@ func TestMiddlewareContext(t *testing.T) {
setting.AuthProxyHeaderProperty = "username"
setting.AuthProxyWhitelist = ""
bus.AddHandler("test", func(query *m.UpsertUserCommand) error {
query.Result = &m.User{Id: 32}
return nil
})
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
query.Result = &m.SignedInUser{OrgId: 4, UserId: 32}
return nil
})
// create session
sc.fakeReq("GET", "/").handler(func(c *Context) {
c.Session.Set(SESS_KEY_USERID, int64(33))
sc.fakeReq("GET", "/").handler(func(c *m.ReqContext) {
c.Session.Set(session.SESS_KEY_USERID, int64(33))
}).exec()
oldSessionID := sc.context.Session.ID()
@@ -300,11 +335,17 @@ func TestMiddlewareContext(t *testing.T) {
setting.LdapEnabled = true
called := false
syncGrafanaUserWithLdapUser = func(ctx *Context, query *m.GetSignedInUserQuery) error {
syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error {
called = true
query.User = &m.User{Id: 32}
return nil
}
bus.AddHandler("test", func(query *m.UpsertUserCommand) error {
query.Result = &m.User{Id: 32}
return nil
})
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
query.Result = &m.SignedInUser{OrgId: 4, UserId: 32}
return nil
@@ -336,12 +377,12 @@ func middlewareScenario(desc string, fn scenarioFunc) {
sc.m.Use(GetContextHandler())
// mock out gc goroutine
startSessionGC = func() {}
sc.m.Use(Sessioner(&session.Options{}))
session.StartSessionGC = func() {}
sc.m.Use(Sessioner(&ms.Options{}, 0))
sc.m.Use(OrgRedirect())
sc.m.Use(AddDefaultResponseHeaders())
sc.defaultHandler = func(c *Context) {
sc.defaultHandler = func(c *m.ReqContext) {
sc.context = c
if sc.handlerFunc != nil {
sc.handlerFunc(sc.context)
@@ -356,7 +397,7 @@ func middlewareScenario(desc string, fn scenarioFunc) {
type scenarioContext struct {
m *macaron.Macaron
context *Context
context *m.ReqContext
resp *httptest.ResponseRecorder
apiKey string
authHeader string
@@ -436,4 +477,4 @@ func (sc *scenarioContext) exec() {
}
type scenarioFunc func(c *scenarioContext)
type handlerFunc func(c *Context)
type handlerFunc func(c *m.ReqContext)
+3 -3
View File
@@ -7,7 +7,7 @@ import (
"strings"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"gopkg.in/macaron.v1"
@@ -22,7 +22,7 @@ func OrgRedirect() macaron.Handler {
return
}
ctx, ok := c.Data["ctx"].(*Context)
ctx, ok := c.Data["ctx"].(*m.ReqContext)
if !ok || !ctx.IsSignedIn {
return
}
@@ -31,7 +31,7 @@ func OrgRedirect() macaron.Handler {
return
}
cmd := models.SetUsingOrgCommand{UserId: ctx.UserId, OrgId: orgId}
cmd := m.SetUsingOrgCommand{UserId: ctx.UserId, OrgId: orgId}
if err := bus.Dispatch(&cmd); err != nil {
if ctx.IsApiRequest() {
ctx.JsonApiErr(404, "Not found", nil)
+12 -11
View File
@@ -6,7 +6,8 @@ import (
"fmt"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/session"
. "github.com/smartystreets/goconvey/convey"
)
@@ -14,16 +15,16 @@ func TestOrgRedirectMiddleware(t *testing.T) {
Convey("Can redirect to correct org", t, func() {
middlewareScenario("when setting a correct org for the user", func(sc *scenarioContext) {
sc.fakeReq("GET", "/").handler(func(c *Context) {
c.Session.Set(SESS_KEY_USERID, int64(12))
sc.fakeReq("GET", "/").handler(func(c *m.ReqContext) {
c.Session.Set(session.SESS_KEY_USERID, int64(12))
}).exec()
bus.AddHandler("test", func(query *models.SetUsingOrgCommand) error {
bus.AddHandler("test", func(query *m.SetUsingOrgCommand) error {
return nil
})
bus.AddHandler("test", func(query *models.GetSignedInUserQuery) error {
query.Result = &models.SignedInUser{OrgId: 1, UserId: 12}
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
query.Result = &m.SignedInUser{OrgId: 1, UserId: 12}
return nil
})
@@ -36,16 +37,16 @@ func TestOrgRedirectMiddleware(t *testing.T) {
})
middlewareScenario("when setting an invalid org for user", func(sc *scenarioContext) {
sc.fakeReq("GET", "/").handler(func(c *Context) {
c.Session.Set(SESS_KEY_USERID, int64(12))
sc.fakeReq("GET", "/").handler(func(c *m.ReqContext) {
c.Session.Set(session.SESS_KEY_USERID, int64(12))
}).exec()
bus.AddHandler("test", func(query *models.SetUsingOrgCommand) error {
bus.AddHandler("test", func(query *m.SetUsingOrgCommand) error {
return fmt.Errorf("")
})
bus.AddHandler("test", func(query *models.GetSignedInUserQuery) error {
query.Result = &models.SignedInUser{OrgId: 1, UserId: 12}
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
query.Result = &m.SignedInUser{OrgId: 1, UserId: 12}
return nil
})
+3 -1
View File
@@ -4,9 +4,11 @@ import (
"net/http"
"gopkg.in/macaron.v1"
m "github.com/grafana/grafana/pkg/models"
)
func MeasureRequestTime() macaron.Handler {
return func(res http.ResponseWriter, req *http.Request, c *Context) {
return func(res http.ResponseWriter, req *http.Request, c *m.ReqContext) {
}
}
+5 -84
View File
@@ -3,15 +3,15 @@ package middleware
import (
"fmt"
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"gopkg.in/macaron.v1"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/quota"
)
func Quota(target string) macaron.Handler {
return func(c *Context) {
limitReached, err := QuotaReached(c, target)
return func(c *m.ReqContext) {
limitReached, err := quota.QuotaReached(c, target)
if err != nil {
c.JsonApiErr(500, "failed to get quota", err)
return
@@ -22,82 +22,3 @@ func Quota(target string) macaron.Handler {
}
}
}
func QuotaReached(c *Context, target string) (bool, error) {
if !setting.Quota.Enabled {
return false, nil
}
// get the list of scopes that this target is valid for. Org, User, Global
scopes, err := m.GetQuotaScopes(target)
if err != nil {
return false, err
}
for _, scope := range scopes {
c.Logger.Debug("Checking quota", "target", target, "scope", scope)
switch scope.Name {
case "global":
if scope.DefaultLimit < 0 {
continue
}
if scope.DefaultLimit == 0 {
return true, nil
}
if target == "session" {
usedSessions := getSessionCount()
if int64(usedSessions) > scope.DefaultLimit {
c.Logger.Debug("Sessions limit reached", "active", usedSessions, "limit", scope.DefaultLimit)
return true, nil
}
continue
}
query := m.GetGlobalQuotaByTargetQuery{Target: scope.Target}
if err := bus.Dispatch(&query); err != nil {
return true, err
}
if query.Result.Used >= scope.DefaultLimit {
return true, nil
}
case "org":
if !c.IsSignedIn {
continue
}
query := m.GetOrgQuotaByTargetQuery{OrgId: c.OrgId, Target: scope.Target, Default: scope.DefaultLimit}
if err := bus.Dispatch(&query); err != nil {
return true, err
}
if query.Result.Limit < 0 {
continue
}
if query.Result.Limit == 0 {
return true, nil
}
if query.Result.Used >= query.Result.Limit {
return true, nil
}
case "user":
if !c.IsSignedIn || c.UserId == 0 {
continue
}
query := m.GetUserQuotaByTargetQuery{UserId: c.UserId, Target: scope.Target, Default: scope.DefaultLimit}
if err := bus.Dispatch(&query); err != nil {
return true, err
}
if query.Result.Limit < 0 {
continue
}
if query.Result.Limit == 0 {
return true, nil
}
if query.Result.Used >= query.Result.Limit {
return true, nil
}
}
}
return false, nil
}
+4 -3
View File
@@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/session"
"github.com/grafana/grafana/pkg/setting"
. "github.com/smartystreets/goconvey/convey"
)
@@ -12,7 +13,7 @@ import (
func TestMiddlewareQuota(t *testing.T) {
Convey("Given the grafana quota middleware", t, func() {
getSessionCount = func() int {
session.GetSessionCount = func() int {
return 4
}
@@ -74,8 +75,8 @@ func TestMiddlewareQuota(t *testing.T) {
middlewareScenario("with user logged in", func(sc *scenarioContext) {
// log us in, so we have a user_id and org_id in the context
sc.fakeReq("GET", "/").handler(func(c *Context) {
c.Session.Set(SESS_KEY_USERID, int64(12))
sc.fakeReq("GET", "/").handler(func(c *m.ReqContext) {
c.Session.Set(session.SESS_KEY_USERID, int64(12))
}).exec()
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
+4 -3
View File
@@ -24,6 +24,7 @@ import (
"gopkg.in/macaron.v1"
"github.com/grafana/grafana/pkg/log"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
)
@@ -34,7 +35,7 @@ var (
slash = []byte("/")
)
// stack returns a nicely formated stack frame, skipping skip frames
// stack returns a nicely formatted stack frame, skipping skip frames
func stack(skip int) []byte {
buf := new(bytes.Buffer) // the returned data
// As we loop, we open files and read them. These variables record the currently
@@ -106,7 +107,7 @@ func Recovery() macaron.Handler {
panicLogger := log.Root
// try to get request logger
if ctx, ok := c.Data["ctx"]; ok {
ctxTyped := ctx.(*Context)
ctxTyped := ctx.(*m.ReqContext)
panicLogger = ctxTyped.Logger
}
@@ -123,7 +124,7 @@ func Recovery() macaron.Handler {
c.Data["ErrorMsg"] = string(stack)
}
ctx, ok := c.Data["ctx"].(*Context)
ctx, ok := c.Data["ctx"].(*m.ReqContext)
if ok && ctx.IsApiRequest() {
resp := make(map[string]interface{})
+13 -11
View File
@@ -4,18 +4,20 @@ import (
"path/filepath"
"testing"
"github.com/go-macaron/session"
ms "github.com/go-macaron/session"
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/session"
. "github.com/smartystreets/goconvey/convey"
"gopkg.in/macaron.v1"
)
func TestRecoveryMiddleware(t *testing.T) {
Convey("Given an api route that panics", t, func() {
apiUrl := "/api/whatever"
recoveryScenario("recovery middleware should return json", apiUrl, func(sc *scenarioContext) {
apiURL := "/api/whatever"
recoveryScenario("recovery middleware should return json", apiURL, func(sc *scenarioContext) {
sc.handlerFunc = PanicHandler
sc.fakeReq("GET", apiUrl).exec()
sc.fakeReq("GET", apiURL).exec()
sc.req.Header.Add("content-type", "application/json")
So(sc.resp.Code, ShouldEqual, 500)
@@ -25,10 +27,10 @@ func TestRecoveryMiddleware(t *testing.T) {
})
Convey("Given a non-api route that panics", t, func() {
apiUrl := "/whatever"
recoveryScenario("recovery middleware should return html", apiUrl, func(sc *scenarioContext) {
apiURL := "/whatever"
recoveryScenario("recovery middleware should return html", apiURL, func(sc *scenarioContext) {
sc.handlerFunc = PanicHandler
sc.fakeReq("GET", apiUrl).exec()
sc.fakeReq("GET", apiURL).exec()
So(sc.resp.Code, ShouldEqual, 500)
So(sc.resp.Header().Get("content-type"), ShouldEqual, "text/html; charset=UTF-8")
@@ -37,7 +39,7 @@ func TestRecoveryMiddleware(t *testing.T) {
})
}
func PanicHandler(c *Context) {
func PanicHandler(c *m.ReqContext) {
panic("Handler has panicked")
}
@@ -60,12 +62,12 @@ func recoveryScenario(desc string, url string, fn scenarioFunc) {
sc.m.Use(GetContextHandler())
// mock out gc goroutine
startSessionGC = func() {}
sc.m.Use(Sessioner(&session.Options{}))
session.StartSessionGC = func() {}
sc.m.Use(Sessioner(&ms.Options{}, 0))
sc.m.Use(OrgRedirect())
sc.m.Use(AddDefaultResponseHeaders())
sc.defaultHandler = func(c *Context) {
sc.defaultHandler = func(c *m.ReqContext) {
sc.context = c
if sc.handlerFunc != nil {
sc.handlerFunc(sc.context)
+8 -8
View File
@@ -10,7 +10,7 @@ import (
var renderKeysLock sync.Mutex
var renderKeys map[string]*m.SignedInUser = make(map[string]*m.SignedInUser)
func initContextWithRenderAuth(ctx *Context) bool {
func initContextWithRenderAuth(ctx *m.ReqContext) bool {
key := ctx.GetCookie("renderKey")
if key == "" {
return false
@@ -19,16 +19,16 @@ func initContextWithRenderAuth(ctx *Context) bool {
renderKeysLock.Lock()
defer renderKeysLock.Unlock()
if renderUser, exists := renderKeys[key]; !exists {
renderUser, exists := renderKeys[key]
if !exists {
ctx.JsonApiErr(401, "Invalid Render Key", nil)
return true
} else {
ctx.IsSignedIn = true
ctx.SignedInUser = renderUser
ctx.IsRenderCall = true
return true
}
ctx.IsSignedIn = true
ctx.SignedInUser = renderUser
ctx.IsRenderCall = true
return true
}
type renderContextFunc func(key string) (string, error)
+8 -157
View File
@@ -1,170 +1,21 @@
package middleware
import (
"math/rand"
"time"
"github.com/go-macaron/session"
_ "github.com/go-macaron/session/memcache"
_ "github.com/go-macaron/session/mysql"
_ "github.com/go-macaron/session/postgres"
_ "github.com/go-macaron/session/redis"
"github.com/grafana/grafana/pkg/log"
ms "github.com/go-macaron/session"
"gopkg.in/macaron.v1"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/session"
)
const (
SESS_KEY_USERID = "uid"
SESS_KEY_OAUTH_STATE = "state"
SESS_KEY_APIKEY = "apikey_id" // used for render requests with api keys
SESS_KEY_LASTLDAPSYNC = "last_ldap_sync"
)
func Sessioner(options *ms.Options, sessionConnMaxLifetime int64) macaron.Handler {
session.Init(options, sessionConnMaxLifetime)
var sessionManager *session.Manager
var sessionOptions *session.Options
var startSessionGC func()
var getSessionCount func() int
var sessionLogger = log.New("session")
func init() {
startSessionGC = func() {
sessionManager.GC()
sessionLogger.Debug("Session GC")
time.AfterFunc(time.Duration(sessionOptions.Gclifetime)*time.Second, startSessionGC)
}
getSessionCount = func() int {
return sessionManager.Count()
}
}
func prepareOptions(opt *session.Options) *session.Options {
if len(opt.Provider) == 0 {
opt.Provider = "memory"
}
if len(opt.ProviderConfig) == 0 {
opt.ProviderConfig = "data/sessions"
}
if len(opt.CookieName) == 0 {
opt.CookieName = "grafana_sess"
}
if len(opt.CookiePath) == 0 {
opt.CookiePath = "/"
}
if opt.Gclifetime == 0 {
opt.Gclifetime = 3600
}
if opt.Maxlifetime == 0 {
opt.Maxlifetime = opt.Gclifetime
}
if opt.IDLength == 0 {
opt.IDLength = 16
}
return opt
}
func Sessioner(options *session.Options) macaron.Handler {
var err error
sessionOptions = prepareOptions(options)
sessionManager, err = session.NewManager(options.Provider, *options)
if err != nil {
panic(err)
}
// start GC threads after some random seconds
rndSeconds := 10 + rand.Int63n(180)
time.AfterFunc(time.Duration(rndSeconds)*time.Second, startSessionGC)
return func(ctx *Context) {
return func(ctx *m.ReqContext) {
ctx.Next()
if err = ctx.Session.Release(); err != nil {
if err := ctx.Session.Release(); err != nil {
panic("session(release): " + err.Error())
}
}
}
func GetSession() SessionStore {
return &SessionWrapper{manager: sessionManager}
}
type SessionStore interface {
// Set sets value to given key in session.
Set(interface{}, interface{}) error
// Get gets value by given key in session.
Get(interface{}) interface{}
// Delete deletes a key from session.
Delete(interface{}) interface{}
// ID returns current session ID.
ID() string
// Release releases session resource and save data to provider.
Release() error
// Destory deletes a session.
Destory(*Context) error
// init
Start(*Context) error
// RegenerateId regenerates the session id
RegenerateId(*Context) error
}
type SessionWrapper struct {
session session.RawStore
manager *session.Manager
}
func (s *SessionWrapper) Start(c *Context) error {
var err error
s.session, err = s.manager.Start(c.Context)
return err
}
func (s *SessionWrapper) RegenerateId(c *Context) error {
var err error
s.session, err = s.manager.RegenerateId(c.Context)
return err
}
func (s *SessionWrapper) Set(k interface{}, v interface{}) error {
if s.session != nil {
return s.session.Set(k, v)
}
return nil
}
func (s *SessionWrapper) Get(k interface{}) interface{} {
if s.session != nil {
return s.session.Get(k)
}
return nil
}
func (s *SessionWrapper) Delete(k interface{}) interface{} {
if s.session != nil {
return s.session.Delete(k)
}
return nil
}
func (s *SessionWrapper) ID() string {
if s.session != nil {
return s.session.ID()
}
return ""
}
func (s *SessionWrapper) Release() error {
if s.session != nil {
return s.session.Release()
}
return nil
}
func (s *SessionWrapper) Destory(c *Context) error {
if s.session != nil {
if err := s.manager.Destory(c.Context); err != nil {
return err
}
s.session = nil
}
return nil
}
+2 -1
View File
@@ -3,12 +3,13 @@ package middleware
import (
"strings"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"gopkg.in/macaron.v1"
)
func ValidateHostHeader(domain string) macaron.Handler {
return func(c *Context) {
return func(c *m.ReqContext) {
// ignore local render calls
if c.IsRenderCall {
return

Some files were not shown because too many files have changed in this diff Show More