Merge branch 'master' into master
This commit is contained in:
+11
-3
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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,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
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 +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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: "",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
})
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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{})
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user