mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Cookies: Provide a mechanism for per user control over cookies (#61566)
This commit is contained in:
parent
5eaaf9b9b7
commit
0caacb3333
@ -91,6 +91,7 @@ Alpha features might be changed or removed without prior notice.
|
||||
| `editPanelCSVDragAndDrop` | Enables drag and drop for CSV and Excel files |
|
||||
| `logsContextDatasourceUi` | Allow datasource to provide custom UI for context view |
|
||||
| `lokiQuerySplitting` | Split large interval queries into subqueries with smaller time intervals |
|
||||
| `individualCookiePreferences` | Support overriding cookie preferences per user |
|
||||
|
||||
## Development feature toggles
|
||||
|
||||
|
@ -81,4 +81,5 @@ export interface FeatureToggles {
|
||||
logsSampleInExplore?: boolean;
|
||||
logsContextDatasourceUi?: boolean;
|
||||
lokiQuerySplitting?: boolean;
|
||||
individualCookiePreferences?: boolean;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ type UpdatePrefsCmd struct {
|
||||
WeekStart string `json:"weekStart"`
|
||||
QueryHistory *pref.QueryHistoryPreference `json:"queryHistory,omitempty"`
|
||||
Language string `json:"language"`
|
||||
Cookies []pref.CookieType `json:"cookies,omitempty"`
|
||||
}
|
||||
|
||||
// swagger:model
|
||||
@ -32,4 +33,5 @@ type PatchPrefsCmd struct {
|
||||
Language *string `json:"language,omitempty"`
|
||||
QueryHistory *pref.QueryHistoryPreference `json:"queryHistory,omitempty"`
|
||||
HomeDashboardUID *string `json:"homeDashboardUID,omitempty"`
|
||||
Cookies []pref.CookieType `json:"cookies,omitempty"`
|
||||
}
|
||||
|
@ -122,13 +122,13 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
|
||||
HelpEnabled: setting.HelpEnabled,
|
||||
ProfileEnabled: setting.ProfileEnabled,
|
||||
QueryHistoryEnabled: hs.Cfg.QueryHistoryEnabled,
|
||||
GoogleAnalyticsId: setting.GoogleAnalyticsId,
|
||||
GoogleAnalytics4Id: setting.GoogleAnalytics4Id,
|
||||
GoogleAnalytics4SendManualPageViews: setting.GoogleAnalytics4SendManualPageViews,
|
||||
RudderstackWriteKey: setting.RudderstackWriteKey,
|
||||
RudderstackDataPlaneUrl: setting.RudderstackDataPlaneUrl,
|
||||
RudderstackSdkUrl: setting.RudderstackSdkUrl,
|
||||
RudderstackConfigUrl: setting.RudderstackConfigUrl,
|
||||
GoogleAnalyticsId: hs.Cfg.GoogleAnalyticsID,
|
||||
GoogleAnalytics4Id: hs.Cfg.GoogleAnalytics4ID,
|
||||
GoogleAnalytics4SendManualPageViews: hs.Cfg.GoogleAnalytics4SendManualPageViews,
|
||||
RudderstackWriteKey: hs.Cfg.RudderstackWriteKey,
|
||||
RudderstackDataPlaneUrl: hs.Cfg.RudderstackDataPlaneURL,
|
||||
RudderstackSdkUrl: hs.Cfg.RudderstackSDKURL,
|
||||
RudderstackConfigUrl: hs.Cfg.RudderstackConfigURL,
|
||||
FeedbackLinksEnabled: hs.Cfg.FeedbackLinksEnabled,
|
||||
ApplicationInsightsConnectionString: hs.Cfg.ApplicationInsightsConnectionString,
|
||||
ApplicationInsightsEndpointUrl: hs.Cfg.ApplicationInsightsEndpointUrl,
|
||||
|
@ -48,6 +48,13 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if hs.Features.IsEnabled(featuremgmt.FlagIndividualCookiePreferences) {
|
||||
if !prefs.Cookies("analytics") {
|
||||
settings.GoogleAnalytics4Id = ""
|
||||
settings.GoogleAnalyticsId = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Locale is used for some number and date/time formatting, whereas language is used just for
|
||||
// translating words in the interface
|
||||
acceptLangHeader := c.Req.Header.Get("Accept-Language")
|
||||
@ -110,10 +117,10 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV
|
||||
Theme: prefs.Theme,
|
||||
AppUrl: appURL,
|
||||
AppSubUrl: appSubURL,
|
||||
GoogleAnalyticsId: setting.GoogleAnalyticsId,
|
||||
GoogleAnalytics4Id: setting.GoogleAnalytics4Id,
|
||||
GoogleAnalytics4SendManualPageViews: setting.GoogleAnalytics4SendManualPageViews,
|
||||
GoogleTagManagerId: setting.GoogleTagManagerId,
|
||||
GoogleAnalyticsId: settings.GoogleAnalyticsId,
|
||||
GoogleAnalytics4Id: settings.GoogleAnalytics4Id,
|
||||
GoogleAnalytics4SendManualPageViews: hs.Cfg.GoogleAnalytics4SendManualPageViews,
|
||||
GoogleTagManagerId: hs.Cfg.GoogleTagManagerID,
|
||||
BuildVersion: setting.BuildVersion,
|
||||
BuildCommit: setting.BuildCommit,
|
||||
NewGrafanaVersion: hs.grafanaUpdateChecker.LatestVersion(),
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
loginservice "github.com/grafana/grafana/pkg/services/login"
|
||||
pref "github.com/grafana/grafana/pkg/services/preference"
|
||||
"github.com/grafana/grafana/pkg/services/secrets"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@ -398,22 +399,35 @@ func (hs *HTTPServer) trySetEncryptedCookie(ctx *contextmodel.ReqContext, cookie
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) redirectWithError(ctx *contextmodel.ReqContext, err error, v ...interface{}) {
|
||||
ctx.Logger.Warn(err.Error(), v...)
|
||||
if err := hs.trySetEncryptedCookie(ctx, loginErrorCookieName, getLoginExternalError(err), 60); err != nil {
|
||||
hs.log.Error("Failed to set encrypted cookie", "err", err)
|
||||
}
|
||||
|
||||
ctx.Redirect(hs.Cfg.AppSubURL + "/login")
|
||||
func (hs *HTTPServer) redirectWithError(c *contextmodel.ReqContext, err error, v ...interface{}) {
|
||||
c.Logger.Warn(err.Error(), v...)
|
||||
c.Redirect(hs.redirectURLWithErrorCookie(c, err))
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) RedirectResponseWithError(ctx *contextmodel.ReqContext, err error, v ...interface{}) *response.RedirectResponse {
|
||||
ctx.Logger.Error(err.Error(), v...)
|
||||
if err := hs.trySetEncryptedCookie(ctx, loginErrorCookieName, getLoginExternalError(err), 60); err != nil {
|
||||
hs.log.Error("Failed to set encrypted cookie", "err", err)
|
||||
func (hs *HTTPServer) RedirectResponseWithError(c *contextmodel.ReqContext, err error, v ...interface{}) *response.RedirectResponse {
|
||||
c.Logger.Error(err.Error(), v...)
|
||||
location := hs.redirectURLWithErrorCookie(c, err)
|
||||
return response.Redirect(location)
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) redirectURLWithErrorCookie(c *contextmodel.ReqContext, err error) string {
|
||||
setCookie := true
|
||||
if hs.Features.IsEnabled(featuremgmt.FlagIndividualCookiePreferences) {
|
||||
prefsQuery := pref.GetPreferenceWithDefaultsQuery{UserID: c.UserID, OrgID: c.OrgID, Teams: c.Teams}
|
||||
prefs, err := hs.preferenceService.GetWithDefaults(c.Req.Context(), &prefsQuery)
|
||||
if err != nil {
|
||||
c.Redirect(hs.Cfg.AppSubURL + "/login")
|
||||
}
|
||||
setCookie = prefs.Cookies("functional")
|
||||
}
|
||||
|
||||
return response.Redirect(hs.Cfg.AppSubURL + "/login")
|
||||
if setCookie {
|
||||
if err := hs.trySetEncryptedCookie(c, loginErrorCookieName, getLoginExternalError(err), 60); err != nil {
|
||||
hs.log.Error("Failed to set encrypted cookie", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
return hs.Cfg.AppSubURL + "/login"
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) samlEnabled() bool {
|
||||
|
@ -27,15 +27,16 @@ import (
|
||||
|
||||
func setupSocialHTTPServerWithConfig(t *testing.T, cfg *setting.Cfg) *HTTPServer {
|
||||
sqlStore := db.InitTestDB(t)
|
||||
features := featuremgmt.WithFeatures()
|
||||
|
||||
return &HTTPServer{
|
||||
Cfg: cfg,
|
||||
License: &licensing.OSSLicensingService{Cfg: cfg},
|
||||
SQLStore: sqlStore,
|
||||
SocialService: social.ProvideService(cfg, featuremgmt.WithFeatures(), &usagestats.UsageStatsMock{}),
|
||||
SocialService: social.ProvideService(cfg, features, &usagestats.UsageStatsMock{}),
|
||||
HooksService: hooks.ProvideService(),
|
||||
SecretsService: fakes.NewFakeSecretsService(),
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
Features: features,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ func (hs *HTTPServer) SetHomeDashboard(c *contextmodel.ReqContext) response.Resp
|
||||
} else {
|
||||
queryResult, err := hs.DashboardService.GetDashboard(c.Req.Context(), &query)
|
||||
if err != nil {
|
||||
return response.Error(404, "Dashboard not found", err)
|
||||
return response.Error(http.StatusNotFound, "Dashboard not found", err)
|
||||
}
|
||||
dashboardID = queryResult.ID
|
||||
}
|
||||
@ -48,7 +48,7 @@ func (hs *HTTPServer) SetHomeDashboard(c *contextmodel.ReqContext) response.Resp
|
||||
cmd.HomeDashboardID = dashboardID
|
||||
|
||||
if err := hs.preferenceService.Save(c.Req.Context(), &cmd); err != nil {
|
||||
return response.Error(500, "Failed to set home dashboard", err)
|
||||
return response.ErrOrFallback(http.StatusInternalServerError, "Failed to set home dashboard", err)
|
||||
}
|
||||
|
||||
return response.Success("Home dashboard set")
|
||||
@ -71,7 +71,7 @@ func (hs *HTTPServer) getPreferencesFor(ctx context.Context, orgID, userID, team
|
||||
|
||||
preference, err := hs.preferenceService.Get(ctx, &prefsQuery)
|
||||
if err != nil {
|
||||
return response.Error(500, "Failed to get preferences", err)
|
||||
return response.Error(http.StatusInternalServerError, "Failed to get preferences", err)
|
||||
}
|
||||
|
||||
var dashboardUID string
|
||||
@ -148,7 +148,7 @@ func (hs *HTTPServer) updatePreferencesFor(ctx context.Context, orgID, userID, t
|
||||
} else {
|
||||
queryResult, err := hs.DashboardService.GetDashboard(ctx, &query)
|
||||
if err != nil {
|
||||
return response.Error(404, "Dashboard not found", err)
|
||||
return response.Error(http.StatusNotFound, "Dashboard not found", err)
|
||||
}
|
||||
dashboardID = queryResult.ID
|
||||
}
|
||||
@ -156,19 +156,20 @@ func (hs *HTTPServer) updatePreferencesFor(ctx context.Context, orgID, userID, t
|
||||
dtoCmd.HomeDashboardID = dashboardID
|
||||
|
||||
saveCmd := pref.SavePreferenceCommand{
|
||||
UserID: userID,
|
||||
OrgID: orgID,
|
||||
TeamID: teamId,
|
||||
Theme: dtoCmd.Theme,
|
||||
Language: dtoCmd.Language,
|
||||
Timezone: dtoCmd.Timezone,
|
||||
WeekStart: dtoCmd.WeekStart,
|
||||
HomeDashboardID: dtoCmd.HomeDashboardID,
|
||||
QueryHistory: dtoCmd.QueryHistory,
|
||||
UserID: userID,
|
||||
OrgID: orgID,
|
||||
TeamID: teamId,
|
||||
Theme: dtoCmd.Theme,
|
||||
Language: dtoCmd.Language,
|
||||
Timezone: dtoCmd.Timezone,
|
||||
WeekStart: dtoCmd.WeekStart,
|
||||
HomeDashboardID: dtoCmd.HomeDashboardID,
|
||||
QueryHistory: dtoCmd.QueryHistory,
|
||||
CookiePreferences: dtoCmd.Cookies,
|
||||
}
|
||||
|
||||
if err := hs.preferenceService.Save(ctx, &saveCmd); err != nil {
|
||||
return response.Error(500, "Failed to save preferences", err)
|
||||
return response.ErrOrFallback(http.StatusInternalServerError, "Failed to save preferences", err)
|
||||
}
|
||||
|
||||
return response.Success("Preferences updated")
|
||||
@ -193,7 +194,7 @@ func (hs *HTTPServer) PatchUserPreferences(c *contextmodel.ReqContext) response.
|
||||
|
||||
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 && *dtoCmd.Theme != systemTheme {
|
||||
return response.Error(400, "Invalid theme", nil)
|
||||
return response.Error(http.StatusBadRequest, "Invalid theme", nil)
|
||||
}
|
||||
|
||||
// convert dashboard UID to ID in order to store internally if it exists in the query, otherwise take the id from query
|
||||
@ -207,7 +208,7 @@ func (hs *HTTPServer) patchPreferencesFor(ctx context.Context, orgID, userID, te
|
||||
} else {
|
||||
queryResult, err := hs.DashboardService.GetDashboard(ctx, &query)
|
||||
if err != nil {
|
||||
return response.Error(404, "Dashboard not found", err)
|
||||
return response.Error(http.StatusNotFound, "Dashboard not found", err)
|
||||
}
|
||||
dashboardID = &queryResult.ID
|
||||
}
|
||||
@ -215,19 +216,20 @@ func (hs *HTTPServer) patchPreferencesFor(ctx context.Context, orgID, userID, te
|
||||
dtoCmd.HomeDashboardID = dashboardID
|
||||
|
||||
patchCmd := pref.PatchPreferenceCommand{
|
||||
UserID: userID,
|
||||
OrgID: orgID,
|
||||
TeamID: teamId,
|
||||
Theme: dtoCmd.Theme,
|
||||
Timezone: dtoCmd.Timezone,
|
||||
WeekStart: dtoCmd.WeekStart,
|
||||
HomeDashboardID: dtoCmd.HomeDashboardID,
|
||||
Language: dtoCmd.Language,
|
||||
QueryHistory: dtoCmd.QueryHistory,
|
||||
UserID: userID,
|
||||
OrgID: orgID,
|
||||
TeamID: teamId,
|
||||
Theme: dtoCmd.Theme,
|
||||
Timezone: dtoCmd.Timezone,
|
||||
WeekStart: dtoCmd.WeekStart,
|
||||
HomeDashboardID: dtoCmd.HomeDashboardID,
|
||||
Language: dtoCmd.Language,
|
||||
QueryHistory: dtoCmd.QueryHistory,
|
||||
CookiePreferences: dtoCmd.Cookies,
|
||||
}
|
||||
|
||||
if err := hs.preferenceService.Patch(ctx, &patchCmd); err != nil {
|
||||
return response.Error(500, "Failed to save preferences", err)
|
||||
return response.ErrOrFallback(http.StatusInternalServerError, "Failed to save preferences", err)
|
||||
}
|
||||
|
||||
return response.Success("Preferences updated")
|
||||
|
@ -367,5 +367,10 @@ var (
|
||||
State: FeatureStateAlpha,
|
||||
FrontendOnly: true,
|
||||
},
|
||||
{
|
||||
Name: "individualCookiePreferences",
|
||||
Description: "Support overriding cookie preferences per user",
|
||||
State: FeatureStateAlpha,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
@ -266,4 +266,8 @@ const (
|
||||
// FlagLokiQuerySplitting
|
||||
// Split large interval queries into subqueries with smaller time intervals
|
||||
FlagLokiQuerySplitting = "lokiQuerySplitting"
|
||||
|
||||
// FlagIndividualCookiePreferences
|
||||
// Support overriding cookie preferences per user
|
||||
FlagIndividualCookiePreferences = "individualCookiePreferences"
|
||||
)
|
||||
|
@ -7,9 +7,16 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
)
|
||||
|
||||
var ErrPrefNotFound = errors.New("preference not found")
|
||||
var ErrUnknownCookieType = errutil.NewBase(
|
||||
errutil.StatusBadRequest,
|
||||
"preferences.unknownCookieType",
|
||||
errutil.WithPublicMessage("Got an unknown cookie preference type. Expected a set containing one or more of 'functional', 'performance', or 'analytics'}"),
|
||||
)
|
||||
|
||||
type Preference struct {
|
||||
ID int64 `xorm:"pk autoincr 'id'" db:"id"`
|
||||
@ -27,6 +34,15 @@ type Preference struct {
|
||||
JSONData *PreferenceJSONData `xorm:"json_data" db:"json_data"`
|
||||
}
|
||||
|
||||
func (p Preference) Cookies(typ string) bool {
|
||||
if p.JSONData == nil || p.JSONData.CookiePreferences == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
_, ok := p.JSONData.CookiePreferences[typ]
|
||||
return ok
|
||||
}
|
||||
|
||||
type GetPreferenceWithDefaultsQuery struct {
|
||||
Teams []int64
|
||||
OrgID int64
|
||||
@ -44,13 +60,14 @@ type SavePreferenceCommand struct {
|
||||
OrgID int64
|
||||
TeamID int64
|
||||
|
||||
HomeDashboardID int64 `json:"homeDashboardId,omitempty"`
|
||||
HomeDashboardUID *string `json:"homeDashboardUID,omitempty"`
|
||||
Timezone string `json:"timezone,omitempty"`
|
||||
WeekStart string `json:"weekStart,omitempty"`
|
||||
Theme string `json:"theme,omitempty"`
|
||||
Language string `json:"language,omitempty"`
|
||||
QueryHistory *QueryHistoryPreference `json:"queryHistory,omitempty"`
|
||||
HomeDashboardID int64 `json:"homeDashboardId,omitempty"`
|
||||
HomeDashboardUID *string `json:"homeDashboardUID,omitempty"`
|
||||
Timezone string `json:"timezone,omitempty"`
|
||||
WeekStart string `json:"weekStart,omitempty"`
|
||||
Theme string `json:"theme,omitempty"`
|
||||
Language string `json:"language,omitempty"`
|
||||
QueryHistory *QueryHistoryPreference `json:"queryHistory,omitempty"`
|
||||
CookiePreferences []CookieType `json:"cookiePreferences,omitempty"`
|
||||
}
|
||||
|
||||
type PatchPreferenceCommand struct {
|
||||
@ -58,18 +75,20 @@ type PatchPreferenceCommand struct {
|
||||
OrgID int64
|
||||
TeamID int64
|
||||
|
||||
HomeDashboardID *int64 `json:"homeDashboardId,omitempty"`
|
||||
HomeDashboardUID *string `json:"homeDashboardUID,omitempty"`
|
||||
Timezone *string `json:"timezone,omitempty"`
|
||||
WeekStart *string `json:"weekStart,omitempty"`
|
||||
Theme *string `json:"theme,omitempty"`
|
||||
Language *string `json:"language,omitempty"`
|
||||
QueryHistory *QueryHistoryPreference `json:"queryHistory,omitempty"`
|
||||
HomeDashboardID *int64 `json:"homeDashboardId,omitempty"`
|
||||
HomeDashboardUID *string `json:"homeDashboardUID,omitempty"`
|
||||
Timezone *string `json:"timezone,omitempty"`
|
||||
WeekStart *string `json:"weekStart,omitempty"`
|
||||
Theme *string `json:"theme,omitempty"`
|
||||
Language *string `json:"language,omitempty"`
|
||||
QueryHistory *QueryHistoryPreference `json:"queryHistory,omitempty"`
|
||||
CookiePreferences []CookieType `json:"cookiePreferences,omitempty"`
|
||||
}
|
||||
|
||||
type PreferenceJSONData struct {
|
||||
Language string `json:"language"`
|
||||
QueryHistory QueryHistoryPreference `json:"queryHistory"`
|
||||
Language string `json:"language"`
|
||||
QueryHistory QueryHistoryPreference `json:"queryHistory"`
|
||||
CookiePreferences map[string]struct{} `json:"cookiePreferences"`
|
||||
}
|
||||
|
||||
type QueryHistoryPreference struct {
|
||||
@ -112,3 +131,7 @@ func (j *PreferenceJSONData) ToDB() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (p Preference) TableName() string { return "preferences" }
|
||||
|
||||
// swagger:model
|
||||
// Enum: analytics,performance,functional
|
||||
type CookieType string
|
||||
|
@ -68,6 +68,10 @@ func (s *Service) GetWithDefaults(ctx context.Context, query *pref.GetPreference
|
||||
if p.JSONData.QueryHistory.HomeTab != "" {
|
||||
res.JSONData.QueryHistory.HomeTab = p.JSONData.QueryHistory.HomeTab
|
||||
}
|
||||
|
||||
if p.JSONData.CookiePreferences != nil {
|
||||
res.JSONData.CookiePreferences = p.JSONData.CookiePreferences
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,6 +95,11 @@ func (s *Service) Get(ctx context.Context, query *pref.GetPreferenceQuery) (*pre
|
||||
}
|
||||
|
||||
func (s *Service) Save(ctx context.Context, cmd *pref.SavePreferenceCommand) error {
|
||||
jsonData, err := preferenceData(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
preference, err := s.store.Get(ctx, &pref.Preference{
|
||||
OrgID: cmd.OrgID,
|
||||
UserID: cmd.UserID,
|
||||
@ -108,9 +117,7 @@ func (s *Service) Save(ctx context.Context, cmd *pref.SavePreferenceCommand) err
|
||||
Theme: cmd.Theme,
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
JSONData: &pref.PreferenceJSONData{
|
||||
Language: cmd.Language,
|
||||
},
|
||||
JSONData: jsonData,
|
||||
}
|
||||
_, err = s.store.Insert(ctx, preference)
|
||||
if err != nil {
|
||||
@ -126,13 +133,8 @@ func (s *Service) Save(ctx context.Context, cmd *pref.SavePreferenceCommand) err
|
||||
preference.Updated = time.Now()
|
||||
preference.Version += 1
|
||||
preference.HomeDashboardID = cmd.HomeDashboardID
|
||||
preference.JSONData = &pref.PreferenceJSONData{
|
||||
Language: cmd.Language,
|
||||
}
|
||||
preference.JSONData = jsonData
|
||||
|
||||
if cmd.QueryHistory != nil {
|
||||
preference.JSONData.QueryHistory = *cmd.QueryHistory
|
||||
}
|
||||
return s.store.Update(ctx, preference)
|
||||
}
|
||||
|
||||
@ -179,6 +181,18 @@ func (s *Service) Patch(ctx context.Context, cmd *pref.PatchPreferenceCommand) e
|
||||
preference.HomeDashboardID = *cmd.HomeDashboardID
|
||||
}
|
||||
|
||||
if cmd.CookiePreferences != nil {
|
||||
cookies, err := parseCookiePreferences(cmd.CookiePreferences)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if preference.JSONData == nil {
|
||||
preference.JSONData = &pref.PreferenceJSONData{}
|
||||
}
|
||||
preference.JSONData.CookiePreferences = cookies
|
||||
}
|
||||
|
||||
if cmd.Timezone != nil {
|
||||
preference.Timezone = *cmd.Timezone
|
||||
}
|
||||
@ -221,3 +235,40 @@ func (s *Service) GetDefaults() *pref.Preference {
|
||||
func (s *Service) DeleteByUser(ctx context.Context, userID int64) error {
|
||||
return s.store.DeleteByUser(ctx, userID)
|
||||
}
|
||||
|
||||
func parseCookiePreferences(prefs []pref.CookieType) (map[string]struct{}, error) {
|
||||
allowed := map[pref.CookieType]struct{}{
|
||||
"analytics": {},
|
||||
"performance": {},
|
||||
"functional": {},
|
||||
}
|
||||
|
||||
m := map[string]struct{}{}
|
||||
for _, c := range prefs {
|
||||
if _, ok := allowed[c]; !ok {
|
||||
return nil, pref.ErrUnknownCookieType.Errorf("'%s' is not an allowed cookie type", c)
|
||||
}
|
||||
|
||||
m[string(c)] = struct{}{}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func preferenceData(cmd *pref.SavePreferenceCommand) (*pref.PreferenceJSONData, error) {
|
||||
jsonData := &pref.PreferenceJSONData{
|
||||
Language: cmd.Language,
|
||||
}
|
||||
|
||||
if cmd.QueryHistory != nil {
|
||||
jsonData.QueryHistory = *cmd.QueryHistory
|
||||
}
|
||||
if cmd.CookiePreferences != nil {
|
||||
cookies, err := parseCookiePreferences(cmd.CookiePreferences)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsonData.CookiePreferences = cookies
|
||||
}
|
||||
|
||||
return jsonData, nil
|
||||
}
|
||||
|
@ -22,12 +22,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gobwas/glob"
|
||||
"github.com/prometheus/common/model"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"github.com/grafana/grafana-aws-sdk/pkg/awsds"
|
||||
"github.com/grafana/grafana-azure-sdk-go/azsettings"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||
"github.com/prometheus/common/model"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
@ -130,16 +129,6 @@ var (
|
||||
appliedCommandLineProperties []string
|
||||
appliedEnvOverrides []string
|
||||
|
||||
// analytics
|
||||
GoogleAnalyticsId string
|
||||
GoogleAnalytics4Id string
|
||||
GoogleAnalytics4SendManualPageViews bool
|
||||
GoogleTagManagerId string
|
||||
RudderstackDataPlaneUrl string
|
||||
RudderstackWriteKey string
|
||||
RudderstackSdkUrl string
|
||||
RudderstackConfigUrl string
|
||||
|
||||
// Alerting
|
||||
AlertingEnabled *bool
|
||||
ExecuteAlerts bool
|
||||
@ -419,6 +408,16 @@ type Cfg struct {
|
||||
ApplicationInsightsEndpointUrl string
|
||||
FeedbackLinksEnabled bool
|
||||
|
||||
// Frontend analytics
|
||||
GoogleAnalyticsID string
|
||||
GoogleAnalytics4ID string
|
||||
GoogleAnalytics4SendManualPageViews bool
|
||||
GoogleTagManagerID string
|
||||
RudderstackDataPlaneURL string
|
||||
RudderstackWriteKey string
|
||||
RudderstackSDKURL string
|
||||
RudderstackConfigURL string
|
||||
|
||||
// AzureAD
|
||||
AzureADSkipOrgRoleSync bool
|
||||
|
||||
@ -1036,15 +1035,15 @@ func (cfg *Cfg) Load(args CommandLineArgs) error {
|
||||
analytics := iniFile.Section("analytics")
|
||||
cfg.CheckForGrafanaUpdates = analytics.Key("check_for_updates").MustBool(true)
|
||||
cfg.CheckForPluginUpdates = analytics.Key("check_for_plugin_updates").MustBool(true)
|
||||
GoogleAnalyticsId = analytics.Key("google_analytics_ua_id").String()
|
||||
GoogleAnalytics4Id = analytics.Key("google_analytics_4_id").String()
|
||||
GoogleAnalytics4SendManualPageViews = analytics.Key("google_analytics_4_send_manual_page_views").MustBool(false)
|
||||
|
||||
GoogleTagManagerId = analytics.Key("google_tag_manager_id").String()
|
||||
RudderstackWriteKey = analytics.Key("rudderstack_write_key").String()
|
||||
RudderstackDataPlaneUrl = analytics.Key("rudderstack_data_plane_url").String()
|
||||
RudderstackSdkUrl = analytics.Key("rudderstack_sdk_url").String()
|
||||
RudderstackConfigUrl = analytics.Key("rudderstack_config_url").String()
|
||||
cfg.GoogleAnalyticsID = analytics.Key("google_analytics_ua_id").String()
|
||||
cfg.GoogleAnalytics4ID = analytics.Key("google_analytics_4_id").String()
|
||||
cfg.GoogleAnalytics4SendManualPageViews = analytics.Key("google_analytics_4_send_manual_page_views").MustBool(false)
|
||||
cfg.GoogleTagManagerID = analytics.Key("google_tag_manager_id").String()
|
||||
cfg.RudderstackWriteKey = analytics.Key("rudderstack_write_key").String()
|
||||
cfg.RudderstackDataPlaneURL = analytics.Key("rudderstack_data_plane_url").String()
|
||||
cfg.RudderstackSDKURL = analytics.Key("rudderstack_sdk_url").String()
|
||||
cfg.RudderstackConfigURL = analytics.Key("rudderstack_config_url").String()
|
||||
|
||||
cfg.ReportingEnabled = analytics.Key("reporting_enabled").MustBool(true)
|
||||
cfg.ReportingDistributor = analytics.Key("reporting_distributor").MustString("grafana-labs")
|
||||
|
Loading…
Reference in New Issue
Block a user