From 0caacb3333152015bf0369f54315a26ff6f60f88 Mon Sep 17 00:00:00 2001 From: Emil Tullstedt Date: Tue, 21 Feb 2023 11:19:07 +0100 Subject: [PATCH] Cookies: Provide a mechanism for per user control over cookies (#61566) --- .../feature-toggles/index.md | 1 + .../src/types/featureToggles.gen.ts | 1 + pkg/api/dtos/prefs.go | 2 + pkg/api/frontendsettings.go | 14 ++-- pkg/api/index.go | 15 ++-- pkg/api/login.go | 38 ++++++---- pkg/api/login_oauth_test.go | 5 +- pkg/api/preferences.go | 54 ++++++++------- pkg/services/featuremgmt/registry.go | 5 ++ pkg/services/featuremgmt/toggles_gen.go | 4 ++ pkg/services/preference/model.go | 55 ++++++++++----- pkg/services/preference/prefimpl/pref.go | 69 ++++++++++++++++--- pkg/setting/setting.go | 41 ++++++----- 13 files changed, 207 insertions(+), 97 deletions(-) diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md index 747f7a66bb0..071e6b4e18f 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -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 diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 3013804924f..91b48daf0bd 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -81,4 +81,5 @@ export interface FeatureToggles { logsSampleInExplore?: boolean; logsContextDatasourceUi?: boolean; lokiQuerySplitting?: boolean; + individualCookiePreferences?: boolean; } diff --git a/pkg/api/dtos/prefs.go b/pkg/api/dtos/prefs.go index c8f80e40cc8..c5318217164 100644 --- a/pkg/api/dtos/prefs.go +++ b/pkg/api/dtos/prefs.go @@ -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"` } diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index 71cdc29fb9a..40c5de4fb68 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -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, diff --git a/pkg/api/index.go b/pkg/api/index.go index 7395929194e..3865a3564ca 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -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(), diff --git a/pkg/api/login.go b/pkg/api/login.go index d4cf320bc16..f200a9ca301 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -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 { diff --git a/pkg/api/login_oauth_test.go b/pkg/api/login_oauth_test.go index 4f68e23b3bd..7b4e469a1ed 100644 --- a/pkg/api/login_oauth_test.go +++ b/pkg/api/login_oauth_test.go @@ -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, } } diff --git a/pkg/api/preferences.go b/pkg/api/preferences.go index 9ec93d64631..12bbc50f3f1 100644 --- a/pkg/api/preferences.go +++ b/pkg/api/preferences.go @@ -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") diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index 4c4f75c7291..21686f269fb 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -367,5 +367,10 @@ var ( State: FeatureStateAlpha, FrontendOnly: true, }, + { + Name: "individualCookiePreferences", + Description: "Support overriding cookie preferences per user", + State: FeatureStateAlpha, + }, } ) diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 5e0b4d03e7c..8275d36c5b9 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -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" ) diff --git a/pkg/services/preference/model.go b/pkg/services/preference/model.go index 7505255a3bd..fd5407be21f 100644 --- a/pkg/services/preference/model.go +++ b/pkg/services/preference/model.go @@ -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 diff --git a/pkg/services/preference/prefimpl/pref.go b/pkg/services/preference/prefimpl/pref.go index 1ddc5b94cf0..57219d8155e 100644 --- a/pkg/services/preference/prefimpl/pref.go +++ b/pkg/services/preference/prefimpl/pref.go @@ -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 +} diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index 71e989f3bf3..968a3edaa32 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -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")