package api import ( "fmt" "net/http" "strings" "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/models" ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" pref "github.com/grafana/grafana/pkg/services/preference" "github.com/grafana/grafana/pkg/setting" ) const ( // Themes lightName = "light" darkName = "dark" ) func (hs *HTTPServer) editorInAnyFolder(c *models.ReqContext) bool { hasEditPermissionInFoldersQuery := models.HasEditPermissionInFoldersQuery{SignedInUser: c.SignedInUser} if err := hs.DashboardService.HasEditPermissionInFolders(c.Req.Context(), &hasEditPermissionInFoldersQuery); err != nil { return false } return hasEditPermissionInFoldersQuery.Result } func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewData, error) { hasAccess := ac.HasAccess(hs.AccessControl, c) hasEditPerm := hasAccess(hs.editorInAnyFolder, ac.EvalAny(ac.EvalPermission(dashboards.ActionDashboardsCreate), ac.EvalPermission(dashboards.ActionFoldersCreate))) settings, err := hs.getFrontendSettingsMap(c) if err != nil { return nil, err } settings["dateFormats"] = hs.Cfg.DateFormats prefsQuery := pref.GetPreferenceWithDefaultsQuery{UserID: c.UserID, OrgID: c.OrgID, Teams: c.Teams} prefs, err := hs.preferenceService.GetWithDefaults(c.Req.Context(), &prefsQuery) if err != nil { return nil, err } // 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") locale := "en-US" language := "" // frontend will set the default language if hs.Features.IsEnabled(featuremgmt.FlagInternationalization) && prefs.JSONData.Language != "" { language = prefs.JSONData.Language } if len(acceptLangHeader) > 0 { parts := strings.Split(acceptLangHeader, ",") locale = parts[0] } appURL := setting.AppUrl appSubURL := hs.Cfg.AppSubURL // special case when doing localhost call from image renderer if c.IsRenderCall && !hs.Cfg.ServeFromSubPath { appURL = fmt.Sprintf("%s://localhost:%s", hs.Cfg.Protocol, hs.Cfg.HTTPPort) appSubURL = "" settings["appSubUrl"] = "" } navTree, err := hs.navTreeService.GetNavTree(c, hasEditPerm, prefs) if err != nil { return nil, err } if c.IsPublicDashboardView { settings["isPublicDashboardView"] = true } weekStart := "" if prefs.WeekStart != nil { weekStart = *prefs.WeekStart } data := dtos.IndexViewData{ User: &dtos.CurrentUser{ Id: c.UserID, IsSignedIn: c.IsSignedIn, Login: c.Login, Email: c.Email, ExternalUserId: c.SignedInUser.ExternalAuthID, Name: c.Name, OrgCount: c.OrgCount, OrgId: c.OrgID, OrgName: c.OrgName, OrgRole: c.OrgRole, GravatarUrl: dtos.GetGravatarUrl(c.Email), IsGrafanaAdmin: c.IsGrafanaAdmin, LightTheme: prefs.Theme == lightName, Timezone: prefs.Timezone, WeekStart: weekStart, Locale: locale, Language: language, HelpFlags1: c.HelpFlags1, HasEditPermissionInFolders: hasEditPerm, }, Settings: settings, Theme: prefs.Theme, AppUrl: appURL, AppSubUrl: appSubURL, GoogleAnalyticsId: setting.GoogleAnalyticsId, GoogleAnalytics4Id: setting.GoogleAnalytics4Id, GoogleAnalytics4SendManualPageViews: setting.GoogleAnalytics4SendManualPageViews, GoogleTagManagerId: setting.GoogleTagManagerId, BuildVersion: setting.BuildVersion, BuildCommit: setting.BuildCommit, NewGrafanaVersion: hs.grafanaUpdateChecker.LatestVersion(), NewGrafanaVersionExists: hs.grafanaUpdateChecker.UpdateAvailable(), AppName: setting.ApplicationName, AppNameBodyClass: "app-grafana", FavIcon: "public/img/fav32.png", AppleTouchIcon: "public/img/apple-touch-icon.png", AppTitle: "Grafana", NavTree: navTree, Sentry: &hs.Cfg.Sentry, Nonce: c.RequestNonce, ContentDeliveryURL: hs.Cfg.GetContentDeliveryURL(hs.License.ContentDeliveryPrefix()), LoadingLogo: "public/img/grafana_icon.svg", } if !hs.AccessControl.IsDisabled() { userPermissions, err := hs.accesscontrolService.GetUserPermissions(c.Req.Context(), c.SignedInUser, ac.Options{ReloadCache: false}) if err != nil { return nil, err } data.User.Permissions = ac.BuildPermissionsMap(userPermissions) } if setting.DisableGravatar { data.User.GravatarUrl = hs.Cfg.AppSubURL + "/public/img/user_profile.png" } if len(data.User.Name) == 0 { data.User.Name = data.User.Login } themeURLParam := c.Query("theme") if themeURLParam == lightName { data.User.LightTheme = true data.Theme = lightName } else if themeURLParam == darkName { data.User.LightTheme = false data.Theme = darkName } hs.HooksService.RunIndexDataHooks(&data, c) // This will remove empty cfg or admin sections and move sections around if topnav is enabled data.NavTree.RemoveEmptySectionsAndApplyNewInformationArchitecture(hs.Features.IsEnabled(featuremgmt.FlagTopnav)) data.NavTree.Sort() return &data, nil } func (hs *HTTPServer) Index(c *models.ReqContext) { data, err := hs.setIndexViewData(c) if err != nil { c.Handle(hs.Cfg, 500, "Failed to get settings", err) return } c.HTML(http.StatusOK, "index", data) } func (hs *HTTPServer) NotFoundHandler(c *models.ReqContext) { if c.IsApiRequest() { c.JsonApiErr(404, "Not found", nil) return } data, err := hs.setIndexViewData(c) if err != nil { c.Handle(hs.Cfg, 500, "Failed to get settings", err) return } c.HTML(404, "index", data) }