diff --git a/docs/sources/http_api/preferences.md b/docs/sources/http_api/preferences.md index 665064b214e..46a63704e3b 100644 --- a/docs/sources/http_api/preferences.md +++ b/docs/sources/http_api/preferences.md @@ -66,6 +66,34 @@ Content-Type: text/plain; charset=utf-8 {"message":"Preferences updated"} ``` +## Patch Current User Prefs + +Update one or more preferences without modifying the others. + +`PATCH /api/user/preferences` + +**Example Request**: + +```http +PATCH /api/user/preferences HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + +{ + "theme": "dark" +} +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: text/plain; charset=utf-8 + +{"message":"Preferences updated"} +``` + ## Get Current Org Prefs `GET /api/org/preferences` @@ -115,3 +143,31 @@ Content-Type: text/plain; charset=utf-8 {"message":"Preferences updated"} ``` + +## Patch Current Org Prefs + +Update one or more preferences without modifying the others. + +`PATCH /api/org/preferences` + +**Example Request**: + +```http +PATCH /api/org/preferences HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + +{ + "theme": "dark" +} +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: text/plain; charset=utf-8 + +{"message":"Preferences updated"} +``` diff --git a/pkg/api/api.go b/pkg/api/api.go index 62da8f40255..255c564c705 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -167,6 +167,7 @@ func (hs *HTTPServer) registerRoutes() { userRoute.Get("/preferences", routing.Wrap(hs.GetUserPreferences)) userRoute.Put("/preferences", routing.Wrap(hs.UpdateUserPreferences)) + userRoute.Patch("/preferences", routing.Wrap(hs.PatchUserPreferences)) userRoute.Get("/auth-tokens", routing.Wrap(hs.GetUserAuthTokens)) userRoute.Post("/revoke-auth-token", routing.Wrap(hs.RevokeUserAuthToken)) @@ -229,6 +230,7 @@ func (hs *HTTPServer) registerRoutes() { // prefs orgRoute.Get("/preferences", authorize(reqOrgAdmin, ac.EvalPermission(ActionOrgsPreferencesRead)), routing.Wrap(hs.GetOrgPreferences)) orgRoute.Put("/preferences", authorize(reqOrgAdmin, ac.EvalPermission(ActionOrgsPreferencesWrite)), routing.Wrap(hs.UpdateOrgPreferences)) + orgRoute.Patch("/preferences", authorize(reqOrgAdmin, ac.EvalPermission(ActionOrgsPreferencesWrite)), routing.Wrap(hs.PatchOrgPreferences)) }) // current org without requirement of user to be org admin diff --git a/pkg/api/docs/definitions/org_preferences.go b/pkg/api/docs/definitions/org_preferences.go index 3299de16c37..d8b23225747 100644 --- a/pkg/api/docs/definitions/org_preferences.go +++ b/pkg/api/docs/definitions/org_preferences.go @@ -20,3 +20,14 @@ package definitions // 401: unauthorisedError // 403: forbiddenError // 500: internalServerError + +// swagger:route PATCH /org/preferences org_preferences patchOrgPreferences +// +// Patch Current Org Prefs. +// +// Responses: +// 200: addOrgUser +// 400: badRequestError +// 401: unauthorisedError +// 403: forbiddenError +// 500: internalServerError diff --git a/pkg/api/docs/definitions/user_preferences.go b/pkg/api/docs/definitions/user_preferences.go index 71e81643673..4867c3d77c7 100644 --- a/pkg/api/docs/definitions/user_preferences.go +++ b/pkg/api/docs/definitions/user_preferences.go @@ -23,6 +23,16 @@ import "github.com/grafana/grafana/pkg/api/dtos" // 401: unauthorisedError // 500: internalServerError +// swagger:route PATCH /user/preferences user_preferences patchUserPreferences +// +// Patch user preferences. +// +// Responses: +// 200: okResponse +// 400: badRequestError +// 401: unauthorisedError +// 500: internalServerError + // swagger:parameters updateUserPreferences updateOrgPreferences updateTeamPreferences type UpdateUserPreferencesParam struct { // in:body @@ -35,3 +45,10 @@ type GetPreferencesResponse struct { // in:body Body dtos.Prefs `json:"body"` } + +// swagger:parameters patchUserPreferences patchOrgPreferences patchTeamPreferences +type PatchUserPreferencesParam struct { + // in:body + // required:true + Body dtos.PatchPrefsCmd `json:"body"` +} diff --git a/pkg/api/dtos/index.go b/pkg/api/dtos/index.go index 64e2d5b531f..330e9b689b7 100644 --- a/pkg/api/dtos/index.go +++ b/pkg/api/dtos/index.go @@ -37,7 +37,8 @@ const ( // are negative to ensure that the default items are placed above // any items with default weight. - WeightHome = (iota - 20) * 100 + WeightSavedItems = (iota - 20) * 100 + WeightHome WeightCreate WeightDashboard WeightExplore diff --git a/pkg/api/dtos/prefs.go b/pkg/api/dtos/prefs.go index bb513f5b416..96a83a94dcb 100644 --- a/pkg/api/dtos/prefs.go +++ b/pkg/api/dtos/prefs.go @@ -1,10 +1,13 @@ package dtos +import "github.com/grafana/grafana/pkg/models" + type Prefs struct { - Theme string `json:"theme"` - HomeDashboardID int64 `json:"homeDashboardId"` - Timezone string `json:"timezone"` - WeekStart string `json:"weekStart"` + Theme string `json:"theme"` + HomeDashboardID int64 `json:"homeDashboardId"` + Timezone string `json:"timezone"` + WeekStart string `json:"weekStart"` + Navbar models.NavbarPreference `json:"navbar,omitempty"` } // swagger:model @@ -15,6 +18,20 @@ type UpdatePrefsCmd struct { // Default:0 HomeDashboardID int64 `json:"homeDashboardId"` // Enum: utc,browser - Timezone string `json:"timezone"` - WeekStart string `json:"weekStart"` + Timezone string `json:"timezone"` + WeekStart string `json:"weekStart"` + Navbar *models.NavbarPreference `json:"navbar,omitempty"` +} + +// swagger:model +type PatchPrefsCmd struct { + // Enum: light,dark + Theme *string `json:"theme,omitempty"` + // The numerical :id of a favorited dashboard + // Default:0 + HomeDashboardID *int64 `json:"homeDashboardId,omitempty"` + // Enum: utc,browser + Timezone *string `json:"timezone,omitempty"` + WeekStart *string `json:"weekStart,omitempty"` + Navbar *models.NavbarPreference `json:"navbar,omitempty"` } diff --git a/pkg/api/index.go b/pkg/api/index.go index 3f7b18ac5d4..ee87bb73240 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -159,6 +159,20 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto navTree := []*dtos.NavLink{} if hs.Features.IsEnabled(featuremgmt.FlagNewNavigation) { + savedItemsLinks, err := hs.buildSavedItemsNavLinks(c) + if err != nil { + return nil, err + } + + navTree = append(navTree, &dtos.NavLink{ + Text: "Saved Items", + Id: "saved-items", + Icon: "heart", + SortWeight: dtos.WeightSavedItems, + Section: dtos.NavSectionCore, + Children: savedItemsLinks, + }) + navTree = append(navTree, &dtos.NavLink{ Text: "Home", Id: "home", @@ -388,6 +402,30 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto return navTree, nil } +func (hs *HTTPServer) buildSavedItemsNavLinks(c *models.ReqContext) ([]*dtos.NavLink, error) { + savedItemsChildNavs := []*dtos.NavLink{} + + // query preferences table for any saved items + prefsQuery := models.GetPreferencesWithDefaultsQuery{User: c.SignedInUser} + if err := hs.SQLStore.GetPreferencesWithDefaults(c.Req.Context(), &prefsQuery); err != nil { + return nil, err + } + savedItems := prefsQuery.Result.JsonData.Navbar.SavedItems + + if len(savedItems) > 0 { + for _, savedItem := range savedItems { + savedItemsChildNavs = append(savedItemsChildNavs, &dtos.NavLink{ + Id: savedItem.Id, + Text: savedItem.Text, + Url: savedItem.Url, + Target: savedItem.Target, + }) + } + } + + return savedItemsChildNavs, nil +} + func (hs *HTTPServer) buildDashboardNavLinks(c *models.ReqContext, hasEditPerm bool) []*dtos.NavLink { dashboardChildNavs := []*dtos.NavLink{} if !hs.Features.IsEnabled(featuremgmt.FlagNewNavigation) { diff --git a/pkg/api/preferences.go b/pkg/api/preferences.go index 5a071b5d9b3..7d6de66a44f 100644 --- a/pkg/api/preferences.go +++ b/pkg/api/preferences.go @@ -51,6 +51,10 @@ func (hs *HTTPServer) getPreferencesFor(ctx context.Context, orgID, userID, team WeekStart: prefsQuery.Result.WeekStart, } + if prefsQuery.Result.JsonData != nil { + dto.Navbar = prefsQuery.Result.JsonData.Navbar + } + return response.JSON(200, &dto) } @@ -84,6 +88,37 @@ func (hs *HTTPServer) updatePreferencesFor(ctx context.Context, orgID, userID, t return response.Success("Preferences updated") } +// PATCH /api/user/preferences +func (hs *HTTPServer) PatchUserPreferences(c *models.ReqContext) response.Response { + dtoCmd := dtos.PatchPrefsCmd{} + if err := web.Bind(c.Req, &dtoCmd); err != nil { + return response.Error(http.StatusBadRequest, "bad request data", err) + } + return hs.patchPreferencesFor(c.Req.Context(), c.OrgId, c.UserId, 0, &dtoCmd) +} + +func (hs *HTTPServer) patchPreferencesFor(ctx context.Context, orgID, userID, teamId int64, dtoCmd *dtos.PatchPrefsCmd) response.Response { + if dtoCmd.Theme != nil && *dtoCmd.Theme != lightTheme && *dtoCmd.Theme != darkTheme && *dtoCmd.Theme != defaultTheme { + return response.Error(400, "Invalid theme", nil) + } + patchCmd := models.PatchPreferencesCommand{ + UserId: userID, + OrgId: orgID, + TeamId: teamId, + Theme: dtoCmd.Theme, + Timezone: dtoCmd.Timezone, + WeekStart: dtoCmd.WeekStart, + HomeDashboardId: dtoCmd.HomeDashboardID, + Navbar: dtoCmd.Navbar, + } + + if err := hs.SQLStore.PatchPreferences(ctx, &patchCmd); err != nil { + return response.Error(500, "Failed to save preferences", err) + } + + return response.Success("Preferences updated") +} + // GET /api/org/preferences func (hs *HTTPServer) GetOrgPreferences(c *models.ReqContext) response.Response { return hs.getPreferencesFor(c.Req.Context(), c.OrgId, 0, 0) @@ -97,3 +132,12 @@ func (hs *HTTPServer) UpdateOrgPreferences(c *models.ReqContext) response.Respon } return hs.updatePreferencesFor(c.Req.Context(), c.OrgId, 0, 0, &dtoCmd) } + +// PATCH /api/org/preferences +func (hs *HTTPServer) PatchOrgPreferences(c *models.ReqContext) response.Response { + dtoCmd := dtos.PatchPrefsCmd{} + if err := web.Bind(c.Req, &dtoCmd); err != nil { + return response.Error(http.StatusBadRequest, "bad request data", err) + } + return hs.patchPreferencesFor(c.Req.Context(), c.OrgId, 0, 0, &dtoCmd) +} diff --git a/pkg/api/preferences_test.go b/pkg/api/preferences_test.go index 5cc5c69c6b9..98cb46f14dd 100644 --- a/pkg/api/preferences_test.go +++ b/pkg/api/preferences_test.go @@ -11,10 +11,16 @@ import ( ) var ( - getOrgPreferencesURL = "/api/org/preferences/" - putOrgPreferencesURL = "/api/org/preferences/" + getOrgPreferencesURL = "/api/org/preferences/" + putOrgPreferencesURL = "/api/org/preferences/" + patchOrgPreferencesUrl = "/api/org/preferences/" + patchUserPreferencesUrl = "/api/user/preferences/" - testUpdateOrgPreferencesCmd = `{ "theme": "light", "homeDashboardId": 1 }` + testUpdateOrgPreferencesCmd = `{ "theme": "light", "homeDashboardId": 1 }` + testPatchOrgPreferencesCmd = `{"navbar":{"savedItems":[{"id":"snapshots","text":"Snapshots","icon":"camera","url":"/dashboard/snapshots"}]}}` + testPatchOrgPreferencesCmdBad = `this is not json` + testPatchUserPreferencesCmd = `{"navbar":{"savedItems":[{"id":"snapshots","text":"Snapshots","icon":"camera","url":"/dashboard/snapshots"}]}}` + testPatchUserPreferencesCmdBad = `this is not json` ) func TestAPIEndpoint_GetCurrentOrgPreferences_LegacyAccessControl(t *testing.T) { @@ -109,3 +115,43 @@ func TestAPIEndpoint_PutCurrentOrgPreferences_AccessControl(t *testing.T) { assert.Equal(t, http.StatusForbidden, response.Code) }) } + +func TestAPIEndpoint_PatchUserPreferences(t *testing.T) { + sc := setupHTTPServer(t, true, false) + + _, err := sc.db.CreateOrgWithMember("TestOrg", testUserID) + require.NoError(t, err) + + setInitCtxSignedInOrgAdmin(sc.initCtx) + input := strings.NewReader(testPatchUserPreferencesCmd) + t.Run("Returns 200 on success", func(t *testing.T) { + response := callAPI(sc.server, http.MethodPatch, patchUserPreferencesUrl, input, t) + assert.Equal(t, http.StatusOK, response.Code) + }) + + input = strings.NewReader(testPatchUserPreferencesCmdBad) + t.Run("Returns 400 with bad data", func(t *testing.T) { + response := callAPI(sc.server, http.MethodPut, patchUserPreferencesUrl, input, t) + assert.Equal(t, http.StatusBadRequest, response.Code) + }) +} + +func TestAPIEndpoint_PatchOrgPreferences(t *testing.T) { + sc := setupHTTPServer(t, true, false) + + _, err := sc.db.CreateOrgWithMember("TestOrg", testUserID) + require.NoError(t, err) + + setInitCtxSignedInOrgAdmin(sc.initCtx) + input := strings.NewReader(testPatchOrgPreferencesCmd) + t.Run("Returns 200 on success", func(t *testing.T) { + response := callAPI(sc.server, http.MethodPatch, patchOrgPreferencesUrl, input, t) + assert.Equal(t, http.StatusOK, response.Code) + }) + + input = strings.NewReader(testPatchOrgPreferencesCmdBad) + t.Run("Returns 400 with bad data", func(t *testing.T) { + response := callAPI(sc.server, http.MethodPut, patchOrgPreferencesUrl, input, t) + assert.Equal(t, http.StatusBadRequest, response.Code) + }) +} diff --git a/pkg/models/preferences.go b/pkg/models/preferences.go index 04a4f6ec2c2..1fbfb3f0992 100644 --- a/pkg/models/preferences.go +++ b/pkg/models/preferences.go @@ -1,9 +1,18 @@ package models import ( + "bytes" + "encoding/json" "time" ) +type NavLink struct { + Id string `json:"id,omitempty"` + Text string `json:"text,omitempty"` + Url string `json:"url,omitempty"` + Target string `json:"target,omitempty"` +} + type Preferences struct { Id int64 OrgId int64 @@ -16,6 +25,32 @@ type Preferences struct { Theme string Created time.Time Updated time.Time + JsonData *PreferencesJsonData +} + +// The following needed for to implement the xorm/database ORM Conversion interface do the +// conversion when reading/writing to the database, see https://gobook.io/read/gitea.com/xorm/manual-en-US/chapter-02/4.columns.html. + +func (j *PreferencesJsonData) FromDB(data []byte) error { + dec := json.NewDecoder(bytes.NewBuffer(data)) + dec.UseNumber() + return dec.Decode(j) +} + +func (j *PreferencesJsonData) ToDB() ([]byte, error) { + if j == nil { + return nil, nil + } + + return json.Marshal(j) +} + +type NavbarPreference struct { + SavedItems []NavLink `json:"savedItems"` +} + +type PreferencesJsonData struct { + Navbar NavbarPreference `json:"navbar"` } // --------------------- @@ -43,8 +78,21 @@ type SavePreferencesCommand struct { OrgId int64 TeamId int64 - HomeDashboardId int64 `json:"homeDashboardId"` - Timezone string `json:"timezone"` - WeekStart string `json:"weekStart"` - Theme string `json:"theme"` + HomeDashboardId int64 `json:"homeDashboardId,omitempty"` + Timezone string `json:"timezone,omitempty"` + WeekStart string `json:"weekStart,omitempty"` + Theme string `json:"theme,omitempty"` + Navbar *NavbarPreference `json:"navbar,omitempty"` +} + +type PatchPreferencesCommand struct { + UserId int64 + OrgId int64 + TeamId int64 + + HomeDashboardId *int64 `json:"homeDashboardId,omitempty"` + Timezone *string `json:"timezone,omitempty"` + WeekStart *string `json:"weekStart,omitempty"` + Theme *string `json:"theme,omitempty"` + Navbar *NavbarPreference `json:"navbar,omitempty"` } diff --git a/pkg/services/sqlstore/migrations/preferences_mig.go b/pkg/services/sqlstore/migrations/preferences_mig.go index a1f6984fa66..6f36a5cf53b 100644 --- a/pkg/services/sqlstore/migrations/preferences_mig.go +++ b/pkg/services/sqlstore/migrations/preferences_mig.go @@ -1,6 +1,8 @@ package migrations -import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" +import ( + . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" +) func addPreferencesMigrations(mg *Migrator) { mg.AddMigration("drop preferences table v2", NewDropTableMigration("preferences")) @@ -46,4 +48,11 @@ func addPreferencesMigrations(mg *Migrator) { mg.AddMigration("Add column week_start in preferences", NewAddColumnMigration(preferencesV2, &Column{ Name: "week_start", Type: DB_NVarchar, Length: 10, Nullable: true, })) + + mg.AddMigration("Add column preferences.json_data", NewAddColumnMigration(preferencesV2, &Column{ + Name: "json_data", Type: DB_Text, Nullable: true, + })) + // change column type of preferences.json_data + mg.AddMigration("alter preferences.json_data to mediumtext v1", NewRawSQLMigration(""). + Mysql("ALTER TABLE preferences MODIFY json_data MEDIUMTEXT;")) } diff --git a/pkg/services/sqlstore/mockstore/mockstore.go b/pkg/services/sqlstore/mockstore/mockstore.go index 14fe879ee26..2fe47a70bfc 100644 --- a/pkg/services/sqlstore/mockstore/mockstore.go +++ b/pkg/services/sqlstore/mockstore/mockstore.go @@ -287,6 +287,10 @@ func (m *SQLStoreMock) SavePreferences(ctx context.Context, cmd *models.SavePref return m.ExpectedError } +func (m *SQLStoreMock) PatchPreferences(ctx context.Context, cmd *models.PatchPreferencesCommand) error { + return m.ExpectedError +} + func (m *SQLStoreMock) GetPluginSettings(ctx context.Context, orgID int64) ([]*models.PluginSettingInfoDTO, error) { return nil, m.ExpectedError } diff --git a/pkg/services/sqlstore/preferences.go b/pkg/services/sqlstore/preferences.go index a85b2165f71..1fccba8adc3 100644 --- a/pkg/services/sqlstore/preferences.go +++ b/pkg/services/sqlstore/preferences.go @@ -13,6 +13,7 @@ func (ss *SQLStore) addPreferencesQueryAndCommandHandlers() { bus.AddHandler("sql", ss.GetPreferences) bus.AddHandler("sql", ss.GetPreferencesWithDefaults) bus.AddHandler("sql", ss.SavePreferences) + bus.AddHandler("sql", ss.PatchPreferences) } func (ss *SQLStore) GetPreferencesWithDefaults(ctx context.Context, query *models.GetPreferencesWithDefaultsQuery) error { @@ -46,6 +47,7 @@ func (ss *SQLStore) GetPreferencesWithDefaults(ctx context.Context, query *model Timezone: ss.Cfg.DateFormats.DefaultTimezone, WeekStart: ss.Cfg.DateFormats.DefaultWeekStart, HomeDashboardId: 0, + JsonData: &models.PreferencesJsonData{}, } for _, p := range prefs { @@ -61,6 +63,9 @@ func (ss *SQLStore) GetPreferencesWithDefaults(ctx context.Context, query *model if p.HomeDashboardId != 0 { res.HomeDashboardId = p.HomeDashboardId } + if p.JsonData != nil { + res.JsonData = p.JsonData + } } query.Result = res @@ -106,10 +111,24 @@ func (ss *SQLStore) SavePreferences(ctx context.Context, cmd *models.SavePrefere Theme: cmd.Theme, Created: time.Now(), Updated: time.Now(), + JsonData: &models.PreferencesJsonData{}, + } + + if cmd.Navbar != nil { + prefs.JsonData.Navbar = *cmd.Navbar } _, err = sess.Insert(&prefs) return err } + // Wrap this in an if statement to maintain backwards compatibility + if cmd.Navbar != nil { + if prefs.JsonData == nil { + prefs.JsonData = &models.PreferencesJsonData{} + } + if cmd.Navbar.SavedItems != nil { + prefs.JsonData.Navbar.SavedItems = cmd.Navbar.SavedItems + } + } prefs.HomeDashboardId = cmd.HomeDashboardId prefs.Timezone = cmd.Timezone prefs.WeekStart = cmd.WeekStart @@ -120,3 +139,58 @@ func (ss *SQLStore) SavePreferences(ctx context.Context, cmd *models.SavePrefere return err }) } + +func (ss *SQLStore) PatchPreferences(ctx context.Context, cmd *models.PatchPreferencesCommand) error { + return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error { + var prefs models.Preferences + exists, err := sess.Where("org_id=? AND user_id=? AND team_id=?", cmd.OrgId, cmd.UserId, cmd.TeamId).Get(&prefs) + if err != nil { + return err + } + + if !exists { + prefs = models.Preferences{ + UserId: cmd.UserId, + OrgId: cmd.OrgId, + TeamId: cmd.TeamId, + Created: time.Now(), + JsonData: &models.PreferencesJsonData{}, + } + } + + if cmd.Navbar != nil { + if prefs.JsonData == nil { + prefs.JsonData = &models.PreferencesJsonData{} + } + if cmd.Navbar.SavedItems != nil { + prefs.JsonData.Navbar.SavedItems = cmd.Navbar.SavedItems + } + } + + if cmd.HomeDashboardId != nil { + prefs.HomeDashboardId = *cmd.HomeDashboardId + } + + if cmd.Timezone != nil { + prefs.Timezone = *cmd.Timezone + } + + if cmd.WeekStart != nil { + prefs.WeekStart = *cmd.WeekStart + } + + if cmd.Theme != nil { + prefs.Theme = *cmd.Theme + } + + prefs.Updated = time.Now() + prefs.Version += 1 + + if exists { + _, err = sess.ID(prefs.Id).AllCols().Update(&prefs) + } else { + _, err = sess.Insert(&prefs) + } + return err + }) +} diff --git a/pkg/services/sqlstore/preferences_test.go b/pkg/services/sqlstore/preferences_test.go index 4f88c98bf42..8ff9f9f073a 100644 --- a/pkg/services/sqlstore/preferences_test.go +++ b/pkg/services/sqlstore/preferences_test.go @@ -15,6 +15,48 @@ import ( func TestPreferencesDataAccess(t *testing.T) { ss := InitTestDB(t) + emptyNavbarPreferences := models.NavbarPreference{} + userNavbarPreferences := models.NavbarPreference{ + SavedItems: []models.NavLink{{ + Id: "explore", + Text: "Explore", + Url: "/explore", + }}, + } + orgNavbarPreferences := models.NavbarPreference{ + SavedItems: []models.NavLink{{ + Id: "alerting", + Text: "Alerting", + Url: "/alerting", + }}, + } + team1NavbarPreferences := models.NavbarPreference{ + SavedItems: []models.NavLink{{ + Id: "dashboards", + Text: "Dashboards", + Url: "/dashboards", + }}, + } + team2NavbarPreferences := models.NavbarPreference{ + SavedItems: []models.NavLink{{ + Id: "home", + Text: "Home", + Url: "/home", + }}, + } + + emptyPreferencesJsonData := models.PreferencesJsonData{ + Navbar: emptyNavbarPreferences, + } + userPreferencesJsonData := models.PreferencesJsonData{ + Navbar: userNavbarPreferences, + } + orgPreferencesJsonData := models.PreferencesJsonData{ + Navbar: orgNavbarPreferences, + } + team2PreferencesJsonData := models.PreferencesJsonData{ + Navbar: team2NavbarPreferences, + } t.Run("GetPreferencesWithDefaults with no saved preferences should return defaults", func(t *testing.T) { ss.Cfg.DefaultTheme = "light" @@ -26,6 +68,7 @@ func TestPreferencesDataAccess(t *testing.T) { require.Equal(t, "light", query.Result.Theme) require.Equal(t, "UTC", query.Result.Timezone) require.Equal(t, int64(0), query.Result.HomeDashboardId) + require.Equal(t, &emptyPreferencesJsonData, query.Result.JsonData) }) t.Run("GetPreferencesWithDefaults with saved org and user home dashboard should return user home dashboard", func(t *testing.T) { @@ -118,8 +161,98 @@ func TestPreferencesDataAccess(t *testing.T) { require.Equal(t, int64(1), query.Result.HomeDashboardId) }) + t.Run("GetPreferencesWithDefaults with saved org and user json data should return user json data", func(t *testing.T) { + err := ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, Navbar: &orgNavbarPreferences}) + require.NoError(t, err) + err = ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, UserId: 1, Navbar: &userNavbarPreferences}) + require.NoError(t, err) + + query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{OrgId: 1, UserId: 1}} + err = ss.GetPreferencesWithDefaults(context.Background(), query) + require.NoError(t, err) + require.Equal(t, &userPreferencesJsonData, query.Result.JsonData) + }) + + t.Run("GetPreferencesWithDefaults with saved org and other user json data should return org json data", func(t *testing.T) { + err := ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, Navbar: &orgNavbarPreferences}) + require.NoError(t, err) + err = ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, UserId: 1, Navbar: &userNavbarPreferences}) + require.NoError(t, err) + + query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{OrgId: 1, UserId: 2}} + err = ss.GetPreferencesWithDefaults(context.Background(), query) + require.NoError(t, err) + require.Equal(t, &orgPreferencesJsonData, query.Result.JsonData) + }) + + t.Run("GetPreferencesWithDefaults with saved org and teams json data should return last team json data", func(t *testing.T) { + err := ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, Navbar: &orgNavbarPreferences}) + require.NoError(t, err) + err = ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, TeamId: 2, Navbar: &team1NavbarPreferences}) + require.NoError(t, err) + err = ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, TeamId: 3, Navbar: &team2NavbarPreferences}) + require.NoError(t, err) + + query := &models.GetPreferencesWithDefaultsQuery{ + User: &models.SignedInUser{OrgId: 1, Teams: []int64{2, 3}}, + } + err = ss.GetPreferencesWithDefaults(context.Background(), query) + require.NoError(t, err) + require.Equal(t, &team2PreferencesJsonData, query.Result.JsonData) + }) + + t.Run("GetPreferencesWithDefaults with saved org and other teams json data should return org json data", func(t *testing.T) { + err := ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, Navbar: &orgNavbarPreferences}) + require.NoError(t, err) + err = ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, TeamId: 2, Navbar: &team1NavbarPreferences}) + require.NoError(t, err) + err = ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, TeamId: 3, Navbar: &team2NavbarPreferences}) + require.NoError(t, err) + + query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{OrgId: 1}} + err = ss.GetPreferencesWithDefaults(context.Background(), query) + require.NoError(t, err) + require.Equal(t, &orgPreferencesJsonData, query.Result.JsonData) + }) + + t.Run("GetPreferencesWithDefaults with saved org, teams and user json data should return user json data", func(t *testing.T) { + err := ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, Navbar: &orgNavbarPreferences}) + require.NoError(t, err) + err = ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, TeamId: 2, Navbar: &team1NavbarPreferences}) + require.NoError(t, err) + err = ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, TeamId: 3, Navbar: &team2NavbarPreferences}) + require.NoError(t, err) + err = ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, UserId: 1, Navbar: &userNavbarPreferences}) + require.NoError(t, err) + + query := &models.GetPreferencesWithDefaultsQuery{ + User: &models.SignedInUser{OrgId: 1, UserId: 1, Teams: []int64{2, 3}}, + } + err = ss.GetPreferencesWithDefaults(context.Background(), query) + require.NoError(t, err) + require.Equal(t, &userPreferencesJsonData, query.Result.JsonData) + }) + + t.Run("GetPreferencesWithDefaults with saved org, other teams and user json data should return org json data", func(t *testing.T) { + err := ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, Navbar: &orgNavbarPreferences}) + require.NoError(t, err) + err = ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, TeamId: 2, Navbar: &team1NavbarPreferences}) + require.NoError(t, err) + err = ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, TeamId: 3, Navbar: &team2NavbarPreferences}) + require.NoError(t, err) + err = ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{OrgId: 1, UserId: 1, Navbar: &userNavbarPreferences}) + require.NoError(t, err) + + query := &models.GetPreferencesWithDefaultsQuery{ + User: &models.SignedInUser{OrgId: 1, UserId: 2}, + } + err = ss.GetPreferencesWithDefaults(context.Background(), query) + require.NoError(t, err) + require.Equal(t, &orgPreferencesJsonData, query.Result.JsonData) + }) + t.Run("SavePreferences for a user should store correct values", func(t *testing.T) { - err := ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{UserId: models.SignedInUser{}.UserId, Theme: "dark", Timezone: "browser", HomeDashboardId: 5, WeekStart: "1"}) + err := ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{UserId: models.SignedInUser{}.UserId, Theme: "dark", Timezone: "browser", HomeDashboardId: 5, WeekStart: "1", Navbar: &userNavbarPreferences}) require.NoError(t, err) query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{}} @@ -132,6 +265,33 @@ func TestPreferencesDataAccess(t *testing.T) { Timezone: "browser", WeekStart: "1", Theme: "dark", + JsonData: &userPreferencesJsonData, + Created: query.Result.Created, + Updated: query.Result.Updated, + } + if diff := cmp.Diff(expected, query.Result); diff != "" { + t.Fatalf("Result mismatch (-want +got):\n%s", diff) + } + }) + + t.Run("PatchPreferences for a user should only modify a single value", func(t *testing.T) { + err := ss.SavePreferences(context.Background(), &models.SavePreferencesCommand{UserId: models.SignedInUser{}.UserId, Theme: "dark", Timezone: "browser", HomeDashboardId: 5, WeekStart: "1", Navbar: &orgNavbarPreferences}) + require.NoError(t, err) + + err = ss.PatchPreferences(context.Background(), &models.PatchPreferencesCommand{UserId: models.SignedInUser{}.UserId, Navbar: &userNavbarPreferences}) + require.NoError(t, err) + + query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{}} + err = ss.GetPreferencesWithDefaults(context.Background(), query) + require.NoError(t, err) + expected := &models.Preferences{ + Id: query.Result.Id, + Version: query.Result.Version, + HomeDashboardId: 5, + Timezone: "browser", + WeekStart: "1", + Theme: "dark", + JsonData: &userPreferencesJsonData, Created: query.Result.Created, Updated: query.Result.Updated, } diff --git a/pkg/services/sqlstore/store.go b/pkg/services/sqlstore/store.go index d74c7b03df0..467550a1ac2 100644 --- a/pkg/services/sqlstore/store.go +++ b/pkg/services/sqlstore/store.go @@ -63,6 +63,7 @@ type Store interface { GetPreferencesWithDefaults(ctx context.Context, query *models.GetPreferencesWithDefaultsQuery) error GetPreferences(ctx context.Context, query *models.GetPreferencesQuery) error SavePreferences(ctx context.Context, cmd *models.SavePreferencesCommand) error + PatchPreferences(ctx context.Context, cmd *models.PatchPreferencesCommand) error GetPluginSettings(ctx context.Context, orgID int64) ([]*models.PluginSettingInfoDTO, error) GetPluginSettingById(ctx context.Context, query *models.GetPluginSettingByIdQuery) error UpdatePluginSetting(ctx context.Context, cmd *models.UpdatePluginSettingCmd) error diff --git a/public/api-merged.json b/public/api-merged.json index 3873ab8603e..2771159da29 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -19,6 +19,598 @@ }, "basePath": "/api", "paths": { + "/access-control/builtin-roles": { + "get": { + "description": "You need to have a permission with action `roles.builtin:list` with scope `roles:*`.", + "tags": ["access_control", "enterprise"], + "summary": "Get all built-in role assignments.", + "operationId": "listBuiltinRoles", + "responses": { + "200": { + "$ref": "#/responses/listBuiltinRolesResponse" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "description": "You need to have a permission with action `roles.builtin:add` and scope `permissions:delegate`. `permission:delegate` scope ensures that users can only create built-in role assignments with the roles which have same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to create a built-in role assignment which will allow to do that. This is done to prevent escalation of privileges.", + "tags": ["access_control", "enterprise"], + "summary": "Create a built-in role assignment.", + "operationId": "addBuiltinRole", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/AddBuiltInRoleCommand" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/builtin-roles/{builtinRole}/roles/{roleUID}": { + "delete": { + "description": "Deletes a built-in role assignment (for one of Viewer, Editor, Admin, or Grafana Admin) to the role with the provided UID.\n\nYou need to have a permission with action `roles.builtin:remove` and scope `permissions:delegate`. `permission:delegate` scope ensures that users can only remove built-in role assignments with the roles which have same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to remove a built-in role assignment which allows to do that.", + "tags": ["access_control", "enterprise"], + "summary": "Remove a built-in role assignment.", + "operationId": "removeBuiltinRole", + "parameters": [ + { + "type": "string", + "x-go-name": "RoleUID", + "name": "roleUID", + "in": "path", + "required": true + }, + { + "type": "string", + "x-go-name": "RoleUID", + "name": "builtinRole", + "in": "path", + "required": true + }, + { + "type": "boolean", + "x-go-name": "Global", + "description": "A flag indicating if the assignment is global or not. If set to false, the default org ID of the authenticated user will be used from the request to remove assignment.", + "name": "global", + "in": "query" + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/roles": { + "get": { + "description": "Gets all existing roles. The response contains all global and organization local roles, for the organization which user is signed in.\n\nYou need to have a permission with action `roles:list` and scope `roles:*`.", + "tags": ["access_control", "enterprise"], + "summary": "Get all roles.", + "operationId": "getAllRoles", + "responses": { + "200": { + "$ref": "#/responses/getAllRolesResponse" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "description": "Creates a new custom role and maps given permissions to that role. Note that roles with the same prefix as Fixed Roles can’t be created.\n\nYou need to have a permission with action `roles:write` and scope `permissions:delegate`. `permission:delegate`` scope ensures that users can only create custom roles with the same, or a subset of permissions which the user has.\nFor example, if a user does not have required permissions for creating users, they won’t be able to create a custom role which allows to do that. This is done to prevent escalation of privileges.", + "tags": ["access_control", "enterprise"], + "summary": "Create a new custom role.", + "operationId": "createRoleWithPermissions", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SetUserRolesCommand" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/getRoleResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/roles/{roleUID}": { + "get": { + "description": "Get a role for the given UID.\n\nYou need to have a permission with action `roles:read` and scope `roles:*`.", + "tags": ["access_control", "enterprise"], + "summary": "Get a role.", + "operationId": "getRole", + "parameters": [ + { + "type": "string", + "x-go-name": "RoleUID", + "name": "roleUID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/getRoleResponse" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "put": { + "description": "You need to have a permission with action `roles:write` and scope `permissions:delegate`. `permission:delegate`` scope ensures that users can only create custom roles with the same, or a subset of permissions which the user has.", + "tags": ["access_control", "enterprise"], + "summary": "Update a custom role.", + "operationId": "updateRoleWithPermissions", + "parameters": [ + { + "type": "string", + "x-go-name": "RoleUID", + "name": "roleUID", + "in": "path", + "required": true + }, + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateRoleCommand" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/getRoleResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "delete": { + "description": "Delete a role with the given UID, and it’s permissions. If the role is assigned to a built-in role, the deletion operation will fail, unless force query param is set to true, and in that case all assignments will also be deleted.\n\nYou need to have a permission with action `roles:delete` and scope `permissions:delegate`. `permission:delegate` scope ensures that users can only delete a custom role with the same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to delete a custom role which allows to do that.", + "tags": ["access_control", "enterprise"], + "summary": "Delete a custom role.", + "operationId": "deleteCustomRole", + "parameters": [ + { + "type": "string", + "x-go-name": "RoleUID", + "name": "roleUID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/status": { + "get": { + "description": "Returns an indicator to check if fine-grained access control is enabled or not.\n\nYou need to have a permission with action `status:accesscontrol` and scope `services:accesscontrol`.", + "tags": ["access_control", "enterprise"], + "summary": "Get status.", + "operationId": "getAccessControlStatus", + "responses": { + "200": { + "$ref": "#/responses/getAccessControlStatusResponse" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/teams/{teamId}/roles": { + "get": { + "description": "You need to have a permission with action `teams.roles:list` and scope `teams:id:\u003cteam ID\u003e`.", + "tags": ["access_control", "enterprise"], + "summary": "Get team roles.", + "operationId": "listTeamRoles", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "put": { + "description": "You need to have a permission with action `teams.roles:add` and `teams.roles:remove` and scope `permissions:delegate` for each.", + "tags": ["access_control", "enterprise"], + "summary": "Update team role.", + "operationId": "setTeamRoles", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "description": "You need to have a permission with action `teams.roles:add` and scope `permissions:delegate`.", + "tags": ["access_control", "enterprise"], + "summary": "Add team role.", + "operationId": "addTeamRole", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + }, + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/AddTeamRoleCommand" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/teams/{teamId}/roles/{roleUID}": { + "delete": { + "description": "You need to have a permission with action `teams.roles:remove` and scope `permissions:delegate`.", + "tags": ["access_control", "enterprise"], + "summary": "Remove team role.", + "operationId": "removeTeamRole", + "parameters": [ + { + "type": "string", + "x-go-name": "RoleUID", + "name": "roleUID", + "in": "path", + "required": true + }, + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/users/{user_id}/roles": { + "get": { + "description": "Lists the roles that have been directly assigned to a given user. The list does not include built-in roles (Viewer, Editor, Admin or Grafana Admin), and it does not include roles that have been inherited from a team.\n\nYou need to have a permission with action `users.roles:list` and scope `users:id:\u003cuser ID\u003e`.", + "tags": ["access_control", "enterprise"], + "summary": "List roles assigned to a user.", + "operationId": "listUserRoles", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "UserID", + "name": "user_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/getAllRolesResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "put": { + "description": "Update the user’s role assignments to match the provided set of UIDs. This will remove any assigned roles that aren’t in the request and add roles that are in the set but are not already assigned to the user.\nIf you want to add or remove a single role, consider using Add a user role assignment or Remove a user role assignment instead.\n\nYou need to have a permission with action `users.roles:add` and `users.roles:remove` and scope `permissions:delegate` for each. `permission:delegate` scope ensures that users can only assign or unassign roles which have same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to assign or unassign a role which will allow to do that. This is done to prevent escalation of privileges.", + "tags": ["access_control", "enterprise"], + "summary": "Set user role assignments.", + "operationId": "setUserRoles", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "UserID", + "name": "user_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "description": "Assign a role to a specific user. For bulk updates consider Set user role assignments.\n\nYou need to have a permission with action `users.roles:add` and scope `permissions:delegate`. `permission:delegate` scope ensures that users can only assign roles which have same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to assign a role which will allow to do that. This is done to prevent escalation of privileges.", + "tags": ["access_control", "enterprise"], + "summary": "Add a user role assignment.", + "operationId": "addUserRole", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/AddUserRoleCommand" + } + }, + { + "type": "integer", + "format": "int64", + "x-go-name": "UserID", + "name": "user_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/users/{user_id}/roles/{roleUID}": { + "delete": { + "description": "Revoke a role from a user. For bulk updates consider Set user role assignments.\n\nYou need to have a permission with action `users.roles:remove` and scope `permissions:delegate`. `permission:delegate` scope ensures that users can only unassign roles which have same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to unassign a role which will allow to do that. This is done to prevent escalation of privileges.", + "tags": ["access_control", "enterprise"], + "summary": "Remove a user role assignment.", + "operationId": "removeUserRole", + "parameters": [ + { + "type": "string", + "x-go-name": "RoleUID", + "name": "roleUID", + "in": "path", + "required": true + }, + { + "type": "boolean", + "x-go-name": "Global", + "description": "A flag indicating if the assignment is global or not. If set to false, the default org ID of the authenticated user will be used from the request to remove assignment.", + "name": "global", + "in": "query" + }, + { + "type": "integer", + "format": "int64", + "x-go-name": "UserID", + "name": "user_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/admin/ldap-sync-status": { + "get": { + "description": "You need to have a permission with action `ldap.status:read`.", + "tags": ["ldap_debug"], + "summary": "Available to grafana admins.", + "operationId": "getLDAPSyncStatus", + "responses": { + "200": { + "$ref": "#/responses/getLDAPSyncStatusResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, "/admin/ldap/reload": { "post": { "security": [ @@ -183,6 +775,24 @@ } } }, + "/admin/provisioning/access-control/reload": { + "post": { + "tags": ["access_control_provisioning", "enterprise"], + "summary": "You need to have a permission with action `provisioning:reload` with scope `provisioners:accesscontrol`.", + "operationId": "adminProvisioningReloadAccessControl", + "responses": { + "202": { + "$ref": "#/responses/acceptedResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + } + } + } + }, "/admin/provisioning/accesscontrol/reload": { "post": { "security": [ @@ -3767,6 +4377,155 @@ } } }, + "/datasources/{datasource_id}/disable-permissions": { + "post": { + "description": "Disables permissions for the data source with the given id. All existing permissions will be removed and anyone will be able to query the data source.\n\nYou need to have a permission with action `datasources.permissions:toggle` and scopes `datasources:*`, `datasources:id:*`, `datasources:id:1` (single data source).", + "tags": ["datasource_permissions", "enterprise"], + "summary": "Disable permissions for a data source.", + "operationId": "disablePermissions", + "parameters": [ + { + "type": "string", + "x-go-name": "DatasourceID", + "name": "datasource_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/createOrUpdateDatasourceResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/datasources/{datasource_id}/enable-permissions": { + "post": { + "description": "Enables permissions for the data source with the given id.\nNo one except Org Admins will be able to query the data source until permissions have been added\nwhich permit certain users or teams to query the data source.\n\nYou need to have a permission with action `datasources.permissions:toggle` and scopes `datasources:*`, `datasources:id:*`, `datasources:id:1` (single data source).", + "tags": ["datasource_permissions", "enterprise"], + "summary": "Enable permissions for a data source.", + "operationId": "enablePermissions", + "parameters": [ + { + "type": "string", + "x-go-name": "DatasourceID", + "name": "datasource_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/createOrUpdateDatasourceResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/datasources/{datasource_id}/permissions": { + "get": { + "description": "Gets all existing permissions for the data source with the given id.\n\nYou need to have a permission with action `datasources.permissions:read` and scopes `datasources:*`, `datasources:id:*`, `datasources:id:1` (single data source).", + "tags": ["datasource_permissions", "enterprise"], + "summary": "Get permissions for a data source.", + "operationId": "getPermissions", + "parameters": [ + { + "type": "string", + "x-go-name": "DatasourceID", + "name": "datasource_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/getPermissionseResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/datasources/{datasource_id}/permissions/{permissionId}": { + "delete": { + "description": "Removes the permission with the given permissionId for the data source with the given id.\n\nYou need to have a permission with action `datasources.permissions:delete` and scopes `datasources:*`, `datasources:id:*`, `datasources:id:1` (single data source).", + "tags": ["datasource_permissions", "enterprise"], + "summary": "Remove permission for a data source.", + "operationId": "deletePermissions", + "parameters": [ + { + "type": "string", + "x-go-name": "PermissionID", + "name": "permissionId", + "in": "path", + "required": true + }, + { + "type": "string", + "x-go-name": "DatasourceID", + "name": "datasource_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, "/ds/query": { "post": { "description": "If you are running Grafana Enterprise and have Fine-grained access control enabled\nyou need to have a permission with action: `datasources:query`.", @@ -4407,6 +5166,208 @@ } } }, + "/licensing/check": { + "get": { + "tags": ["licensing", "enterprise"], + "summary": "Check license availability.", + "operationId": "getLicenseStatus", + "responses": { + "200": { + "$ref": "#/responses/getLicenseStatusResponse" + } + } + } + }, + "/licensing/custom-permissions": { + "get": { + "description": "You need to have a permission with action `licensing.reports:read`.", + "tags": ["licensing", "enterprise"], + "summary": "Get custom permissions report.", + "operationId": "getCustomPermissionsReport", + "responses": { + "200": { + "$ref": "#/responses/getCustomPermissionsReportResponse" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/licensing/custom-permissions-csv": { + "get": { + "description": "You need to have a permission with action `licensing.reports:read`.", + "produces": ["text/csv"], + "tags": ["licensing", "enterprise"], + "summary": "Get custom permissions report in CSV format.", + "operationId": "getCustomPermissionsCSV", + "responses": { + "200": { + "$ref": "#/responses/getCustomPermissionsReportResponse" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/licensing/refresh-stats": { + "get": { + "description": "You need to have a permission with action `licensing:read`.", + "tags": ["licensing", "enterprise"], + "summary": "Refresh license stats.", + "operationId": "refreshLicenseStats", + "responses": { + "200": { + "$ref": "#/responses/refreshLicenseStatsResponse" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/licensing/token": { + "get": { + "description": "You need to have a permission with action `licensing:read`.", + "tags": ["licensing", "enterprise"], + "summary": "Get license token.", + "operationId": "getLicenseToken", + "responses": { + "200": { + "$ref": "#/responses/getLicenseTokenResponse" + } + } + }, + "post": { + "description": "You need to have a permission with action `licensing:update`.", + "tags": ["licensing", "enterprise"], + "summary": "Create license token.", + "operationId": "postLicenseToken", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/DeleteTokenCommand" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/getLicenseTokenResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + } + } + }, + "delete": { + "description": "Removes the license stored in the Grafana database. Available in Grafana Enterprise v7.4+.\n\nYou need to have a permission with action `licensing:delete`.", + "tags": ["licensing", "enterprise"], + "summary": "Remove license from database.", + "operationId": "deleteLicenseToken", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/DeleteTokenCommand" + } + } + ], + "responses": { + "202": { + "$ref": "#/responses/acceptedResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "422": { + "$ref": "#/responses/unprocessableEntityError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/licensing/token/renew": { + "post": { + "description": "Manually ask license issuer for a new token. Available in Grafana Enterprise v7.4+.\n\nYou need to have a permission with action `licensing:update`.", + "tags": ["licensing", "enterprise"], + "summary": "Manually force license refresh.", + "operationId": "postRenewLicenseToken", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/postRenewLicenseTokenResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "404": { + "$ref": "#/responses/notFoundError" + } + } + } + }, + "/login/saml": { + "get": { + "tags": ["saml", "enterprise"], + "summary": "It initiates the login flow by redirecting the user to the IdP.", + "operationId": "getSAMLLogin", + "responses": { + "302": { + "description": "" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/logout/saml": { + "get": { + "tags": ["saml", "enterprise"], + "summary": "GetLogout initiates single logout process.", + "operationId": "getSAMLLogout", + "responses": { + "302": { + "description": "" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, "/org": { "get": { "description": "Get current Organization", @@ -4605,6 +5566,39 @@ "$ref": "#/responses/internalServerError" } } + }, + "patch": { + "tags": ["org_preferences"], + "summary": "Patch Current Org Prefs.", + "operationId": "patchOrgPreferences", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PatchPrefsCmd" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/addOrgUser" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } } }, "/org/users": { @@ -5475,6 +6469,594 @@ } } }, + "/recording-rules": { + "get": { + "tags": ["recording_rules", "enterprise"], + "summary": "Get all recording rules.", + "operationId": "listRecordingRules", + "responses": { + "200": { + "$ref": "#/responses/listRecordingRulesResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "put": { + "tags": ["recording_rules", "enterprise"], + "summary": "Update a recording rule.", + "operationId": "updateRecordingRule", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/RecordingRuleJSON" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/recordingRuleResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "tags": ["recording_rules", "enterprise"], + "summary": "Create a new recording rule.", + "operationId": "createRecordingRule", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/RecordingRuleJSON" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/recordingRuleResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/recording-rules/test": { + "post": { + "tags": ["recording_rules", "enterprise"], + "summary": "Test a recording rule.", + "operationId": "testCreateRecordingRule", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/RecordingRuleJSON" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "422": { + "$ref": "#/responses/unprocessableEntityError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/recording-rules/writer": { + "get": { + "tags": ["recording_rules", "enterprise"], + "summary": "Get the write target.", + "operationId": "getRecordingRuleWriteTarget", + "responses": { + "200": { + "$ref": "#/responses/recordingRuleWriteTargetResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "tags": ["recording_rules", "enterprise"], + "summary": "Create a new write target.", + "operationId": "createRecordingRuleWriteTarget", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PrometheusRemoteWriteTargetJSON" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/recordingRuleWriteTargetResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "422": { + "$ref": "#/responses/unprocessableEntityError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "delete": { + "tags": ["recording_rules", "enterprise"], + "summary": "Delete the write target.", + "operationId": "deleteRecordingRuleWriteTarget", + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/recording-rules/{recordingRuleID}": { + "delete": { + "tags": ["recording_rules", "enterprise"], + "summary": "Delete a recording rule.", + "operationId": "deleteRecordingRule", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "RecordingRuleID", + "name": "recordingRuleID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/reports": { + "get": { + "description": "Available to org admins only and with a valid or expired license\n\nYou need to have a permission with action `reports:read` with scope `reports:*`.", + "tags": ["reports", "enterprise"], + "summary": "List reports.", + "operationId": "getReports", + "responses": { + "200": { + "$ref": "#/responses/getReportsResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "description": "Available to org admins only and with a valid license.\n\nYou need to have a permission with action `reports.admin:create`.", + "tags": ["reports", "enterprise"], + "summary": "Create a report.", + "operationId": "createReport", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateOrUpdateConfigCmd" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/createReportResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/reports/email": { + "post": { + "description": "Generate and send a report. This API waits for the report to be generated before returning. We recommend that you set the client’s timeout to at least 60 seconds. Available to org admins only and with a valid license.\n\nOnly available in Grafana Enterprise v7.0+.\nThis API endpoint is experimental and may be deprecated in a future release. On deprecation, a migration strategy will be provided and the endpoint will remain functional until the next major release of Grafana.\n\nYou need to have a permission with action `reports:send`.", + "tags": ["reports", "enterprise"], + "summary": "Send a report.", + "operationId": "sendReport", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ReportEmailDTO" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/reports/render/pdf/{DashboardID}": { + "get": { + "description": "Available to all users and with a valid license.", + "produces": ["application/pdf"], + "tags": ["reports", "enterprise"], + "summary": "Render report for dashboard.", + "operationId": "renderReportPDF", + "parameters": [ + { + "type": "integer", + "format": "int64", + "name": "DashboardID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/contentResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/reports/settings": { + "get": { + "description": "Available to org admins only and with a valid or expired license\n\nYou need to have a permission with action `reports.settings:read`x.", + "tags": ["reports", "enterprise"], + "summary": "Get settings.", + "operationId": "getReportSettings", + "responses": { + "200": { + "$ref": "#/responses/getReportSettingsResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "description": "Available to org admins only and with a valid or expired license\n\nYou need to have a permission with action `reports.settings:write`xx.", + "tags": ["reports", "enterprise"], + "summary": "Save settings.", + "operationId": "saveReportSettings", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SettingsDTO" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/reports/test-email": { + "post": { + "description": "Available to org admins only and with a valid license.\n\nYou need to have a permission with action `reports:send`.", + "tags": ["reports", "enterprise"], + "summary": "Send test report via email.", + "operationId": "sendTestEmail", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateOrUpdateConfigCmd" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/reports/{reportID}": { + "get": { + "description": "Available to org admins only and with a valid or expired license\n\nYou need to have a permission with action `reports:read` with scope `reports:id:\u003creport ID\u003e`.", + "tags": ["reports", "enterprise"], + "summary": "Get a report.", + "operationId": "getReport", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "ReportID", + "name": "reportID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/getReportResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "put": { + "description": "Available to org admins only and with a valid or expired license\n\nYou need to have a permission with action `reports.admin:write` with scope `reports:id:\u003creport ID\u003e`.", + "tags": ["reports", "enterprise"], + "summary": "Update a report.", + "operationId": "updateReport", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "ReportID", + "name": "reportID", + "in": "path", + "required": true + }, + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateOrUpdateConfigCmd" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "delete": { + "description": "Available to org admins only and with a valid or expired license\n\nYou need to have a permission with action `reports.delete` with scope `reports:id:\u003creport ID\u003e`.", + "tags": ["reports", "enterprise"], + "summary": "Delete a report.", + "operationId": "deleteReport", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "ReportID", + "name": "reportID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, "/ruler/grafana/api/v1/rules": { "get": { "description": "List rule groups", @@ -5843,6 +7425,77 @@ } } }, + "/saml/acs": { + "post": { + "tags": ["saml", "enterprise"], + "summary": "It performs assertion Consumer Service (ACS).", + "operationId": "postACS", + "parameters": [ + { + "type": "string", + "name": "RelayState", + "in": "query" + } + ], + "responses": { + "302": { + "description": "" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/saml/metadata": { + "get": { + "produces": ["application/xml;application/samlmetadata+xml"], + "tags": ["saml", "enterprise"], + "summary": "It exposes the SP (Grafana's) metadata for the IdP's consumption.", + "operationId": "getSAMLMetadata", + "responses": { + "200": { + "$ref": "#/responses/contentResponse" + } + } + } + }, + "/saml/slo": { + "post": { + "tags": ["saml", "enterprise"], + "summary": "It performs Single Logout (SLO) callback.", + "operationId": "postSLO", + "parameters": [ + { + "type": "string", + "name": "SAMLRequest", + "in": "query" + }, + { + "type": "string", + "name": "SAMLResponse", + "in": "query" + } + ], + "responses": { + "302": { + "description": "" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, "/search": { "get": { "tags": ["search"], @@ -6194,6 +7847,132 @@ } } }, + "/teams/{teamId}/groups": { + "get": { + "tags": ["sync_team_groups", "enterprise"], + "summary": "Get External Groups.", + "operationId": "getTeamGroupsApi", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/getTeamGroupsApiResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "tags": ["sync_team_groups", "enterprise"], + "summary": "Add External Group.", + "operationId": "addTeamGroupApi", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/TeamGroupMapping" + } + }, + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/teams/{teamId}/groups/{groupId}": { + "delete": { + "tags": ["sync_team_groups", "enterprise"], + "summary": "Remove External Group.", + "operationId": "removeTeamGroupApi", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "GroupID", + "name": "groupId", + "in": "path", + "required": true + }, + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, "/teams/{team_id}": { "get": { "tags": ["teams"], @@ -6800,6 +8579,36 @@ "$ref": "#/responses/internalServerError" } } + }, + "patch": { + "tags": ["user_preferences"], + "summary": "Patch user preferences.", + "operationId": "patchUserPreferences", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PatchPrefsCmd" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } } }, "/user/quotas": { @@ -7417,6 +9226,50 @@ "type": "object", "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, + "ActiveSyncStatusDTO": { + "description": "ActiveSyncStatusDTO holds the information for LDAP background Sync", + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "x-go-name": "Enabled" + }, + "nextSync": { + "type": "string", + "format": "date-time", + "x-go-name": "NextSync" + }, + "prevSync": { + "$ref": "#/definitions/SyncResult" + }, + "schedule": { + "type": "string", + "x-go-name": "Schedule" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/ldapdebug" + }, + "ActiveUserStats": { + "type": "object", + "properties": { + "active_admins_and_editors": { + "type": "integer", + "format": "int64", + "x-go-name": "ActiveAdminsAndEditors" + }, + "active_users": { + "type": "integer", + "format": "int64", + "x-go-name": "ActiveUsers" + }, + "active_viewers": { + "type": "integer", + "format": "int64", + "x-go-name": "ActiveViewers" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/licensing" + }, "AddApiKeyCommand": { "description": "COMMANDS", "type": "object", @@ -7436,6 +9289,26 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "AddBuiltInRoleCommand": { + "type": "object", + "properties": { + "builtInRole": { + "type": "string", + "enum": ["Viewer", " Editor", " Admin", " Grafana Admin"], + "x-go-name": "BuiltinRole" + }, + "global": { + "description": "A flag indicating if the assignment is global or not. If set to false, the default org ID of the authenticated user will be used from the request to create organization local assignment. Refer to the Built-in role assignments for more information.", + "type": "boolean", + "x-go-name": "Global" + }, + "roleUid": { + "type": "string", + "x-go-name": "RoleUID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, "AddDataSourceCommand": { "description": "Also acts as api DTO", "type": "object", @@ -7538,6 +9411,29 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "AddPermissionDTO": { + "type": "object", + "properties": { + "builtinRole": { + "type": "string", + "x-go-name": "BuiltinRole" + }, + "permission": { + "$ref": "#/definitions/DsPermissionType" + }, + "teamId": { + "type": "integer", + "format": "int64", + "x-go-name": "TeamId" + }, + "userId": { + "type": "integer", + "format": "int64", + "x-go-name": "UserId" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/dspermissions" + }, "AddTeamMemberCommand": { "type": "object", "properties": { @@ -7549,6 +9445,30 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "AddTeamRoleCommand": { + "type": "object", + "properties": { + "roleUid": { + "type": "string", + "x-go-name": "RoleUID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, + "AddUserRoleCommand": { + "type": "object", + "properties": { + "global": { + "type": "boolean", + "x-go-name": "Global" + }, + "roleUid": { + "type": "string", + "x-go-name": "RoleUID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, "Address": { "type": "object", "properties": { @@ -8295,6 +10215,32 @@ }, "x-go-package": "github.com/prometheus/common/config" }, + "BrandingOptionsDTO": { + "type": "object", + "properties": { + "emailFooterLink": { + "type": "string", + "x-go-name": "EmailFooterLink" + }, + "emailFooterMode": { + "type": "string", + "x-go-name": "EmailFooterMode" + }, + "emailFooterText": { + "type": "string", + "x-go-name": "EmailFooterText" + }, + "emailLogoUrl": { + "type": "string", + "x-go-name": "EmailLogo" + }, + "reportLogoUrl": { + "type": "string", + "x-go-name": "ReportLogo" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, "CalculateDiffTarget": { "type": "object", "properties": { @@ -8362,6 +10308,89 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, + "ConfigDTO": { + "description": "ConfigDTO is model representation in transfer", + "type": "object", + "properties": { + "created": { + "type": "string", + "format": "date-time", + "x-go-name": "Created" + }, + "dashboardId": { + "type": "integer", + "format": "int64", + "x-go-name": "DashboardID" + }, + "dashboardName": { + "type": "string", + "x-go-name": "DashboardName" + }, + "dashboardUid": { + "type": "string", + "x-go-name": "DashboardUID" + }, + "enableCsv": { + "type": "boolean", + "x-go-name": "EnableCSV" + }, + "enableDashboardUrl": { + "type": "boolean", + "x-go-name": "EnableDashboardURL" + }, + "id": { + "type": "integer", + "format": "int64", + "x-go-name": "ID" + }, + "message": { + "type": "string", + "x-go-name": "Message" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "options": { + "$ref": "#/definitions/ReportOptionsDTO" + }, + "orgId": { + "type": "integer", + "format": "int64", + "x-go-name": "OrgID" + }, + "recipients": { + "type": "string", + "x-go-name": "Recipients" + }, + "replyTo": { + "type": "string", + "x-go-name": "ReplyTo" + }, + "schedule": { + "$ref": "#/definitions/ScheduleDTO" + }, + "state": { + "type": "string", + "x-go-name": "State" + }, + "templateVars": { + "type": "object", + "x-go-name": "TemplateVars" + }, + "updated": { + "type": "string", + "format": "date-time", + "x-go-name": "Updated" + }, + "userId": { + "type": "integer", + "format": "int64", + "x-go-name": "UserID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, "CreateAlertNotificationCommand": { "type": "object", "properties": { @@ -8495,6 +10524,59 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/services/libraryelements" }, + "CreateOrUpdateConfigCmd": { + "type": "object", + "properties": { + "dashboardId": { + "type": "integer", + "format": "int64", + "x-go-name": "DashboardID" + }, + "dashboardUid": { + "type": "string", + "x-go-name": "DashboardUID" + }, + "enableCsv": { + "type": "boolean", + "x-go-name": "EnableCSV" + }, + "enableDashboardUrl": { + "type": "boolean", + "x-go-name": "EnableDashboardURL" + }, + "message": { + "type": "string", + "x-go-name": "Message" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "options": { + "$ref": "#/definitions/ReportOptionsDTO" + }, + "recipients": { + "type": "string", + "x-go-name": "Recipients" + }, + "replyTo": { + "type": "string", + "x-go-name": "ReplyTo" + }, + "schedule": { + "$ref": "#/definitions/ScheduleDTO" + }, + "state": { + "type": "string", + "x-go-name": "State" + }, + "templateVars": { + "type": "object", + "x-go-name": "TemplateVars" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, "CreateOrgCommand": { "type": "object", "properties": { @@ -8505,6 +10587,48 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "CreateRoleWithPermissionsCommand": { + "type": "object", + "properties": { + "description": { + "type": "string", + "x-go-name": "Description" + }, + "displayName": { + "type": "string", + "x-go-name": "DisplayName" + }, + "group": { + "type": "string", + "x-go-name": "Group" + }, + "hidden": { + "type": "boolean", + "x-go-name": "Hidden" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "permissions": { + "type": "array", + "items": { + "$ref": "#/definitions/Permission" + }, + "x-go-name": "Permissions" + }, + "uid": { + "type": "string", + "x-go-name": "UID" + }, + "version": { + "type": "integer", + "format": "int64", + "x-go-name": "Version" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, "CreateTeamCommand": { "type": "object", "properties": { @@ -8519,6 +10643,67 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "CustomPermissionsRecordDTO": { + "type": "object", + "properties": { + "customPermissions": { + "type": "string", + "x-go-name": "CustomPermissions" + }, + "granteeName": { + "type": "string", + "x-go-name": "GranteeName" + }, + "granteeType": { + "type": "string", + "x-go-name": "GranteeType" + }, + "granteeUrl": { + "type": "string", + "x-go-name": "GranteeURL" + }, + "id": { + "type": "integer", + "format": "int64", + "x-go-name": "ID" + }, + "isFolder": { + "type": "boolean", + "x-go-name": "IsFolder" + }, + "orgId": { + "type": "integer", + "format": "int64", + "x-go-name": "OrgID" + }, + "orgRole": { + "type": "string", + "x-go-name": "OrgRole" + }, + "slug": { + "type": "string", + "x-go-name": "Slug" + }, + "title": { + "type": "string", + "x-go-name": "Title" + }, + "uid": { + "type": "string", + "x-go-name": "UID" + }, + "url": { + "type": "string", + "x-go-name": "URL" + }, + "usersCount": { + "type": "integer", + "format": "int64", + "x-go-name": "UsersCount" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/licensing" + }, "DashboardAclInfoDTO": { "type": "object", "properties": { @@ -9339,6 +11524,16 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" }, + "DeleteTokenCommand": { + "type": "object", + "properties": { + "instance": { + "type": "string", + "x-go-name": "Instance" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/licensing" + }, "DiscoveryBase": { "type": "object", "required": ["status"], @@ -9557,6 +11752,19 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, + "FailedUser": { + "description": "FailedUser holds the information of an user that failed", + "type": "object", + "properties": { + "Error": { + "type": "string" + }, + "Login": { + "type": "string" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/ldapsync" + }, "Failure": { "$ref": "#/definitions/ResponseDetails" }, @@ -10957,6 +13165,41 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" }, + "NavLink": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-go-name": "Id" + }, + "target": { + "type": "string", + "x-go-name": "Target" + }, + "text": { + "type": "string", + "x-go-name": "Text" + }, + "url": { + "type": "string", + "x-go-name": "Url" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/models" + }, + "NavbarPreference": { + "type": "object", + "properties": { + "savedItems": { + "type": "array", + "items": { + "$ref": "#/definitions/NavLink" + }, + "x-go-name": "SavedItems" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/models" + }, "NewApiKeyResult": { "type": "object", "properties": { @@ -11432,6 +13675,36 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/services/libraryelements" }, + "PatchPrefsCmd": { + "type": "object", + "properties": { + "homeDashboardId": { + "description": "The numerical :id of a favorited dashboard", + "type": "integer", + "format": "int64", + "default": 0, + "x-go-name": "HomeDashboardID" + }, + "navbar": { + "$ref": "#/definitions/NavbarPreference" + }, + "theme": { + "type": "string", + "enum": ["light", "dark"], + "x-go-name": "Theme" + }, + "timezone": { + "type": "string", + "enum": ["utc", "browser"], + "x-go-name": "Timezone" + }, + "weekStart": { + "type": "string", + "x-go-name": "WeekStart" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" + }, "PauseAlertCommand": { "type": "object", "properties": { @@ -11457,6 +13730,31 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" }, + "Permission": { + "type": "object", + "title": "Permission is the model for access control permissions.", + "properties": { + "action": { + "type": "string", + "x-go-name": "Action" + }, + "created": { + "type": "string", + "format": "date-time", + "x-go-name": "Created" + }, + "scope": { + "type": "string", + "x-go-name": "Scope" + }, + "updated": { + "type": "string", + "format": "date-time", + "x-go-name": "Updated" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/services/accesscontrol" + }, "PermissionDenied": { "type": "object", "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" @@ -11849,6 +14147,9 @@ "format": "int64", "x-go-name": "HomeDashboardID" }, + "navbar": { + "$ref": "#/definitions/NavbarPreference" + }, "theme": { "type": "string", "x-go-name": "Theme" @@ -11864,6 +14165,24 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" }, + "PrometheusRemoteWriteTargetJSON": { + "type": "object", + "properties": { + "data_source_uid": { + "type": "string", + "x-go-name": "DatasourceUID" + }, + "id": { + "type": "string", + "x-go-name": "ID" + }, + "remote_write_path": { + "type": "string", + "x-go-name": "WritePath" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/recordedqueries/api" + }, "PushoverConfig": { "type": "object", "properties": { @@ -12003,6 +14322,65 @@ }, "x-go-package": "github.com/prometheus/alertmanager/config" }, + "RecordingRuleJSON": { + "description": "RecordingRuleJSON is the external representation of a recording rule", + "type": "object", + "properties": { + "active": { + "type": "boolean", + "x-go-name": "Active" + }, + "count": { + "type": "boolean", + "x-go-name": "Count" + }, + "description": { + "type": "string", + "x-go-name": "Description" + }, + "dest_data_source_uid": { + "type": "string", + "x-go-name": "DestDataSourceUID" + }, + "id": { + "type": "string", + "x-go-name": "ID" + }, + "interval": { + "type": "integer", + "format": "int64", + "x-go-name": "Interval" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "prom_name": { + "type": "string", + "x-go-name": "PromName" + }, + "queries": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "x-go-name": "Queries" + }, + "range": { + "type": "integer", + "format": "int64", + "x-go-name": "Range" + }, + "target_ref_id": { + "type": "string", + "x-go-name": "TargetRefID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/recordedqueries/api" + }, "Regexp": { "description": "A Regexp is safe for concurrent use by multiple goroutines,\nexcept for configuration methods, such as Longest.", "type": "object", @@ -12022,6 +14400,49 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/services/ngalert/models" }, + "ReportEmailDTO": { + "type": "object", + "properties": { + "email": { + "type": "string", + "x-go-name": "Email" + }, + "emails": { + "description": "Comma-separated list of emails to which to send the report to.", + "type": "string", + "x-go-name": "Emails" + }, + "id": { + "description": "Send the report to the emails specified in the report. Required if emails is not present.", + "type": "string", + "format": "int64", + "x-go-name": "Id" + }, + "useEmailsFromReport": { + "description": "Send the report to the emails specified in the report. Required if emails is not present.", + "type": "boolean", + "x-go-name": "UseEmailsFromReport" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, + "ReportOptionsDTO": { + "type": "object", + "properties": { + "layout": { + "type": "string", + "x-go-name": "Layout" + }, + "orientation": { + "type": "string", + "x-go-name": "Orientation" + }, + "timeRange": { + "$ref": "#/definitions/TimeRangeDTO" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, "ResponseDetails": { "type": "object", "properties": { @@ -12052,6 +14473,62 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "RoleDTO": { + "type": "object", + "properties": { + "created": { + "type": "string", + "format": "date-time", + "x-go-name": "Created" + }, + "delegatable": { + "type": "boolean", + "x-go-name": "Delegatable" + }, + "description": { + "type": "string", + "x-go-name": "Description" + }, + "displayName": { + "type": "string", + "x-go-name": "DisplayName" + }, + "group": { + "type": "string", + "x-go-name": "Group" + }, + "hidden": { + "type": "boolean", + "x-go-name": "Hidden" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "permissions": { + "type": "array", + "items": { + "$ref": "#/definitions/Permission" + }, + "x-go-name": "Permissions" + }, + "uid": { + "type": "string", + "x-go-name": "UID" + }, + "updated": { + "type": "string", + "format": "date-time", + "x-go-name": "Updated" + }, + "version": { + "type": "integer", + "format": "int64", + "x-go-name": "Version" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/services/accesscontrol" + }, "RoleType": { "type": "string", "x-go-package": "github.com/grafana/grafana/pkg/models" @@ -12367,6 +14844,61 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "ScheduleDTO": { + "type": "object", + "properties": { + "day": { + "type": "string", + "x-go-name": "Day" + }, + "dayOfMonth": { + "type": "string", + "x-go-name": "DayOfMonth" + }, + "endDate": { + "type": "string", + "format": "date-time", + "x-go-name": "EndDate" + }, + "frequency": { + "type": "string", + "x-go-name": "Frequency" + }, + "hour": { + "type": "integer", + "format": "int64", + "x-go-name": "Hour" + }, + "intervalAmount": { + "type": "integer", + "format": "int64", + "x-go-name": "IntervalAmount" + }, + "intervalFrequency": { + "type": "string", + "x-go-name": "IntervalFrequency" + }, + "minute": { + "type": "integer", + "format": "int64", + "x-go-name": "Minute" + }, + "startDate": { + "type": "string", + "format": "date-time", + "x-go-name": "StartDate" + }, + "timeZone": { + "type": "string", + "x-go-name": "TimeZone" + }, + "workdaysOnly": { + "type": "boolean", + "x-go-name": "WorkdaysOnly" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, "SearchTeamQueryResult": { "type": "object", "properties": { @@ -12432,6 +14964,27 @@ "title": "SecretURL is a URL that must not be revealed on marshaling.", "$ref": "#/definitions/URL" }, + "SetUserRolesCommand": { + "type": "object", + "properties": { + "global": { + "type": "boolean", + "x-go-name": "Global" + }, + "includeHidden": { + "type": "boolean", + "x-go-name": "IncludeHidden" + }, + "roleUids": { + "type": "array", + "items": { + "type": "string" + }, + "x-go-name": "RoleUIDs" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, "SettingsBag": { "type": "object", "additionalProperties": { @@ -12442,6 +14995,30 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/setting" }, + "SettingsDTO": { + "type": "object", + "properties": { + "branding": { + "$ref": "#/definitions/BrandingOptionsDTO" + }, + "id": { + "type": "integer", + "format": "int64", + "x-go-name": "ID" + }, + "orgId": { + "type": "integer", + "format": "int64", + "x-go-name": "OrgID" + }, + "userId": { + "type": "integer", + "format": "int64", + "x-go-name": "UserID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, "SigV4Config": { "description": "SigV4Config is the configuration for signing remote write requests with\nAWS's SigV4 verification process. Empty values will be retrieved using the\nAWS default credentials chain.", "type": "object", @@ -12652,6 +15229,16 @@ "SmtpNotEnabled": { "$ref": "#/definitions/ResponseDetails" }, + "Status": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "x-go-name": "Enabled" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, "Success": { "$ref": "#/definitions/ResponseDetails" }, @@ -12665,6 +15252,40 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/api/docs/definitions" }, + "SyncResult": { + "type": "object", + "title": "SyncResult holds the result of a sync with LDAP. This gives us information on which users were updated and how.", + "properties": { + "Elapsed": { + "$ref": "#/definitions/Duration" + }, + "FailedUsers": { + "type": "array", + "items": { + "$ref": "#/definitions/FailedUser" + } + }, + "MissingUserIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + } + }, + "Started": { + "type": "string", + "format": "date-time" + }, + "UpdatedUserIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + } + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/ldapsync" + }, "TLSConfig": { "type": "object", "title": "TLSConfig configures the options for TLS connections.", @@ -12756,6 +15377,36 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "TeamGroupDTO": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "x-go-name": "GroupId" + }, + "orgId": { + "type": "integer", + "format": "int64", + "x-go-name": "OrgId" + }, + "teamId": { + "type": "integer", + "format": "int64", + "x-go-name": "TeamId" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/teamgroupsync/models" + }, + "TeamGroupMapping": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "x-go-name": "GroupId" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/teamgroupsync/models" + }, "TeamMemberDTO": { "type": "object", "properties": { @@ -13047,6 +15698,136 @@ }, "x-go-package": "github.com/prometheus/alertmanager/timeinterval" }, + "TimeRangeDTO": { + "type": "object", + "properties": { + "from": { + "type": "string", + "x-go-name": "From" + }, + "to": { + "type": "string", + "x-go-name": "To" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, + "Token": { + "type": "object", + "properties": { + "account": { + "type": "string", + "x-go-name": "Account" + }, + "company": { + "type": "string", + "x-go-name": "Company" + }, + "details_url": { + "type": "string", + "x-go-name": "DetailsUrl" + }, + "exp": { + "type": "integer", + "format": "int64", + "x-go-name": "Expires" + }, + "iat": { + "type": "integer", + "format": "int64", + "x-go-name": "Issued" + }, + "included_admins": { + "type": "integer", + "format": "int64", + "x-go-name": "IncludedAdmins" + }, + "included_users": { + "type": "integer", + "format": "int64", + "x-go-name": "IncludedUsers" + }, + "included_viewers": { + "type": "integer", + "format": "int64", + "x-go-name": "IncludedViewers" + }, + "iss": { + "type": "string", + "x-go-name": "Issuer" + }, + "jti": { + "type": "string", + "x-go-name": "Id" + }, + "lexp": { + "type": "integer", + "format": "int64", + "x-go-name": "LicenseExpires" + }, + "lic_exp_warn_days": { + "type": "integer", + "format": "int64", + "x-go-name": "LicenseExpiresWarnDays" + }, + "lid": { + "type": "string", + "x-go-name": "LicenseId" + }, + "limit_by": { + "type": "string", + "x-go-name": "LimitBy" + }, + "max_concurrent_user_sessions": { + "type": "integer", + "format": "int64", + "x-go-name": "MaxConcurrentUserSessions" + }, + "nbf": { + "type": "integer", + "format": "int64", + "x-go-name": "LicenseIssued" + }, + "prod": { + "type": "array", + "items": { + "type": "string" + }, + "x-go-name": "Products" + }, + "slug": { + "type": "string", + "x-go-name": "Slug" + }, + "status": { + "$ref": "#/definitions/TokenStatus" + }, + "sub": { + "type": "string", + "x-go-name": "Subject" + }, + "tok_exp_warn_days": { + "type": "integer", + "format": "int64", + "x-go-name": "TokenExpiresWarnDays" + }, + "update_days": { + "type": "integer", + "format": "int64", + "x-go-name": "UpdateDays" + }, + "usage_billing": { + "type": "boolean", + "x-go-name": "UsageBilling" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/licensing" + }, + "TokenStatus": { + "type": "integer", + "format": "int64", + "x-go-package": "github.com/grafana/grafana/pkg/extensions/licensing" + }, "TrimDashboardCommand": { "type": "object", "properties": { @@ -13417,6 +16198,9 @@ "default": 0, "x-go-name": "HomeDashboardID" }, + "navbar": { + "$ref": "#/definitions/NavbarPreference" + }, "theme": { "type": "string", "enum": ["light", "dark"], @@ -13434,6 +16218,48 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" }, + "UpdateRoleCommand": { + "type": "object", + "properties": { + "description": { + "type": "string", + "x-go-name": "Description" + }, + "displayName": { + "type": "string", + "x-go-name": "DisplayName" + }, + "global": { + "type": "boolean", + "x-go-name": "Global" + }, + "group": { + "type": "string", + "x-go-name": "Group" + }, + "hidden": { + "type": "boolean", + "x-go-name": "Hidden" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "permissions": { + "type": "array", + "items": { + "$ref": "#/definitions/Permission" + }, + "x-go-name": "Permissions" + }, + "version": { + "type": "integer", + "format": "int64", + "x-go-name": "Version" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, "UpdateTeamCommand": { "type": "object", "properties": { @@ -14485,6 +17311,16 @@ "$ref": "#/definitions/ErrorResponseBody" } }, + "contentResponse": { + "description": "", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8" + } + } + }, "createAnnotationResponse": { "description": "", "schema": { @@ -14559,6 +17395,12 @@ } } }, + "createReportResponse": { + "description": "", + "schema": { + "type": "object" + } + }, "createSnapshotResponse": { "description": "", "schema": { @@ -14780,6 +17622,12 @@ } } }, + "getAccessControlStatusResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/Status" + } + }, "getAlertNotificationChannelResponse": { "description": "", "schema": { @@ -14813,6 +17661,15 @@ } } }, + "getAllRolesResponse": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/RoleDTO" + } + } + }, "getAnnotationTagsResponse": { "description": "", "schema": { @@ -14837,6 +17694,15 @@ } } }, + "getCustomPermissionsReportResponse": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/CustomPermissionsRecordDTO" + } + } + }, "getDashboardPermissionsResponse": { "description": "", "schema": { @@ -14907,6 +17773,12 @@ } } }, + "getLDAPSyncStatusResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/ActiveSyncStatusDTO" + } + }, "getLibraryElementConnectionsResponse": { "description": "", "schema": { @@ -14925,6 +17797,15 @@ "$ref": "#/definitions/LibraryElementSearchResponse" } }, + "getLicenseStatusResponse": { + "description": "" + }, + "getLicenseTokenResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/Token" + } + }, "getOrgResponse": { "description": "", "schema": { @@ -14940,6 +17821,12 @@ } } }, + "getPermissionseResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/AddPermissionDTO" + } + }, "getPreferencesResponse": { "description": "", "schema": { @@ -14955,6 +17842,33 @@ } } }, + "getReportResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/ConfigDTO" + } + }, + "getReportSettingsResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/SettingsDTO" + } + }, + "getReportsResponse": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ConfigDTO" + } + } + }, + "getRoleResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/RoleDTO" + } + }, "getSettingsResponse": { "description": "", "schema": { @@ -14996,6 +17910,15 @@ "$ref": "#/definitions/AdminStats" } }, + "getTeamGroupsApiResponse": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/TeamGroupDTO" + } + } + }, "getTeamMembersResponse": { "description": "", "schema": { @@ -15058,6 +17981,27 @@ "$ref": "#/definitions/ErrorResponseBody" } }, + "listBuiltinRolesResponse": { + "description": "", + "schema": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/RoleDTO" + } + } + } + }, + "listRecordingRulesResponse": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/RecordingRuleJSON" + } + } + }, "lookupAlertNotificationChannelsResponse": { "description": "", "schema": { @@ -15187,6 +18131,9 @@ } } }, + "postRenewLicenseTokenResponse": { + "description": "" + }, "preconditionFailedError": { "description": "PreconditionFailedError", "schema": { @@ -15205,6 +18152,24 @@ "$ref": "#/definitions/DataResponse" } }, + "recordingRuleResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/RecordingRuleJSON" + } + }, + "recordingRuleWriteTargetResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/PrometheusRemoteWriteTargetJSON" + } + }, + "refreshLicenseStatsResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/ActiveUserStats" + } + }, "searchOrgResponse": { "description": "", "schema": { diff --git a/public/api-spec.json b/public/api-spec.json index 7338c39b31c..0f77b8f8555 100644 --- a/public/api-spec.json +++ b/public/api-spec.json @@ -19,6 +19,598 @@ }, "basePath": "/api", "paths": { + "/access-control/builtin-roles": { + "get": { + "description": "You need to have a permission with action `roles.builtin:list` with scope `roles:*`.", + "tags": ["access_control", "enterprise"], + "summary": "Get all built-in role assignments.", + "operationId": "listBuiltinRoles", + "responses": { + "200": { + "$ref": "#/responses/listBuiltinRolesResponse" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "description": "You need to have a permission with action `roles.builtin:add` and scope `permissions:delegate`. `permission:delegate` scope ensures that users can only create built-in role assignments with the roles which have same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to create a built-in role assignment which will allow to do that. This is done to prevent escalation of privileges.", + "tags": ["access_control", "enterprise"], + "summary": "Create a built-in role assignment.", + "operationId": "addBuiltinRole", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/AddBuiltInRoleCommand" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/builtin-roles/{builtinRole}/roles/{roleUID}": { + "delete": { + "description": "Deletes a built-in role assignment (for one of Viewer, Editor, Admin, or Grafana Admin) to the role with the provided UID.\n\nYou need to have a permission with action `roles.builtin:remove` and scope `permissions:delegate`. `permission:delegate` scope ensures that users can only remove built-in role assignments with the roles which have same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to remove a built-in role assignment which allows to do that.", + "tags": ["access_control", "enterprise"], + "summary": "Remove a built-in role assignment.", + "operationId": "removeBuiltinRole", + "parameters": [ + { + "type": "string", + "x-go-name": "RoleUID", + "name": "roleUID", + "in": "path", + "required": true + }, + { + "type": "string", + "x-go-name": "RoleUID", + "name": "builtinRole", + "in": "path", + "required": true + }, + { + "type": "boolean", + "x-go-name": "Global", + "description": "A flag indicating if the assignment is global or not. If set to false, the default org ID of the authenticated user will be used from the request to remove assignment.", + "name": "global", + "in": "query" + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/roles": { + "get": { + "description": "Gets all existing roles. The response contains all global and organization local roles, for the organization which user is signed in.\n\nYou need to have a permission with action `roles:list` and scope `roles:*`.", + "tags": ["access_control", "enterprise"], + "summary": "Get all roles.", + "operationId": "getAllRoles", + "responses": { + "200": { + "$ref": "#/responses/getAllRolesResponse" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "description": "Creates a new custom role and maps given permissions to that role. Note that roles with the same prefix as Fixed Roles can’t be created.\n\nYou need to have a permission with action `roles:write` and scope `permissions:delegate`. `permission:delegate`` scope ensures that users can only create custom roles with the same, or a subset of permissions which the user has.\nFor example, if a user does not have required permissions for creating users, they won’t be able to create a custom role which allows to do that. This is done to prevent escalation of privileges.", + "tags": ["access_control", "enterprise"], + "summary": "Create a new custom role.", + "operationId": "createRoleWithPermissions", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SetUserRolesCommand" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/getRoleResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/roles/{roleUID}": { + "get": { + "description": "Get a role for the given UID.\n\nYou need to have a permission with action `roles:read` and scope `roles:*`.", + "tags": ["access_control", "enterprise"], + "summary": "Get a role.", + "operationId": "getRole", + "parameters": [ + { + "type": "string", + "x-go-name": "RoleUID", + "name": "roleUID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/getRoleResponse" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "put": { + "description": "You need to have a permission with action `roles:write` and scope `permissions:delegate`. `permission:delegate`` scope ensures that users can only create custom roles with the same, or a subset of permissions which the user has.", + "tags": ["access_control", "enterprise"], + "summary": "Update a custom role.", + "operationId": "updateRoleWithPermissions", + "parameters": [ + { + "type": "string", + "x-go-name": "RoleUID", + "name": "roleUID", + "in": "path", + "required": true + }, + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateRoleCommand" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/getRoleResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "delete": { + "description": "Delete a role with the given UID, and it’s permissions. If the role is assigned to a built-in role, the deletion operation will fail, unless force query param is set to true, and in that case all assignments will also be deleted.\n\nYou need to have a permission with action `roles:delete` and scope `permissions:delegate`. `permission:delegate` scope ensures that users can only delete a custom role with the same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to delete a custom role which allows to do that.", + "tags": ["access_control", "enterprise"], + "summary": "Delete a custom role.", + "operationId": "deleteCustomRole", + "parameters": [ + { + "type": "string", + "x-go-name": "RoleUID", + "name": "roleUID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/status": { + "get": { + "description": "Returns an indicator to check if fine-grained access control is enabled or not.\n\nYou need to have a permission with action `status:accesscontrol` and scope `services:accesscontrol`.", + "tags": ["access_control", "enterprise"], + "summary": "Get status.", + "operationId": "getAccessControlStatus", + "responses": { + "200": { + "$ref": "#/responses/getAccessControlStatusResponse" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/teams/{teamId}/roles": { + "get": { + "description": "You need to have a permission with action `teams.roles:list` and scope `teams:id:\u003cteam ID\u003e`.", + "tags": ["access_control", "enterprise"], + "summary": "Get team roles.", + "operationId": "listTeamRoles", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "put": { + "description": "You need to have a permission with action `teams.roles:add` and `teams.roles:remove` and scope `permissions:delegate` for each.", + "tags": ["access_control", "enterprise"], + "summary": "Update team role.", + "operationId": "setTeamRoles", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "description": "You need to have a permission with action `teams.roles:add` and scope `permissions:delegate`.", + "tags": ["access_control", "enterprise"], + "summary": "Add team role.", + "operationId": "addTeamRole", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + }, + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/AddTeamRoleCommand" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/teams/{teamId}/roles/{roleUID}": { + "delete": { + "description": "You need to have a permission with action `teams.roles:remove` and scope `permissions:delegate`.", + "tags": ["access_control", "enterprise"], + "summary": "Remove team role.", + "operationId": "removeTeamRole", + "parameters": [ + { + "type": "string", + "x-go-name": "RoleUID", + "name": "roleUID", + "in": "path", + "required": true + }, + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/users/{user_id}/roles": { + "get": { + "description": "Lists the roles that have been directly assigned to a given user. The list does not include built-in roles (Viewer, Editor, Admin or Grafana Admin), and it does not include roles that have been inherited from a team.\n\nYou need to have a permission with action `users.roles:list` and scope `users:id:\u003cuser ID\u003e`.", + "tags": ["access_control", "enterprise"], + "summary": "List roles assigned to a user.", + "operationId": "listUserRoles", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "UserID", + "name": "user_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/getAllRolesResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "put": { + "description": "Update the user’s role assignments to match the provided set of UIDs. This will remove any assigned roles that aren’t in the request and add roles that are in the set but are not already assigned to the user.\nIf you want to add or remove a single role, consider using Add a user role assignment or Remove a user role assignment instead.\n\nYou need to have a permission with action `users.roles:add` and `users.roles:remove` and scope `permissions:delegate` for each. `permission:delegate` scope ensures that users can only assign or unassign roles which have same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to assign or unassign a role which will allow to do that. This is done to prevent escalation of privileges.", + "tags": ["access_control", "enterprise"], + "summary": "Set user role assignments.", + "operationId": "setUserRoles", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "UserID", + "name": "user_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "description": "Assign a role to a specific user. For bulk updates consider Set user role assignments.\n\nYou need to have a permission with action `users.roles:add` and scope `permissions:delegate`. `permission:delegate` scope ensures that users can only assign roles which have same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to assign a role which will allow to do that. This is done to prevent escalation of privileges.", + "tags": ["access_control", "enterprise"], + "summary": "Add a user role assignment.", + "operationId": "addUserRole", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/AddUserRoleCommand" + } + }, + { + "type": "integer", + "format": "int64", + "x-go-name": "UserID", + "name": "user_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/access-control/users/{user_id}/roles/{roleUID}": { + "delete": { + "description": "Revoke a role from a user. For bulk updates consider Set user role assignments.\n\nYou need to have a permission with action `users.roles:remove` and scope `permissions:delegate`. `permission:delegate` scope ensures that users can only unassign roles which have same, or a subset of permissions which the user has. For example, if a user does not have required permissions for creating users, they won’t be able to unassign a role which will allow to do that. This is done to prevent escalation of privileges.", + "tags": ["access_control", "enterprise"], + "summary": "Remove a user role assignment.", + "operationId": "removeUserRole", + "parameters": [ + { + "type": "string", + "x-go-name": "RoleUID", + "name": "roleUID", + "in": "path", + "required": true + }, + { + "type": "boolean", + "x-go-name": "Global", + "description": "A flag indicating if the assignment is global or not. If set to false, the default org ID of the authenticated user will be used from the request to remove assignment.", + "name": "global", + "in": "query" + }, + { + "type": "integer", + "format": "int64", + "x-go-name": "UserID", + "name": "user_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/admin/ldap-sync-status": { + "get": { + "description": "You need to have a permission with action `ldap.status:read`.", + "tags": ["ldap_debug"], + "summary": "Available to grafana admins.", + "operationId": "getLDAPSyncStatus", + "responses": { + "200": { + "$ref": "#/responses/getLDAPSyncStatusResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, "/admin/ldap/reload": { "post": { "security": [ @@ -183,6 +775,24 @@ } } }, + "/admin/provisioning/access-control/reload": { + "post": { + "tags": ["access_control_provisioning", "enterprise"], + "summary": "You need to have a permission with action `provisioning:reload` with scope `provisioners:accesscontrol`.", + "operationId": "adminProvisioningReloadAccessControl", + "responses": { + "202": { + "$ref": "#/responses/acceptedResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + } + } + } + }, "/admin/provisioning/accesscontrol/reload": { "post": { "security": [ @@ -2817,6 +3427,155 @@ } } }, + "/datasources/{datasource_id}/disable-permissions": { + "post": { + "description": "Disables permissions for the data source with the given id. All existing permissions will be removed and anyone will be able to query the data source.\n\nYou need to have a permission with action `datasources.permissions:toggle` and scopes `datasources:*`, `datasources:id:*`, `datasources:id:1` (single data source).", + "tags": ["datasource_permissions", "enterprise"], + "summary": "Disable permissions for a data source.", + "operationId": "disablePermissions", + "parameters": [ + { + "type": "string", + "x-go-name": "DatasourceID", + "name": "datasource_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/createOrUpdateDatasourceResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/datasources/{datasource_id}/enable-permissions": { + "post": { + "description": "Enables permissions for the data source with the given id.\nNo one except Org Admins will be able to query the data source until permissions have been added\nwhich permit certain users or teams to query the data source.\n\nYou need to have a permission with action `datasources.permissions:toggle` and scopes `datasources:*`, `datasources:id:*`, `datasources:id:1` (single data source).", + "tags": ["datasource_permissions", "enterprise"], + "summary": "Enable permissions for a data source.", + "operationId": "enablePermissions", + "parameters": [ + { + "type": "string", + "x-go-name": "DatasourceID", + "name": "datasource_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/createOrUpdateDatasourceResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/datasources/{datasource_id}/permissions": { + "get": { + "description": "Gets all existing permissions for the data source with the given id.\n\nYou need to have a permission with action `datasources.permissions:read` and scopes `datasources:*`, `datasources:id:*`, `datasources:id:1` (single data source).", + "tags": ["datasource_permissions", "enterprise"], + "summary": "Get permissions for a data source.", + "operationId": "getPermissions", + "parameters": [ + { + "type": "string", + "x-go-name": "DatasourceID", + "name": "datasource_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/getPermissionseResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/datasources/{datasource_id}/permissions/{permissionId}": { + "delete": { + "description": "Removes the permission with the given permissionId for the data source with the given id.\n\nYou need to have a permission with action `datasources.permissions:delete` and scopes `datasources:*`, `datasources:id:*`, `datasources:id:1` (single data source).", + "tags": ["datasource_permissions", "enterprise"], + "summary": "Remove permission for a data source.", + "operationId": "deletePermissions", + "parameters": [ + { + "type": "string", + "x-go-name": "PermissionID", + "name": "permissionId", + "in": "path", + "required": true + }, + { + "type": "string", + "x-go-name": "DatasourceID", + "name": "datasource_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, "/ds/query": { "post": { "description": "If you are running Grafana Enterprise and have Fine-grained access control enabled\nyou need to have a permission with action: `datasources:query`.", @@ -3457,6 +4216,208 @@ } } }, + "/licensing/check": { + "get": { + "tags": ["licensing", "enterprise"], + "summary": "Check license availability.", + "operationId": "getLicenseStatus", + "responses": { + "200": { + "$ref": "#/responses/getLicenseStatusResponse" + } + } + } + }, + "/licensing/custom-permissions": { + "get": { + "description": "You need to have a permission with action `licensing.reports:read`.", + "tags": ["licensing", "enterprise"], + "summary": "Get custom permissions report.", + "operationId": "getCustomPermissionsReport", + "responses": { + "200": { + "$ref": "#/responses/getCustomPermissionsReportResponse" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/licensing/custom-permissions-csv": { + "get": { + "description": "You need to have a permission with action `licensing.reports:read`.", + "produces": ["text/csv"], + "tags": ["licensing", "enterprise"], + "summary": "Get custom permissions report in CSV format.", + "operationId": "getCustomPermissionsCSV", + "responses": { + "200": { + "$ref": "#/responses/getCustomPermissionsReportResponse" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/licensing/refresh-stats": { + "get": { + "description": "You need to have a permission with action `licensing:read`.", + "tags": ["licensing", "enterprise"], + "summary": "Refresh license stats.", + "operationId": "refreshLicenseStats", + "responses": { + "200": { + "$ref": "#/responses/refreshLicenseStatsResponse" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/licensing/token": { + "get": { + "description": "You need to have a permission with action `licensing:read`.", + "tags": ["licensing", "enterprise"], + "summary": "Get license token.", + "operationId": "getLicenseToken", + "responses": { + "200": { + "$ref": "#/responses/getLicenseTokenResponse" + } + } + }, + "post": { + "description": "You need to have a permission with action `licensing:update`.", + "tags": ["licensing", "enterprise"], + "summary": "Create license token.", + "operationId": "postLicenseToken", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/DeleteTokenCommand" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/getLicenseTokenResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + } + } + }, + "delete": { + "description": "Removes the license stored in the Grafana database. Available in Grafana Enterprise v7.4+.\n\nYou need to have a permission with action `licensing:delete`.", + "tags": ["licensing", "enterprise"], + "summary": "Remove license from database.", + "operationId": "deleteLicenseToken", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/DeleteTokenCommand" + } + } + ], + "responses": { + "202": { + "$ref": "#/responses/acceptedResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "422": { + "$ref": "#/responses/unprocessableEntityError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/licensing/token/renew": { + "post": { + "description": "Manually ask license issuer for a new token. Available in Grafana Enterprise v7.4+.\n\nYou need to have a permission with action `licensing:update`.", + "tags": ["licensing", "enterprise"], + "summary": "Manually force license refresh.", + "operationId": "postRenewLicenseToken", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/postRenewLicenseTokenResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "404": { + "$ref": "#/responses/notFoundError" + } + } + } + }, + "/login/saml": { + "get": { + "tags": ["saml", "enterprise"], + "summary": "It initiates the login flow by redirecting the user to the IdP.", + "operationId": "getSAMLLogin", + "responses": { + "302": { + "description": "" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/logout/saml": { + "get": { + "tags": ["saml", "enterprise"], + "summary": "GetLogout initiates single logout process.", + "operationId": "getSAMLLogout", + "responses": { + "302": { + "description": "" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, "/org": { "get": { "description": "Get current Organization", @@ -3655,6 +4616,39 @@ "$ref": "#/responses/internalServerError" } } + }, + "patch": { + "tags": ["org_preferences"], + "summary": "Patch Current Org Prefs.", + "operationId": "patchOrgPreferences", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PatchPrefsCmd" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/addOrgUser" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } } }, "/org/users": { @@ -4412,6 +5406,665 @@ } } }, + "/recording-rules": { + "get": { + "tags": ["recording_rules", "enterprise"], + "summary": "Get all recording rules.", + "operationId": "listRecordingRules", + "responses": { + "200": { + "$ref": "#/responses/listRecordingRulesResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "put": { + "tags": ["recording_rules", "enterprise"], + "summary": "Update a recording rule.", + "operationId": "updateRecordingRule", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/RecordingRuleJSON" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/recordingRuleResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "tags": ["recording_rules", "enterprise"], + "summary": "Create a new recording rule.", + "operationId": "createRecordingRule", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/RecordingRuleJSON" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/recordingRuleResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/recording-rules/test": { + "post": { + "tags": ["recording_rules", "enterprise"], + "summary": "Test a recording rule.", + "operationId": "testCreateRecordingRule", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/RecordingRuleJSON" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "422": { + "$ref": "#/responses/unprocessableEntityError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/recording-rules/writer": { + "get": { + "tags": ["recording_rules", "enterprise"], + "summary": "Get the write target.", + "operationId": "getRecordingRuleWriteTarget", + "responses": { + "200": { + "$ref": "#/responses/recordingRuleWriteTargetResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "tags": ["recording_rules", "enterprise"], + "summary": "Create a new write target.", + "operationId": "createRecordingRuleWriteTarget", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PrometheusRemoteWriteTargetJSON" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/recordingRuleWriteTargetResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "422": { + "$ref": "#/responses/unprocessableEntityError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "delete": { + "tags": ["recording_rules", "enterprise"], + "summary": "Delete the write target.", + "operationId": "deleteRecordingRuleWriteTarget", + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/recording-rules/{recordingRuleID}": { + "delete": { + "tags": ["recording_rules", "enterprise"], + "summary": "Delete a recording rule.", + "operationId": "deleteRecordingRule", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "RecordingRuleID", + "name": "recordingRuleID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/reports": { + "get": { + "description": "Available to org admins only and with a valid or expired license\n\nYou need to have a permission with action `reports:read` with scope `reports:*`.", + "tags": ["reports", "enterprise"], + "summary": "List reports.", + "operationId": "getReports", + "responses": { + "200": { + "$ref": "#/responses/getReportsResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "description": "Available to org admins only and with a valid license.\n\nYou need to have a permission with action `reports.admin:create`.", + "tags": ["reports", "enterprise"], + "summary": "Create a report.", + "operationId": "createReport", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateOrUpdateConfigCmd" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/createReportResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/reports/email": { + "post": { + "description": "Generate and send a report. This API waits for the report to be generated before returning. We recommend that you set the client’s timeout to at least 60 seconds. Available to org admins only and with a valid license.\n\nOnly available in Grafana Enterprise v7.0+.\nThis API endpoint is experimental and may be deprecated in a future release. On deprecation, a migration strategy will be provided and the endpoint will remain functional until the next major release of Grafana.\n\nYou need to have a permission with action `reports:send`.", + "tags": ["reports", "enterprise"], + "summary": "Send a report.", + "operationId": "sendReport", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ReportEmailDTO" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/reports/render/pdf/{DashboardID}": { + "get": { + "description": "Available to all users and with a valid license.", + "produces": ["application/pdf"], + "tags": ["reports", "enterprise"], + "summary": "Render report for dashboard.", + "operationId": "renderReportPDF", + "parameters": [ + { + "type": "integer", + "format": "int64", + "name": "DashboardID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/contentResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/reports/settings": { + "get": { + "description": "Available to org admins only and with a valid or expired license\n\nYou need to have a permission with action `reports.settings:read`x.", + "tags": ["reports", "enterprise"], + "summary": "Get settings.", + "operationId": "getReportSettings", + "responses": { + "200": { + "$ref": "#/responses/getReportSettingsResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "description": "Available to org admins only and with a valid or expired license\n\nYou need to have a permission with action `reports.settings:write`xx.", + "tags": ["reports", "enterprise"], + "summary": "Save settings.", + "operationId": "saveReportSettings", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SettingsDTO" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/reports/test-email": { + "post": { + "description": "Available to org admins only and with a valid license.\n\nYou need to have a permission with action `reports:send`.", + "tags": ["reports", "enterprise"], + "summary": "Send test report via email.", + "operationId": "sendTestEmail", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateOrUpdateConfigCmd" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/reports/{reportID}": { + "get": { + "description": "Available to org admins only and with a valid or expired license\n\nYou need to have a permission with action `reports:read` with scope `reports:id:\u003creport ID\u003e`.", + "tags": ["reports", "enterprise"], + "summary": "Get a report.", + "operationId": "getReport", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "ReportID", + "name": "reportID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/getReportResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "put": { + "description": "Available to org admins only and with a valid or expired license\n\nYou need to have a permission with action `reports.admin:write` with scope `reports:id:\u003creport ID\u003e`.", + "tags": ["reports", "enterprise"], + "summary": "Update a report.", + "operationId": "updateReport", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "ReportID", + "name": "reportID", + "in": "path", + "required": true + }, + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateOrUpdateConfigCmd" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "delete": { + "description": "Available to org admins only and with a valid or expired license\n\nYou need to have a permission with action `reports.delete` with scope `reports:id:\u003creport ID\u003e`.", + "tags": ["reports", "enterprise"], + "summary": "Delete a report.", + "operationId": "deleteReport", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "ReportID", + "name": "reportID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/saml/acs": { + "post": { + "tags": ["saml", "enterprise"], + "summary": "It performs assertion Consumer Service (ACS).", + "operationId": "postACS", + "parameters": [ + { + "type": "string", + "name": "RelayState", + "in": "query" + } + ], + "responses": { + "302": { + "description": "" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/saml/metadata": { + "get": { + "produces": ["application/xml;application/samlmetadata+xml"], + "tags": ["saml", "enterprise"], + "summary": "It exposes the SP (Grafana's) metadata for the IdP's consumption.", + "operationId": "getSAMLMetadata", + "responses": { + "200": { + "$ref": "#/responses/contentResponse" + } + } + } + }, + "/saml/slo": { + "post": { + "tags": ["saml", "enterprise"], + "summary": "It performs Single Logout (SLO) callback.", + "operationId": "postSLO", + "parameters": [ + { + "type": "string", + "name": "SAMLRequest", + "in": "query" + }, + { + "type": "string", + "name": "SAMLResponse", + "in": "query" + } + ], + "responses": { + "302": { + "description": "" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, "/search": { "get": { "tags": ["search"], @@ -4763,6 +6416,132 @@ } } }, + "/teams/{teamId}/groups": { + "get": { + "tags": ["sync_team_groups", "enterprise"], + "summary": "Get External Groups.", + "operationId": "getTeamGroupsApi", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/getTeamGroupsApiResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + }, + "post": { + "tags": ["sync_team_groups", "enterprise"], + "summary": "Add External Group.", + "operationId": "addTeamGroupApi", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/TeamGroupMapping" + } + }, + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/teams/{teamId}/groups/{groupId}": { + "delete": { + "tags": ["sync_team_groups", "enterprise"], + "summary": "Remove External Group.", + "operationId": "removeTeamGroupApi", + "parameters": [ + { + "type": "integer", + "format": "int64", + "x-go-name": "GroupID", + "name": "groupId", + "in": "path", + "required": true + }, + { + "type": "integer", + "format": "int64", + "x-go-name": "TeamID", + "name": "teamId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "404": { + "$ref": "#/responses/notFoundError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, "/teams/{team_id}": { "get": { "tags": ["teams"], @@ -5369,6 +7148,36 @@ "$ref": "#/responses/internalServerError" } } + }, + "patch": { + "tags": ["user_preferences"], + "summary": "Patch user preferences.", + "operationId": "patchUserPreferences", + "parameters": [ + { + "x-go-name": "Body", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PatchPrefsCmd" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/okResponse" + }, + "400": { + "$ref": "#/responses/badRequestError" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } } }, "/user/quotas": { @@ -5803,6 +7612,50 @@ } }, "definitions": { + "ActiveSyncStatusDTO": { + "description": "ActiveSyncStatusDTO holds the information for LDAP background Sync", + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "x-go-name": "Enabled" + }, + "nextSync": { + "type": "string", + "format": "date-time", + "x-go-name": "NextSync" + }, + "prevSync": { + "$ref": "#/definitions/SyncResult" + }, + "schedule": { + "type": "string", + "x-go-name": "Schedule" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/ldapdebug" + }, + "ActiveUserStats": { + "type": "object", + "properties": { + "active_admins_and_editors": { + "type": "integer", + "format": "int64", + "x-go-name": "ActiveAdminsAndEditors" + }, + "active_users": { + "type": "integer", + "format": "int64", + "x-go-name": "ActiveUsers" + }, + "active_viewers": { + "type": "integer", + "format": "int64", + "x-go-name": "ActiveViewers" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/licensing" + }, "AddApiKeyCommand": { "description": "COMMANDS", "type": "object", @@ -5822,6 +7675,26 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "AddBuiltInRoleCommand": { + "type": "object", + "properties": { + "builtInRole": { + "type": "string", + "enum": ["Viewer", " Editor", " Admin", " Grafana Admin"], + "x-go-name": "BuiltinRole" + }, + "global": { + "description": "A flag indicating if the assignment is global or not. If set to false, the default org ID of the authenticated user will be used from the request to create organization local assignment. Refer to the Built-in role assignments for more information.", + "type": "boolean", + "x-go-name": "Global" + }, + "roleUid": { + "type": "string", + "x-go-name": "RoleUID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, "AddDataSourceCommand": { "description": "Also acts as api DTO", "type": "object", @@ -5924,6 +7797,29 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "AddPermissionDTO": { + "type": "object", + "properties": { + "builtinRole": { + "type": "string", + "x-go-name": "BuiltinRole" + }, + "permission": { + "$ref": "#/definitions/DsPermissionType" + }, + "teamId": { + "type": "integer", + "format": "int64", + "x-go-name": "TeamId" + }, + "userId": { + "type": "integer", + "format": "int64", + "x-go-name": "UserId" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/dspermissions" + }, "AddTeamMemberCommand": { "type": "object", "properties": { @@ -5935,6 +7831,30 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "AddTeamRoleCommand": { + "type": "object", + "properties": { + "roleUid": { + "type": "string", + "x-go-name": "RoleUID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, + "AddUserRoleCommand": { + "type": "object", + "properties": { + "global": { + "type": "boolean", + "x-go-name": "Global" + }, + "roleUid": { + "type": "string", + "x-go-name": "RoleUID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, "Address": { "type": "object", "properties": { @@ -6476,6 +8396,32 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "BrandingOptionsDTO": { + "type": "object", + "properties": { + "emailFooterLink": { + "type": "string", + "x-go-name": "EmailFooterLink" + }, + "emailFooterMode": { + "type": "string", + "x-go-name": "EmailFooterMode" + }, + "emailFooterText": { + "type": "string", + "x-go-name": "EmailFooterText" + }, + "emailLogoUrl": { + "type": "string", + "x-go-name": "EmailLogo" + }, + "reportLogoUrl": { + "type": "string", + "x-go-name": "ReportLogo" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, "CalculateDiffTarget": { "type": "object", "properties": { @@ -6509,6 +8455,89 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "ConfigDTO": { + "description": "ConfigDTO is model representation in transfer", + "type": "object", + "properties": { + "created": { + "type": "string", + "format": "date-time", + "x-go-name": "Created" + }, + "dashboardId": { + "type": "integer", + "format": "int64", + "x-go-name": "DashboardID" + }, + "dashboardName": { + "type": "string", + "x-go-name": "DashboardName" + }, + "dashboardUid": { + "type": "string", + "x-go-name": "DashboardUID" + }, + "enableCsv": { + "type": "boolean", + "x-go-name": "EnableCSV" + }, + "enableDashboardUrl": { + "type": "boolean", + "x-go-name": "EnableDashboardURL" + }, + "id": { + "type": "integer", + "format": "int64", + "x-go-name": "ID" + }, + "message": { + "type": "string", + "x-go-name": "Message" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "options": { + "$ref": "#/definitions/ReportOptionsDTO" + }, + "orgId": { + "type": "integer", + "format": "int64", + "x-go-name": "OrgID" + }, + "recipients": { + "type": "string", + "x-go-name": "Recipients" + }, + "replyTo": { + "type": "string", + "x-go-name": "ReplyTo" + }, + "schedule": { + "$ref": "#/definitions/ScheduleDTO" + }, + "state": { + "type": "string", + "x-go-name": "State" + }, + "templateVars": { + "type": "object", + "x-go-name": "TemplateVars" + }, + "updated": { + "type": "string", + "format": "date-time", + "x-go-name": "Updated" + }, + "userId": { + "type": "integer", + "format": "int64", + "x-go-name": "UserID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, "CreateAlertNotificationCommand": { "type": "object", "properties": { @@ -6642,6 +8671,59 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/services/libraryelements" }, + "CreateOrUpdateConfigCmd": { + "type": "object", + "properties": { + "dashboardId": { + "type": "integer", + "format": "int64", + "x-go-name": "DashboardID" + }, + "dashboardUid": { + "type": "string", + "x-go-name": "DashboardUID" + }, + "enableCsv": { + "type": "boolean", + "x-go-name": "EnableCSV" + }, + "enableDashboardUrl": { + "type": "boolean", + "x-go-name": "EnableDashboardURL" + }, + "message": { + "type": "string", + "x-go-name": "Message" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "options": { + "$ref": "#/definitions/ReportOptionsDTO" + }, + "recipients": { + "type": "string", + "x-go-name": "Recipients" + }, + "replyTo": { + "type": "string", + "x-go-name": "ReplyTo" + }, + "schedule": { + "$ref": "#/definitions/ScheduleDTO" + }, + "state": { + "type": "string", + "x-go-name": "State" + }, + "templateVars": { + "type": "object", + "x-go-name": "TemplateVars" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, "CreateOrgCommand": { "type": "object", "properties": { @@ -6652,6 +8734,48 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "CreateRoleWithPermissionsCommand": { + "type": "object", + "properties": { + "description": { + "type": "string", + "x-go-name": "Description" + }, + "displayName": { + "type": "string", + "x-go-name": "DisplayName" + }, + "group": { + "type": "string", + "x-go-name": "Group" + }, + "hidden": { + "type": "boolean", + "x-go-name": "Hidden" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "permissions": { + "type": "array", + "items": { + "$ref": "#/definitions/Permission" + }, + "x-go-name": "Permissions" + }, + "uid": { + "type": "string", + "x-go-name": "UID" + }, + "version": { + "type": "integer", + "format": "int64", + "x-go-name": "Version" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, "CreateTeamCommand": { "type": "object", "properties": { @@ -6666,6 +8790,67 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "CustomPermissionsRecordDTO": { + "type": "object", + "properties": { + "customPermissions": { + "type": "string", + "x-go-name": "CustomPermissions" + }, + "granteeName": { + "type": "string", + "x-go-name": "GranteeName" + }, + "granteeType": { + "type": "string", + "x-go-name": "GranteeType" + }, + "granteeUrl": { + "type": "string", + "x-go-name": "GranteeURL" + }, + "id": { + "type": "integer", + "format": "int64", + "x-go-name": "ID" + }, + "isFolder": { + "type": "boolean", + "x-go-name": "IsFolder" + }, + "orgId": { + "type": "integer", + "format": "int64", + "x-go-name": "OrgID" + }, + "orgRole": { + "type": "string", + "x-go-name": "OrgRole" + }, + "slug": { + "type": "string", + "x-go-name": "Slug" + }, + "title": { + "type": "string", + "x-go-name": "Title" + }, + "uid": { + "type": "string", + "x-go-name": "UID" + }, + "url": { + "type": "string", + "x-go-name": "URL" + }, + "usersCount": { + "type": "integer", + "format": "int64", + "x-go-name": "UsersCount" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/licensing" + }, "DashboardAclInfoDTO": { "type": "object", "properties": { @@ -7465,6 +9650,16 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" }, + "DeleteTokenCommand": { + "type": "object", + "properties": { + "instance": { + "type": "string", + "x-go-name": "Instance" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/licensing" + }, "DsAccess": { "type": "string", "x-go-package": "github.com/grafana/grafana/pkg/models" @@ -7523,6 +9718,19 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" }, + "FailedUser": { + "description": "FailedUser holds the information of an user that failed", + "type": "object", + "properties": { + "Error": { + "type": "string" + }, + "Login": { + "type": "string" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/ldapsync" + }, "FindTagsResult": { "type": "object", "title": "FindTagsResult is the result of a tags search.", @@ -8235,6 +10443,41 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" }, + "NavLink": { + "type": "object", + "properties": { + "id": { + "type": "string", + "x-go-name": "Id" + }, + "target": { + "type": "string", + "x-go-name": "Target" + }, + "text": { + "type": "string", + "x-go-name": "Text" + }, + "url": { + "type": "string", + "x-go-name": "Url" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/models" + }, + "NavbarPreference": { + "type": "object", + "properties": { + "savedItems": { + "type": "array", + "items": { + "$ref": "#/definitions/NavLink" + }, + "x-go-name": "SavedItems" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/models" + }, "NewApiKeyResult": { "type": "object", "properties": { @@ -8452,6 +10695,36 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/services/libraryelements" }, + "PatchPrefsCmd": { + "type": "object", + "properties": { + "homeDashboardId": { + "description": "The numerical :id of a favorited dashboard", + "type": "integer", + "format": "int64", + "default": 0, + "x-go-name": "HomeDashboardID" + }, + "navbar": { + "$ref": "#/definitions/NavbarPreference" + }, + "theme": { + "type": "string", + "enum": ["light", "dark"], + "x-go-name": "Theme" + }, + "timezone": { + "type": "string", + "enum": ["utc", "browser"], + "x-go-name": "Timezone" + }, + "weekStart": { + "type": "string", + "x-go-name": "WeekStart" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" + }, "PauseAlertCommand": { "type": "object", "properties": { @@ -8477,6 +10750,31 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" }, + "Permission": { + "type": "object", + "title": "Permission is the model for access control permissions.", + "properties": { + "action": { + "type": "string", + "x-go-name": "Action" + }, + "created": { + "type": "string", + "format": "date-time", + "x-go-name": "Created" + }, + "scope": { + "type": "string", + "x-go-name": "Scope" + }, + "updated": { + "type": "string", + "format": "date-time", + "x-go-name": "Updated" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/services/accesscontrol" + }, "PermissionType": { "type": "integer", "format": "int64", @@ -8553,6 +10851,9 @@ "format": "int64", "x-go-name": "HomeDashboardID" }, + "navbar": { + "$ref": "#/definitions/NavbarPreference" + }, "theme": { "type": "string", "x-go-name": "Theme" @@ -8568,6 +10869,24 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" }, + "PrometheusRemoteWriteTargetJSON": { + "type": "object", + "properties": { + "data_source_uid": { + "type": "string", + "x-go-name": "DatasourceUID" + }, + "id": { + "type": "string", + "x-go-name": "ID" + }, + "remote_write_path": { + "type": "string", + "x-go-name": "WritePath" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/recordedqueries/api" + }, "QueryDataResponse": { "description": "It is the return type of a QueryData call.", "type": "object", @@ -8579,6 +10898,108 @@ }, "x-go-package": "github.com/grafana/grafana-plugin-sdk-go/backend" }, + "RecordingRuleJSON": { + "description": "RecordingRuleJSON is the external representation of a recording rule", + "type": "object", + "properties": { + "active": { + "type": "boolean", + "x-go-name": "Active" + }, + "count": { + "type": "boolean", + "x-go-name": "Count" + }, + "description": { + "type": "string", + "x-go-name": "Description" + }, + "dest_data_source_uid": { + "type": "string", + "x-go-name": "DestDataSourceUID" + }, + "id": { + "type": "string", + "x-go-name": "ID" + }, + "interval": { + "type": "integer", + "format": "int64", + "x-go-name": "Interval" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "prom_name": { + "type": "string", + "x-go-name": "PromName" + }, + "queries": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "x-go-name": "Queries" + }, + "range": { + "type": "integer", + "format": "int64", + "x-go-name": "Range" + }, + "target_ref_id": { + "type": "string", + "x-go-name": "TargetRefID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/recordedqueries/api" + }, + "ReportEmailDTO": { + "type": "object", + "properties": { + "email": { + "type": "string", + "x-go-name": "Email" + }, + "emails": { + "description": "Comma-separated list of emails to which to send the report to.", + "type": "string", + "x-go-name": "Emails" + }, + "id": { + "description": "Send the report to the emails specified in the report. Required if emails is not present.", + "type": "string", + "format": "int64", + "x-go-name": "Id" + }, + "useEmailsFromReport": { + "description": "Send the report to the emails specified in the report. Required if emails is not present.", + "type": "boolean", + "x-go-name": "UseEmailsFromReport" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, + "ReportOptionsDTO": { + "type": "object", + "properties": { + "layout": { + "type": "string", + "x-go-name": "Layout" + }, + "orientation": { + "type": "string", + "x-go-name": "Orientation" + }, + "timeRange": { + "$ref": "#/definitions/TimeRangeDTO" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, "Responses": { "description": "The QueryData method the QueryDataHandler method will set the RefId\nproperty on the DataRespones' frames based on these RefIDs.", "type": "object", @@ -8599,6 +11020,62 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "RoleDTO": { + "type": "object", + "properties": { + "created": { + "type": "string", + "format": "date-time", + "x-go-name": "Created" + }, + "delegatable": { + "type": "boolean", + "x-go-name": "Delegatable" + }, + "description": { + "type": "string", + "x-go-name": "Description" + }, + "displayName": { + "type": "string", + "x-go-name": "DisplayName" + }, + "group": { + "type": "string", + "x-go-name": "Group" + }, + "hidden": { + "type": "boolean", + "x-go-name": "Hidden" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "permissions": { + "type": "array", + "items": { + "$ref": "#/definitions/Permission" + }, + "x-go-name": "Permissions" + }, + "uid": { + "type": "string", + "x-go-name": "UID" + }, + "updated": { + "type": "string", + "format": "date-time", + "x-go-name": "Updated" + }, + "version": { + "type": "integer", + "format": "int64", + "x-go-name": "Version" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/services/accesscontrol" + }, "RoleType": { "type": "string", "x-go-package": "github.com/grafana/grafana/pkg/models" @@ -8642,6 +11119,61 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "ScheduleDTO": { + "type": "object", + "properties": { + "day": { + "type": "string", + "x-go-name": "Day" + }, + "dayOfMonth": { + "type": "string", + "x-go-name": "DayOfMonth" + }, + "endDate": { + "type": "string", + "format": "date-time", + "x-go-name": "EndDate" + }, + "frequency": { + "type": "string", + "x-go-name": "Frequency" + }, + "hour": { + "type": "integer", + "format": "int64", + "x-go-name": "Hour" + }, + "intervalAmount": { + "type": "integer", + "format": "int64", + "x-go-name": "IntervalAmount" + }, + "intervalFrequency": { + "type": "string", + "x-go-name": "IntervalFrequency" + }, + "minute": { + "type": "integer", + "format": "int64", + "x-go-name": "Minute" + }, + "startDate": { + "type": "string", + "format": "date-time", + "x-go-name": "StartDate" + }, + "timeZone": { + "type": "string", + "x-go-name": "TimeZone" + }, + "workdaysOnly": { + "type": "boolean", + "x-go-name": "WorkdaysOnly" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, "SearchTeamQueryResult": { "type": "object", "properties": { @@ -8698,6 +11230,27 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "SetUserRolesCommand": { + "type": "object", + "properties": { + "global": { + "type": "boolean", + "x-go-name": "Global" + }, + "includeHidden": { + "type": "boolean", + "x-go-name": "IncludeHidden" + }, + "roleUids": { + "type": "array", + "items": { + "type": "string" + }, + "x-go-name": "RoleUIDs" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, "SettingsBag": { "type": "object", "additionalProperties": { @@ -8708,6 +11261,40 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/setting" }, + "SettingsDTO": { + "type": "object", + "properties": { + "branding": { + "$ref": "#/definitions/BrandingOptionsDTO" + }, + "id": { + "type": "integer", + "format": "int64", + "x-go-name": "ID" + }, + "orgId": { + "type": "integer", + "format": "int64", + "x-go-name": "OrgID" + }, + "userId": { + "type": "integer", + "format": "int64", + "x-go-name": "UserID" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, + "Status": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "x-go-name": "Enabled" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, "SuccessResponseBody": { "type": "object", "properties": { @@ -8718,6 +11305,40 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/api/docs/definitions" }, + "SyncResult": { + "type": "object", + "title": "SyncResult holds the result of a sync with LDAP. This gives us information on which users were updated and how.", + "properties": { + "Elapsed": { + "$ref": "#/definitions/Duration" + }, + "FailedUsers": { + "type": "array", + "items": { + "$ref": "#/definitions/FailedUser" + } + }, + "MissingUserIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + } + }, + "Started": { + "type": "string", + "format": "date-time" + }, + "UpdatedUserIds": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + } + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/ldapsync" + }, "TagsDTO": { "type": "object", "title": "TagsDTO is the frontend DTO for Tag.", @@ -8777,6 +11398,36 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "TeamGroupDTO": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "x-go-name": "GroupId" + }, + "orgId": { + "type": "integer", + "format": "int64", + "x-go-name": "OrgId" + }, + "teamId": { + "type": "integer", + "format": "int64", + "x-go-name": "TeamId" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/teamgroupsync/models" + }, + "TeamGroupMapping": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "x-go-name": "GroupId" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/teamgroupsync/models" + }, "TeamMemberDTO": { "type": "object", "properties": { @@ -8896,6 +11547,136 @@ "type": "string", "x-go-package": "github.com/grafana/grafana/pkg/models" }, + "TimeRangeDTO": { + "type": "object", + "properties": { + "from": { + "type": "string", + "x-go-name": "From" + }, + "to": { + "type": "string", + "x-go-name": "To" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/report" + }, + "Token": { + "type": "object", + "properties": { + "account": { + "type": "string", + "x-go-name": "Account" + }, + "company": { + "type": "string", + "x-go-name": "Company" + }, + "details_url": { + "type": "string", + "x-go-name": "DetailsUrl" + }, + "exp": { + "type": "integer", + "format": "int64", + "x-go-name": "Expires" + }, + "iat": { + "type": "integer", + "format": "int64", + "x-go-name": "Issued" + }, + "included_admins": { + "type": "integer", + "format": "int64", + "x-go-name": "IncludedAdmins" + }, + "included_users": { + "type": "integer", + "format": "int64", + "x-go-name": "IncludedUsers" + }, + "included_viewers": { + "type": "integer", + "format": "int64", + "x-go-name": "IncludedViewers" + }, + "iss": { + "type": "string", + "x-go-name": "Issuer" + }, + "jti": { + "type": "string", + "x-go-name": "Id" + }, + "lexp": { + "type": "integer", + "format": "int64", + "x-go-name": "LicenseExpires" + }, + "lic_exp_warn_days": { + "type": "integer", + "format": "int64", + "x-go-name": "LicenseExpiresWarnDays" + }, + "lid": { + "type": "string", + "x-go-name": "LicenseId" + }, + "limit_by": { + "type": "string", + "x-go-name": "LimitBy" + }, + "max_concurrent_user_sessions": { + "type": "integer", + "format": "int64", + "x-go-name": "MaxConcurrentUserSessions" + }, + "nbf": { + "type": "integer", + "format": "int64", + "x-go-name": "LicenseIssued" + }, + "prod": { + "type": "array", + "items": { + "type": "string" + }, + "x-go-name": "Products" + }, + "slug": { + "type": "string", + "x-go-name": "Slug" + }, + "status": { + "$ref": "#/definitions/TokenStatus" + }, + "sub": { + "type": "string", + "x-go-name": "Subject" + }, + "tok_exp_warn_days": { + "type": "integer", + "format": "int64", + "x-go-name": "TokenExpiresWarnDays" + }, + "update_days": { + "type": "integer", + "format": "int64", + "x-go-name": "UpdateDays" + }, + "usage_billing": { + "type": "boolean", + "x-go-name": "UsageBilling" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/licensing" + }, + "TokenStatus": { + "type": "integer", + "format": "int64", + "x-go-package": "github.com/grafana/grafana/pkg/extensions/licensing" + }, "TrimDashboardCommand": { "type": "object", "properties": { @@ -9228,6 +12009,9 @@ "default": 0, "x-go-name": "HomeDashboardID" }, + "navbar": { + "$ref": "#/definitions/NavbarPreference" + }, "theme": { "type": "string", "enum": ["light", "dark"], @@ -9245,6 +12029,48 @@ }, "x-go-package": "github.com/grafana/grafana/pkg/api/dtos" }, + "UpdateRoleCommand": { + "type": "object", + "properties": { + "description": { + "type": "string", + "x-go-name": "Description" + }, + "displayName": { + "type": "string", + "x-go-name": "DisplayName" + }, + "global": { + "type": "boolean", + "x-go-name": "Global" + }, + "group": { + "type": "string", + "x-go-name": "Group" + }, + "hidden": { + "type": "boolean", + "x-go-name": "Hidden" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "permissions": { + "type": "array", + "items": { + "$ref": "#/definitions/Permission" + }, + "x-go-name": "Permissions" + }, + "version": { + "type": "integer", + "format": "int64", + "x-go-name": "Version" + } + }, + "x-go-package": "github.com/grafana/grafana/pkg/extensions/accesscontrol" + }, "UpdateTeamCommand": { "type": "object", "properties": { @@ -9605,6 +12431,16 @@ "$ref": "#/definitions/ErrorResponseBody" } }, + "contentResponse": { + "description": "", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8" + } + } + }, "createAnnotationResponse": { "description": "", "schema": { @@ -9679,6 +12515,12 @@ } } }, + "createReportResponse": { + "description": "", + "schema": { + "type": "object" + } + }, "createSnapshotResponse": { "description": "", "schema": { @@ -9900,6 +12742,12 @@ } } }, + "getAccessControlStatusResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/Status" + } + }, "getAlertNotificationChannelResponse": { "description": "", "schema": { @@ -9933,6 +12781,15 @@ } } }, + "getAllRolesResponse": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/RoleDTO" + } + } + }, "getAnnotationTagsResponse": { "description": "", "schema": { @@ -9957,6 +12814,15 @@ } } }, + "getCustomPermissionsReportResponse": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/CustomPermissionsRecordDTO" + } + } + }, "getDashboardPermissionsResponse": { "description": "", "schema": { @@ -10027,6 +12893,12 @@ } } }, + "getLDAPSyncStatusResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/ActiveSyncStatusDTO" + } + }, "getLibraryElementConnectionsResponse": { "description": "", "schema": { @@ -10045,6 +12917,15 @@ "$ref": "#/definitions/LibraryElementSearchResponse" } }, + "getLicenseStatusResponse": { + "description": "" + }, + "getLicenseTokenResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/Token" + } + }, "getOrgResponse": { "description": "", "schema": { @@ -10060,6 +12941,12 @@ } } }, + "getPermissionseResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/AddPermissionDTO" + } + }, "getPreferencesResponse": { "description": "", "schema": { @@ -10075,6 +12962,33 @@ } } }, + "getReportResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/ConfigDTO" + } + }, + "getReportSettingsResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/SettingsDTO" + } + }, + "getReportsResponse": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ConfigDTO" + } + } + }, + "getRoleResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/RoleDTO" + } + }, "getSettingsResponse": { "description": "", "schema": { @@ -10116,6 +13030,15 @@ "$ref": "#/definitions/AdminStats" } }, + "getTeamGroupsApiResponse": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/TeamGroupDTO" + } + } + }, "getTeamMembersResponse": { "description": "", "schema": { @@ -10178,6 +13101,27 @@ "$ref": "#/definitions/ErrorResponseBody" } }, + "listBuiltinRolesResponse": { + "description": "", + "schema": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/RoleDTO" + } + } + } + }, + "listRecordingRulesResponse": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/RecordingRuleJSON" + } + } + }, "lookupAlertNotificationChannelsResponse": { "description": "", "schema": { @@ -10307,6 +13251,9 @@ } } }, + "postRenewLicenseTokenResponse": { + "description": "" + }, "preconditionFailedError": { "description": "PreconditionFailedError", "schema": { @@ -10325,6 +13272,24 @@ "$ref": "#/definitions/DataResponse" } }, + "recordingRuleResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/RecordingRuleJSON" + } + }, + "recordingRuleWriteTargetResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/PrometheusRemoteWriteTargetJSON" + } + }, + "refreshLicenseStatsResponse": { + "description": "", + "schema": { + "$ref": "#/definitions/ActiveUserStats" + } + }, "searchOrgResponse": { "description": "", "schema": {