| 
									
										
										
										
											2015-01-29 19:10:34 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2023-05-16 00:38:54 +08:00
										 |  |  | 	"context" | 
					
						
							|  |  |  | 	"crypto/hmac" | 
					
						
							|  |  |  | 	"crypto/sha256" | 
					
						
							|  |  |  | 	"encoding/hex" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2016-09-23 18:29:53 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2022-04-15 20:01:58 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2016-07-05 23:59:43 +08:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 17:37:13 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/dtos" | 
					
						
							| 
									
										
										
										
											2023-04-28 00:20:37 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/middleware" | 
					
						
							| 
									
										
										
										
											2021-04-19 17:23:29 +08:00
										 |  |  | 	ac "github.com/grafana/grafana/pkg/services/accesscontrol" | 
					
						
							| 
									
										
										
										
											2023-01-27 15:50:36 +08:00
										 |  |  | 	contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" | 
					
						
							| 
									
										
										
										
											2022-03-10 00:57:50 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/dashboards" | 
					
						
							| 
									
										
										
										
											2022-01-27 01:44:20 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/featuremgmt" | 
					
						
							| 
									
										
										
										
											2023-05-16 00:38:54 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/login" | 
					
						
							| 
									
										
										
										
											2023-08-01 20:04:37 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/org" | 
					
						
							| 
									
										
										
										
											2022-04-21 21:03:17 +08:00
										 |  |  | 	pref "github.com/grafana/grafana/pkg/services/preference" | 
					
						
							| 
									
										
										
										
											2023-05-16 00:38:54 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/user" | 
					
						
							| 
									
										
										
										
											2015-02-05 17:37:13 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2015-01-29 19:10:34 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 15:50:36 +08:00
										 |  |  | func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexViewData, error) { | 
					
						
							| 
									
										
										
										
											2023-02-01 03:14:15 +08:00
										 |  |  | 	settings, err := hs.getFrontendSettings(c) | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-11 19:28:55 +08:00
										 |  |  | 	prefsQuery := pref.GetPreferenceWithDefaultsQuery{UserID: c.UserID, OrgID: c.OrgID, Teams: c.Teams} | 
					
						
							| 
									
										
										
										
											2022-04-21 21:03:17 +08:00
										 |  |  | 	prefs, err := hs.preferenceService.GetWithDefaults(c.Req.Context(), &prefsQuery) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-21 18:19:07 +08:00
										 |  |  | 	if hs.Features.IsEnabled(featuremgmt.FlagIndividualCookiePreferences) { | 
					
						
							|  |  |  | 		if !prefs.Cookies("analytics") { | 
					
						
							|  |  |  | 			settings.GoogleAnalytics4Id = "" | 
					
						
							|  |  |  | 			settings.GoogleAnalyticsId = "" | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-22 20:18:34 +08:00
										 |  |  | 	// Locale is used for some number and date/time formatting, whereas language is used just for
 | 
					
						
							|  |  |  | 	// translating words in the interface
 | 
					
						
							| 
									
										
										
										
											2022-06-21 18:12:49 +08:00
										 |  |  | 	acceptLangHeader := c.Req.Header.Get("Accept-Language") | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 	locale := "en-US" | 
					
						
							| 
									
										
										
										
											2022-11-22 20:18:34 +08:00
										 |  |  | 	language := "" // frontend will set the default language
 | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-02 16:24:40 +08:00
										 |  |  | 	if prefs.JSONData.Language != "" { | 
					
						
							| 
									
										
										
										
											2022-11-22 20:18:34 +08:00
										 |  |  | 		language = prefs.JSONData.Language | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(acceptLangHeader) > 0 { | 
					
						
							| 
									
										
										
										
											2022-06-21 18:12:49 +08:00
										 |  |  | 		parts := strings.Split(acceptLangHeader, ",") | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 		locale = parts[0] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	appURL := setting.AppUrl | 
					
						
							| 
									
										
										
										
											2021-03-10 19:41:29 +08:00
										 |  |  | 	appSubURL := hs.Cfg.AppSubURL | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// special case when doing localhost call from image renderer
 | 
					
						
							|  |  |  | 	if c.IsRenderCall && !hs.Cfg.ServeFromSubPath { | 
					
						
							| 
									
										
										
										
											2021-03-10 19:41:29 +08:00
										 |  |  | 		appURL = fmt.Sprintf("%s://localhost:%s", hs.Cfg.Protocol, hs.Cfg.HTTPPort) | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 		appSubURL = "" | 
					
						
							| 
									
										
										
										
											2023-02-01 03:14:15 +08:00
										 |  |  | 		settings.AppSubUrl = "" | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-30 21:39:09 +08:00
										 |  |  | 	navTree, err := hs.navTreeService.GetNavTree(c, prefs) | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-21 22:53:56 +08:00
										 |  |  | 	weekStart := "" | 
					
						
							|  |  |  | 	if prefs.WeekStart != nil { | 
					
						
							|  |  |  | 		weekStart = *prefs.WeekStart | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-10 21:37:04 +08:00
										 |  |  | 	theme := hs.getThemeForIndexData(prefs.Theme, c.Query("theme")) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-01 20:04:37 +08:00
										 |  |  | 	userOrgCount := 1 | 
					
						
							|  |  |  | 	userOrgs, err := hs.orgService.GetUserOrgList(c.Req.Context(), &org.GetUserOrgListQuery{UserID: c.UserID}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		hs.log.Error("Failed to count user orgs", "error", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(userOrgs) > 0 { | 
					
						
							|  |  |  | 		userOrgCount = len(userOrgs) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-30 21:39:09 +08:00
										 |  |  | 	hasAccess := ac.HasAccess(hs.AccessControl, c) | 
					
						
							|  |  |  | 	hasEditPerm := hasAccess(ac.EvalAny(ac.EvalPermission(dashboards.ActionDashboardsCreate), ac.EvalPermission(dashboards.ActionFoldersCreate))) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 	data := dtos.IndexViewData{ | 
					
						
							|  |  |  | 		User: &dtos.CurrentUser{ | 
					
						
							| 
									
										
										
										
											2022-08-11 19:28:55 +08:00
										 |  |  | 			Id:                         c.UserID, | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 			IsSignedIn:                 c.IsSignedIn, | 
					
						
							|  |  |  | 			Login:                      c.Login, | 
					
						
							|  |  |  | 			Email:                      c.Email, | 
					
						
							|  |  |  | 			Name:                       c.Name, | 
					
						
							| 
									
										
										
										
											2022-08-11 19:28:55 +08:00
										 |  |  | 			OrgId:                      c.OrgID, | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 			OrgName:                    c.OrgName, | 
					
						
							|  |  |  | 			OrgRole:                    c.OrgRole, | 
					
						
							| 
									
										
										
										
											2023-08-01 20:04:37 +08:00
										 |  |  | 			OrgCount:                   userOrgCount, | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 			GravatarUrl:                dtos.GetGravatarUrl(c.Email), | 
					
						
							|  |  |  | 			IsGrafanaAdmin:             c.IsGrafanaAdmin, | 
					
						
							| 
									
										
										
										
											2023-05-10 21:37:04 +08:00
										 |  |  | 			Theme:                      theme.ID, | 
					
						
							|  |  |  | 			LightTheme:                 theme.Type == "light", | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 			Timezone:                   prefs.Timezone, | 
					
						
							| 
									
										
										
										
											2022-11-21 22:53:56 +08:00
										 |  |  | 			WeekStart:                  weekStart, | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 			Locale:                     locale, | 
					
						
							| 
									
										
										
										
											2022-11-22 20:18:34 +08:00
										 |  |  | 			Language:                   language, | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 			HelpFlags1:                 c.HelpFlags1, | 
					
						
							|  |  |  | 			HasEditPermissionInFolders: hasEditPerm, | 
					
						
							| 
									
										
										
										
											2023-05-16 00:38:54 +08:00
										 |  |  | 			Analytics:                  hs.buildUserAnalyticsSettings(c.Req.Context(), c.SignedInUser), | 
					
						
							| 
									
										
										
										
											2023-07-28 21:32:58 +08:00
										 |  |  | 			AuthenticatedBy:            c.SignedInUser.AuthenticatedBy, | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-11-09 22:09:19 +08:00
										 |  |  | 		Settings:                            settings, | 
					
						
							| 
									
										
										
										
											2023-05-10 21:37:04 +08:00
										 |  |  | 		ThemeType:                           theme.Type, | 
					
						
							| 
									
										
										
										
											2022-11-09 22:09:19 +08:00
										 |  |  | 		AppUrl:                              appURL, | 
					
						
							|  |  |  | 		AppSubUrl:                           appSubURL, | 
					
						
							| 
									
										
										
										
											2023-06-01 20:35:05 +08:00
										 |  |  | 		NewsFeedEnabled:                     setting.NewsFeedEnabled, | 
					
						
							| 
									
										
										
										
											2023-02-21 18:19:07 +08:00
										 |  |  | 		GoogleAnalyticsId:                   settings.GoogleAnalyticsId, | 
					
						
							|  |  |  | 		GoogleAnalytics4Id:                  settings.GoogleAnalytics4Id, | 
					
						
							|  |  |  | 		GoogleAnalytics4SendManualPageViews: hs.Cfg.GoogleAnalytics4SendManualPageViews, | 
					
						
							|  |  |  | 		GoogleTagManagerId:                  hs.Cfg.GoogleTagManagerID, | 
					
						
							| 
									
										
										
										
											2022-11-09 22:09:19 +08:00
										 |  |  | 		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, | 
					
						
							|  |  |  | 		Nonce:                               c.RequestNonce, | 
					
						
							|  |  |  | 		ContentDeliveryURL:                  hs.Cfg.GetContentDeliveryURL(hs.License.ContentDeliveryPrefix()), | 
					
						
							|  |  |  | 		LoadingLogo:                         "public/img/grafana_icon.svg", | 
					
						
							| 
									
										
										
										
											2023-04-28 00:20:37 +08:00
										 |  |  | 		IsDevelopmentEnv:                    hs.Cfg.Env == setting.Dev, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if hs.Cfg.CSPEnabled { | 
					
						
							|  |  |  | 		data.CSPEnabled = true | 
					
						
							|  |  |  | 		data.CSPContent = middleware.ReplacePolicyVariables(hs.Cfg.CSPTemplate, appURL, c.RequestNonce) | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-31 16:58:57 +08:00
										 |  |  | 	userPermissions, err := hs.accesscontrolService.GetUserPermissions(c.Req.Context(), c.SignedInUser, ac.Options{ReloadCache: false}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2021-04-16 21:02:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-31 16:58:57 +08:00
										 |  |  | 	data.User.Permissions = ac.BuildPermissionsMap(userPermissions) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 	if setting.DisableGravatar { | 
					
						
							| 
									
										
										
										
											2021-03-10 19:41:29 +08:00
										 |  |  | 		data.User.GravatarUrl = hs.Cfg.AppSubURL + "/public/img/user_profile.png" | 
					
						
							| 
									
										
										
										
											2020-09-08 04:10:06 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(data.User.Name) == 0 { | 
					
						
							|  |  |  | 		data.User.Name = data.User.Login | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-27 16:24:44 +08:00
										 |  |  | 	hs.HooksService.RunIndexDataHooks(&data, c) | 
					
						
							| 
									
										
										
										
											2019-11-15 16:28:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-20 18:10:12 +08:00
										 |  |  | 	data.NavTree.ApplyAdminIA() | 
					
						
							| 
									
										
										
										
											2022-09-28 14:29:35 +08:00
										 |  |  | 	data.NavTree.Sort() | 
					
						
							| 
									
										
										
										
											2020-09-11 21:17:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-20 16:43:10 +08:00
										 |  |  | 	return &data, nil | 
					
						
							| 
									
										
										
										
											2015-01-29 19:10:34 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-16 00:38:54 +08:00
										 |  |  | func (hs *HTTPServer) buildUserAnalyticsSettings(ctx context.Context, signedInUser *user.SignedInUser) dtos.AnalyticsSettings { | 
					
						
							|  |  |  | 	identifier := signedInUser.Email + "@" + setting.AppUrl | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	authInfo, err := hs.authInfoService.GetAuthInfo(ctx, &login.GetAuthInfoQuery{UserId: signedInUser.UserID}) | 
					
						
							|  |  |  | 	if err != nil && !errors.Is(err, user.ErrUserNotFound) { | 
					
						
							|  |  |  | 		hs.log.Error("Failed to get auth info for analytics", "error", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if authInfo != nil && authInfo.AuthModule == login.GrafanaComAuthModule { | 
					
						
							|  |  |  | 		identifier = authInfo.AuthId | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return dtos.AnalyticsSettings{ | 
					
						
							|  |  |  | 		Identifier:         identifier, | 
					
						
							|  |  |  | 		IntercomIdentifier: hashUserIdentifier(identifier, hs.Cfg.IntercomSecret), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func hashUserIdentifier(identifier string, secret string) string { | 
					
						
							|  |  |  | 	if secret == "" { | 
					
						
							|  |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	key := []byte(secret) | 
					
						
							|  |  |  | 	h := hmac.New(sha256.New, key) | 
					
						
							|  |  |  | 	h.Write([]byte(identifier)) | 
					
						
							|  |  |  | 	return hex.EncodeToString(h.Sum(nil)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 15:50:36 +08:00
										 |  |  | func (hs *HTTPServer) Index(c *contextmodel.ReqContext) { | 
					
						
							| 
									
										
										
										
											2018-10-09 23:47:43 +08:00
										 |  |  | 	data, err := hs.setIndexViewData(c) | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-12-16 02:09:04 +08:00
										 |  |  | 		c.Handle(hs.Cfg, 500, "Failed to get settings", err) | 
					
						
							| 
									
										
										
										
											2015-01-29 19:10:34 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-04-15 20:01:58 +08:00
										 |  |  | 	c.HTML(http.StatusOK, "index", data) | 
					
						
							| 
									
										
										
										
											2015-01-29 19:10:34 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 15:50:36 +08:00
										 |  |  | func (hs *HTTPServer) NotFoundHandler(c *contextmodel.ReqContext) { | 
					
						
							| 
									
										
										
										
											2015-01-29 19:10:34 +08:00
										 |  |  | 	if c.IsApiRequest() { | 
					
						
							| 
									
										
										
										
											2015-03-23 03:14:00 +08:00
										 |  |  | 		c.JsonApiErr(404, "Not found", nil) | 
					
						
							| 
									
										
										
										
											2015-01-29 19:10:34 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 23:47:43 +08:00
										 |  |  | 	data, err := hs.setIndexViewData(c) | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-12-16 02:09:04 +08:00
										 |  |  | 		c.Handle(hs.Cfg, 500, "Failed to get settings", err) | 
					
						
							| 
									
										
										
										
											2015-01-29 19:10:34 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-22 19:37:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	c.HTML(404, "index", data) | 
					
						
							| 
									
										
										
										
											2015-01-29 19:10:34 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-05-10 21:37:04 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func (hs *HTTPServer) getThemeForIndexData(themePrefId string, themeURLParam string) *pref.ThemeDTO { | 
					
						
							|  |  |  | 	if themeURLParam != "" && pref.IsValidThemeID(themeURLParam) { | 
					
						
							|  |  |  | 		return pref.GetThemeByID(themeURLParam) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if pref.IsValidThemeID(themePrefId) { | 
					
						
							|  |  |  | 		theme := pref.GetThemeByID(themePrefId) | 
					
						
							|  |  |  | 		if !theme.IsExtra || hs.Features.IsEnabled(featuremgmt.FlagExtraThemes) { | 
					
						
							|  |  |  | 			return theme | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return pref.GetThemeByID(hs.Cfg.DefaultTheme) | 
					
						
							|  |  |  | } |