mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 18:30:41 -06:00
623 lines
21 KiB
Go
623 lines
21 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/grafana/grafana/pkg/api/dtos"
|
|
"github.com/grafana/grafana/pkg/plugins"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
|
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
|
"github.com/grafana/grafana/pkg/services/datasources"
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
|
"github.com/grafana/grafana/pkg/services/licensing"
|
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
|
|
"github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
"github.com/grafana/grafana/pkg/tsdb/grafanads"
|
|
"github.com/grafana/grafana/pkg/util"
|
|
)
|
|
|
|
func (hs *HTTPServer) GetFrontendSettings(c *contextmodel.ReqContext) {
|
|
settings, err := hs.getFrontendSettings(c)
|
|
if err != nil {
|
|
c.JsonApiErr(400, "Failed to get frontend settings", err)
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, settings)
|
|
}
|
|
|
|
// getFrontendSettings returns a json object with all the settings needed for front end initialisation.
|
|
func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.FrontendSettingsDTO, error) {
|
|
availablePlugins, err := hs.availablePlugins(c.Req.Context(), c.OrgID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
apps := make(map[string]*plugins.AppDTO, 0)
|
|
for _, ap := range availablePlugins[plugins.TypeApp] {
|
|
apps[ap.Plugin.ID] = newAppDTO(
|
|
ap.Plugin,
|
|
ap.Settings,
|
|
)
|
|
}
|
|
|
|
dataSources, err := hs.getFSDataSources(c, availablePlugins)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defaultDS := "-- Grafana --"
|
|
for n, ds := range dataSources {
|
|
if ds.IsDefault {
|
|
defaultDS = n
|
|
}
|
|
}
|
|
|
|
panels := make(map[string]plugins.PanelDTO)
|
|
for _, ap := range availablePlugins[plugins.TypePanel] {
|
|
panel := ap.Plugin
|
|
if panel.State == plugins.ReleaseStateAlpha && !hs.Cfg.PluginsEnableAlpha {
|
|
continue
|
|
}
|
|
|
|
if panel.ID == "datagrid" && !hs.Features.IsEnabled(featuremgmt.FlagEnableDatagridEditing) {
|
|
continue
|
|
}
|
|
|
|
panels[panel.ID] = plugins.PanelDTO{
|
|
ID: panel.ID,
|
|
Name: panel.Name,
|
|
Alias: panel.Alias,
|
|
Info: panel.Info,
|
|
Module: panel.Module,
|
|
BaseURL: panel.BaseURL,
|
|
SkipDataQuery: panel.SkipDataQuery,
|
|
HideFromList: panel.HideFromList,
|
|
ReleaseState: string(panel.State),
|
|
Signature: string(panel.Signature),
|
|
Sort: getPanelSort(panel.ID),
|
|
AngularDetected: panel.AngularDetected,
|
|
}
|
|
}
|
|
|
|
hideVersion := hs.Cfg.AnonymousHideVersion && !c.IsSignedIn
|
|
version := setting.BuildVersion
|
|
commit := setting.BuildCommit
|
|
buildstamp := setting.BuildStamp
|
|
|
|
if hideVersion {
|
|
version = ""
|
|
commit = ""
|
|
buildstamp = 0
|
|
}
|
|
|
|
hasAccess := accesscontrol.HasAccess(hs.AccessControl, c)
|
|
secretsManagerPluginEnabled := kvstore.EvaluateRemoteSecretsPlugin(c.Req.Context(), hs.secretsPluginManager, hs.Cfg) == nil
|
|
trustedTypesDefaultPolicyEnabled := (hs.Cfg.CSPEnabled && strings.Contains(hs.Cfg.CSPTemplate, "require-trusted-types-for")) || (hs.Cfg.CSPReportOnlyEnabled && strings.Contains(hs.Cfg.CSPReportOnlyTemplate, "require-trusted-types-for"))
|
|
|
|
frontendSettings := &dtos.FrontendSettingsDTO{
|
|
DefaultDatasource: defaultDS,
|
|
Datasources: dataSources,
|
|
MinRefreshInterval: setting.MinRefreshInterval,
|
|
Panels: panels,
|
|
Apps: apps,
|
|
AppUrl: hs.Cfg.AppURL,
|
|
AppSubUrl: hs.Cfg.AppSubURL,
|
|
AllowOrgCreate: (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin,
|
|
AuthProxyEnabled: hs.Cfg.AuthProxyEnabled,
|
|
LdapEnabled: hs.Cfg.LDAPAuthEnabled,
|
|
JwtHeaderName: hs.Cfg.JWTAuthHeaderName,
|
|
JwtUrlLogin: hs.Cfg.JWTAuthURLLogin,
|
|
AlertingErrorOrTimeout: setting.AlertingErrorOrTimeout,
|
|
AlertingNoDataOrNullValues: setting.AlertingNoDataOrNullValues,
|
|
AlertingMinInterval: setting.AlertingMinInterval,
|
|
LiveEnabled: hs.Cfg.LiveMaxConnections != 0,
|
|
AutoAssignOrg: hs.Cfg.AutoAssignOrg,
|
|
VerifyEmailEnabled: setting.VerifyEmailEnabled,
|
|
SigV4AuthEnabled: setting.SigV4AuthEnabled,
|
|
AzureAuthEnabled: setting.AzureAuthEnabled,
|
|
RbacEnabled: hs.Cfg.RBACEnabled,
|
|
ExploreEnabled: setting.ExploreEnabled,
|
|
HelpEnabled: setting.HelpEnabled,
|
|
ProfileEnabled: setting.ProfileEnabled,
|
|
NewsFeedEnabled: setting.NewsFeedEnabled,
|
|
QueryHistoryEnabled: hs.Cfg.QueryHistoryEnabled,
|
|
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,
|
|
DisableLoginForm: hs.Cfg.DisableLoginForm,
|
|
DisableUserSignUp: !setting.AllowUserSignUp,
|
|
LoginHint: setting.LoginHint,
|
|
PasswordHint: setting.PasswordHint,
|
|
ExternalUserMngInfo: setting.ExternalUserMngInfo,
|
|
ExternalUserMngLinkUrl: setting.ExternalUserMngLinkUrl,
|
|
ExternalUserMngLinkName: setting.ExternalUserMngLinkName,
|
|
ViewersCanEdit: hs.Cfg.ViewersCanEdit,
|
|
AngularSupportEnabled: hs.Cfg.AngularSupportEnabled,
|
|
EditorsCanAdmin: hs.Cfg.EditorsCanAdmin,
|
|
DisableSanitizeHtml: hs.Cfg.DisableSanitizeHtml,
|
|
TrustedTypesDefaultPolicyEnabled: trustedTypesDefaultPolicyEnabled,
|
|
CSPReportOnlyEnabled: hs.Cfg.CSPReportOnlyEnabled,
|
|
DateFormats: hs.Cfg.DateFormats,
|
|
SecureSocksDSProxyEnabled: hs.Cfg.SecureSocksDSProxy.Enabled && hs.Cfg.SecureSocksDSProxy.ShowUI,
|
|
DisableFrontendSandboxForPlugins: hs.Cfg.DisableFrontendSandboxForPlugins,
|
|
|
|
Auth: dtos.FrontendSettingsAuthDTO{
|
|
OAuthSkipOrgRoleUpdateSync: hs.Cfg.OAuthSkipOrgRoleUpdateSync,
|
|
SAMLSkipOrgRoleSync: hs.Cfg.SAMLSkipOrgRoleSync,
|
|
LDAPSkipOrgRoleSync: hs.Cfg.LDAPSkipOrgRoleSync,
|
|
GoogleSkipOrgRoleSync: hs.Cfg.GoogleSkipOrgRoleSync,
|
|
JWTAuthSkipOrgRoleSync: hs.Cfg.JWTAuthSkipOrgRoleSync,
|
|
GrafanaComSkipOrgRoleSync: hs.Cfg.GrafanaComSkipOrgRoleSync,
|
|
GenericOAuthSkipOrgRoleSync: hs.Cfg.GenericOAuthSkipOrgRoleSync,
|
|
AzureADSkipOrgRoleSync: hs.Cfg.AzureADSkipOrgRoleSync,
|
|
GithubSkipOrgRoleSync: hs.Cfg.GitHubSkipOrgRoleSync,
|
|
GitLabSkipOrgRoleSync: hs.Cfg.GitLabSkipOrgRoleSync,
|
|
OktaSkipOrgRoleSync: hs.Cfg.OktaSkipOrgRoleSync,
|
|
DisableSyncLock: hs.Cfg.DisableSyncLock,
|
|
},
|
|
|
|
BuildInfo: dtos.FrontendSettingsBuildInfoDTO{
|
|
HideVersion: hideVersion,
|
|
Version: version,
|
|
Commit: commit,
|
|
Buildstamp: buildstamp,
|
|
Edition: hs.License.Edition(),
|
|
LatestVersion: hs.grafanaUpdateChecker.LatestVersion(),
|
|
HasUpdate: hs.grafanaUpdateChecker.UpdateAvailable(),
|
|
Env: setting.Env,
|
|
},
|
|
|
|
LicenseInfo: dtos.FrontendSettingsLicenseInfoDTO{
|
|
Expiry: hs.License.Expiry(),
|
|
StateInfo: hs.License.StateInfo(),
|
|
LicenseUrl: hs.License.LicenseURL(hasAccess(licensing.PageAccess)),
|
|
Edition: hs.License.Edition(),
|
|
EnabledFeatures: hs.License.EnabledFeatures(),
|
|
},
|
|
|
|
FeatureToggles: hs.Features.GetEnabled(c.Req.Context()),
|
|
AnonymousEnabled: hs.Cfg.AnonymousEnabled,
|
|
RendererAvailable: hs.RenderService.IsAvailable(c.Req.Context()),
|
|
RendererVersion: hs.RenderService.Version(),
|
|
SecretsManagerPluginEnabled: secretsManagerPluginEnabled,
|
|
Http2Enabled: hs.Cfg.Protocol == setting.HTTP2Scheme,
|
|
GrafanaJavascriptAgent: hs.Cfg.GrafanaJavascriptAgent,
|
|
PluginCatalogURL: hs.Cfg.PluginCatalogURL,
|
|
PluginAdminEnabled: hs.Cfg.PluginAdminEnabled,
|
|
PluginAdminExternalManageEnabled: hs.Cfg.PluginAdminEnabled && hs.Cfg.PluginAdminExternalManageEnabled,
|
|
PluginCatalogHiddenPlugins: hs.Cfg.PluginCatalogHiddenPlugins,
|
|
ExpressionsEnabled: hs.Cfg.ExpressionsEnabled,
|
|
AwsAllowedAuthProviders: hs.Cfg.AWSAllowedAuthProviders,
|
|
AwsAssumeRoleEnabled: hs.Cfg.AWSAssumeRoleEnabled,
|
|
SupportBundlesEnabled: isSupportBundlesEnabled(hs),
|
|
|
|
Azure: dtos.FrontendSettingsAzureDTO{
|
|
Cloud: hs.Cfg.Azure.Cloud,
|
|
ManagedIdentityEnabled: hs.Cfg.Azure.ManagedIdentityEnabled,
|
|
UserIdentityEnabled: hs.Cfg.Azure.UserIdentityEnabled,
|
|
},
|
|
|
|
Caching: dtos.FrontendSettingsCachingDTO{
|
|
Enabled: hs.Cfg.SectionWithEnvOverrides("caching").Key("enabled").MustBool(true),
|
|
},
|
|
RecordedQueries: dtos.FrontendSettingsRecordedQueriesDTO{
|
|
Enabled: hs.Cfg.SectionWithEnvOverrides("recorded_queries").Key("enabled").MustBool(true),
|
|
},
|
|
Reporting: dtos.FrontendSettingsReportingDTO{
|
|
Enabled: hs.Cfg.SectionWithEnvOverrides("reporting").Key("enabled").MustBool(true),
|
|
},
|
|
|
|
UnifiedAlerting: dtos.FrontendSettingsUnifiedAlertingDTO{
|
|
MinInterval: hs.Cfg.UnifiedAlerting.MinInterval.String(),
|
|
},
|
|
|
|
Oauth: hs.getEnabledOAuthProviders(),
|
|
SamlEnabled: hs.samlEnabled(),
|
|
SamlName: hs.samlName(),
|
|
TokenExpirationDayLimit: hs.Cfg.SATokenExpirationDayLimit,
|
|
|
|
SnapshotEnabled: hs.Cfg.SnapshotEnabled,
|
|
|
|
SqlConnectionLimits: dtos.FrontendSettingsSqlConnectionLimitsDTO{
|
|
MaxOpenConns: hs.Cfg.SqlDatasourceMaxOpenConnsDefault,
|
|
MaxIdleConns: hs.Cfg.SqlDatasourceMaxIdleConnsDefault,
|
|
ConnMaxLifetime: hs.Cfg.SqlDatasourceMaxConnLifetimeDefault,
|
|
},
|
|
}
|
|
|
|
if hs.Cfg.UnifiedAlerting.StateHistory.Enabled {
|
|
frontendSettings.UnifiedAlerting.AlertStateHistoryBackend = hs.Cfg.UnifiedAlerting.StateHistory.Backend
|
|
frontendSettings.UnifiedAlerting.AlertStateHistoryPrimary = hs.Cfg.UnifiedAlerting.StateHistory.MultiPrimary
|
|
}
|
|
|
|
if hs.Cfg.UnifiedAlerting.Enabled != nil {
|
|
frontendSettings.UnifiedAlertingEnabled = *hs.Cfg.UnifiedAlerting.Enabled
|
|
}
|
|
|
|
if setting.AlertingEnabled != nil {
|
|
frontendSettings.AlertingEnabled = *setting.AlertingEnabled
|
|
}
|
|
|
|
if hs.pluginsCDNService != nil && hs.pluginsCDNService.IsEnabled() {
|
|
cdnBaseURL, err := hs.pluginsCDNService.BaseURL()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("plugins cdn base url: %w", err)
|
|
}
|
|
frontendSettings.PluginsCDNBaseURL = cdnBaseURL
|
|
}
|
|
|
|
if hs.Cfg.GeomapDefaultBaseLayerConfig != nil {
|
|
frontendSettings.GeomapDefaultBaseLayerConfig = &hs.Cfg.GeomapDefaultBaseLayerConfig
|
|
}
|
|
|
|
if !hs.Cfg.GeomapEnableCustomBaseLayers {
|
|
frontendSettings.GeomapDisableCustomBaseLayer = true
|
|
}
|
|
|
|
return frontendSettings, nil
|
|
}
|
|
|
|
func isSupportBundlesEnabled(hs *HTTPServer) bool {
|
|
return hs.Cfg.SectionWithEnvOverrides("support_bundles").Key("enabled").MustBool(true)
|
|
}
|
|
|
|
func (hs *HTTPServer) getFSDataSources(c *contextmodel.ReqContext, availablePlugins AvailablePlugins) (map[string]plugins.DataSourceDTO, error) {
|
|
orgDataSources := make([]*datasources.DataSource, 0)
|
|
if c.OrgID != 0 {
|
|
query := datasources.GetDataSourcesQuery{OrgID: c.OrgID, DataSourceLimit: hs.Cfg.DataSourceLimit}
|
|
dataSources, err := hs.DataSourcesService.GetDataSources(c.Req.Context(), &query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if c.IsPublicDashboardView {
|
|
// If RBAC is enabled, it will filter out all datasources for a public user, so we need to skip it
|
|
orgDataSources = dataSources
|
|
} else {
|
|
filtered, err := hs.filterDatasourcesByQueryPermission(c.Req.Context(), c.SignedInUser, dataSources)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
orgDataSources = filtered
|
|
}
|
|
}
|
|
|
|
dataSources := make(map[string]plugins.DataSourceDTO)
|
|
|
|
for _, ds := range orgDataSources {
|
|
url := ds.URL
|
|
|
|
if ds.Access == datasources.DS_ACCESS_PROXY {
|
|
url = "/api/datasources/proxy/uid/" + ds.UID
|
|
}
|
|
|
|
dsDTO := plugins.DataSourceDTO{
|
|
ID: ds.ID,
|
|
UID: ds.UID,
|
|
Type: ds.Type,
|
|
Name: ds.Name,
|
|
URL: url,
|
|
IsDefault: ds.IsDefault,
|
|
Access: string(ds.Access),
|
|
ReadOnly: ds.ReadOnly,
|
|
}
|
|
|
|
ap, exists := availablePlugins.Get(plugins.TypeDataSource, ds.Type)
|
|
if !exists {
|
|
c.Logger.Error("Could not find plugin definition for data source", "datasource_type", ds.Type)
|
|
continue
|
|
}
|
|
plugin := ap.Plugin
|
|
dsDTO.Type = plugin.ID
|
|
dsDTO.Preload = plugin.Preload
|
|
dsDTO.Module = plugin.Module
|
|
dsDTO.PluginMeta = &plugins.PluginMetaDTO{
|
|
JSONData: plugin.JSONData,
|
|
Signature: plugin.Signature,
|
|
Module: plugin.Module,
|
|
BaseURL: plugin.BaseURL,
|
|
}
|
|
dsDTO.AngularDetected = plugin.AngularDetected
|
|
|
|
if ds.JsonData == nil {
|
|
dsDTO.JSONData = make(map[string]interface{})
|
|
} else {
|
|
dsDTO.JSONData = ds.JsonData.MustMap()
|
|
}
|
|
|
|
if ds.Access == datasources.DS_ACCESS_DIRECT {
|
|
if ds.BasicAuth {
|
|
password, err := hs.DataSourcesService.DecryptedBasicAuthPassword(c.Req.Context(), ds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dsDTO.BasicAuth = util.GetBasicAuthHeader(
|
|
ds.BasicAuthUser,
|
|
password,
|
|
)
|
|
}
|
|
if ds.WithCredentials {
|
|
dsDTO.WithCredentials = ds.WithCredentials
|
|
}
|
|
|
|
if ds.Type == datasources.DS_INFLUXDB_08 {
|
|
password, err := hs.DataSourcesService.DecryptedPassword(c.Req.Context(), ds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dsDTO.Username = ds.User
|
|
dsDTO.Password = password
|
|
dsDTO.URL = url + "/db/" + ds.Database
|
|
}
|
|
|
|
if ds.Type == datasources.DS_INFLUXDB {
|
|
password, err := hs.DataSourcesService.DecryptedPassword(c.Req.Context(), ds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dsDTO.Username = ds.User
|
|
dsDTO.Password = password
|
|
dsDTO.URL = url
|
|
}
|
|
}
|
|
|
|
// Update `jsonData.database` for outdated provisioned SQL datasources created WITHOUT the `jsonData` object in their configuration.
|
|
// In these cases, the `Database` value is defined (if at all) on the root level of the provisioning config object.
|
|
// This is done for easier warning/error checking on the front end.
|
|
if (ds.Type == datasources.DS_MSSQL) || (ds.Type == datasources.DS_MYSQL) || (ds.Type == datasources.DS_POSTGRES) {
|
|
// Only update if the value isn't already assigned.
|
|
if dsDTO.JSONData["database"] == nil || dsDTO.JSONData["database"] == "" {
|
|
dsDTO.JSONData["database"] = ds.Database
|
|
}
|
|
}
|
|
|
|
if (ds.Type == datasources.DS_INFLUXDB) || (ds.Type == datasources.DS_ES) {
|
|
dsDTO.Database = ds.Database
|
|
}
|
|
|
|
if ds.Type == datasources.DS_PROMETHEUS {
|
|
// add unproxied server URL for link to Prometheus web UI
|
|
ds.JsonData.Set("directUrl", ds.URL)
|
|
}
|
|
|
|
dataSources[ds.Name] = dsDTO
|
|
}
|
|
|
|
// add data sources that are built in (meaning they are not added via data sources page, nor have any entry in
|
|
// the datasource table)
|
|
for _, ds := range hs.pluginStore.Plugins(c.Req.Context(), plugins.TypeDataSource) {
|
|
if ds.BuiltIn {
|
|
dto := plugins.DataSourceDTO{
|
|
Type: string(ds.Type),
|
|
Name: ds.Name,
|
|
JSONData: make(map[string]interface{}),
|
|
PluginMeta: &plugins.PluginMetaDTO{
|
|
JSONData: ds.JSONData,
|
|
Signature: ds.Signature,
|
|
Module: ds.Module,
|
|
BaseURL: ds.BaseURL,
|
|
},
|
|
AngularDetected: ds.AngularDetected,
|
|
}
|
|
if ds.Name == grafanads.DatasourceName {
|
|
dto.ID = grafanads.DatasourceID
|
|
dto.UID = grafanads.DatasourceUID
|
|
}
|
|
dataSources[ds.Name] = dto
|
|
}
|
|
}
|
|
|
|
return dataSources, nil
|
|
}
|
|
|
|
func newAppDTO(plugin plugins.PluginDTO, settings pluginsettings.InfoDTO) *plugins.AppDTO {
|
|
app := &plugins.AppDTO{
|
|
ID: plugin.ID,
|
|
Version: plugin.Info.Version,
|
|
Path: plugin.Module,
|
|
Preload: false,
|
|
AngularDetected: plugin.AngularDetected,
|
|
}
|
|
|
|
if settings.Enabled {
|
|
app.Preload = plugin.Preload
|
|
}
|
|
|
|
return app
|
|
}
|
|
|
|
func getPanelSort(id string) int {
|
|
sort := 100
|
|
switch id {
|
|
case "timeseries":
|
|
sort = 1
|
|
case "barchart":
|
|
sort = 2
|
|
case "stat":
|
|
sort = 3
|
|
case "gauge":
|
|
sort = 4
|
|
case "bargauge":
|
|
sort = 5
|
|
case "table":
|
|
sort = 6
|
|
case "singlestat":
|
|
sort = 7
|
|
case "piechart":
|
|
sort = 8
|
|
case "state-timeline":
|
|
sort = 9
|
|
case "heatmap":
|
|
sort = 10
|
|
case "status-history":
|
|
sort = 11
|
|
case "histogram":
|
|
sort = 12
|
|
case "graph":
|
|
sort = 13
|
|
case "text":
|
|
sort = 14
|
|
case "alertlist":
|
|
sort = 15
|
|
case "dashlist":
|
|
sort = 16
|
|
case "news":
|
|
sort = 17
|
|
}
|
|
return sort
|
|
}
|
|
|
|
type availablePluginDTO struct {
|
|
Plugin plugins.PluginDTO
|
|
Settings pluginsettings.InfoDTO
|
|
}
|
|
|
|
// AvailablePlugins represents a mapping from plugin types (panel, data source, etc.) to plugin IDs to plugins
|
|
// For example ["panel"] -> ["piechart"] -> {pie chart plugin DTO}
|
|
type AvailablePlugins map[plugins.Type]map[string]*availablePluginDTO
|
|
|
|
func (ap AvailablePlugins) Get(pluginType plugins.Type, pluginID string) (*availablePluginDTO, bool) {
|
|
p, exists := ap[pluginType][pluginID]
|
|
if exists {
|
|
return p, true
|
|
}
|
|
for _, p = range ap[pluginType] {
|
|
if p.Plugin.ID == pluginID || p.Plugin.Alias == pluginID {
|
|
return p, true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (hs *HTTPServer) availablePlugins(ctx context.Context, orgID int64) (AvailablePlugins, error) {
|
|
ap := make(AvailablePlugins)
|
|
|
|
pluginSettingMap, err := hs.pluginSettings(ctx, orgID)
|
|
if err != nil {
|
|
return ap, err
|
|
}
|
|
|
|
apps := make(map[string]*availablePluginDTO)
|
|
for _, app := range hs.pluginStore.Plugins(ctx, plugins.TypeApp) {
|
|
if s, exists := pluginSettingMap[app.ID]; exists {
|
|
app.Pinned = s.Pinned
|
|
apps[app.ID] = &availablePluginDTO{
|
|
Plugin: app,
|
|
Settings: *s,
|
|
}
|
|
}
|
|
}
|
|
ap[plugins.TypeApp] = apps
|
|
|
|
dataSources := make(map[string]*availablePluginDTO)
|
|
for _, ds := range hs.pluginStore.Plugins(ctx, plugins.TypeDataSource) {
|
|
if s, exists := pluginSettingMap[ds.ID]; exists {
|
|
dataSources[ds.ID] = &availablePluginDTO{
|
|
Plugin: ds,
|
|
Settings: *s,
|
|
}
|
|
}
|
|
}
|
|
ap[plugins.TypeDataSource] = dataSources
|
|
|
|
panels := make(map[string]*availablePluginDTO)
|
|
for _, p := range hs.pluginStore.Plugins(ctx, plugins.TypePanel) {
|
|
if s, exists := pluginSettingMap[p.ID]; exists {
|
|
panels[p.ID] = &availablePluginDTO{
|
|
Plugin: p,
|
|
Settings: *s,
|
|
}
|
|
}
|
|
}
|
|
ap[plugins.TypePanel] = panels
|
|
|
|
return ap, nil
|
|
}
|
|
|
|
func (hs *HTTPServer) pluginSettings(ctx context.Context, orgID int64) (map[string]*pluginsettings.InfoDTO, error) {
|
|
pluginSettings := make(map[string]*pluginsettings.InfoDTO)
|
|
|
|
// fill settings from database
|
|
if pss, err := hs.PluginSettings.GetPluginSettings(ctx, &pluginsettings.GetArgs{OrgID: orgID}); err != nil {
|
|
return nil, err
|
|
} else {
|
|
for _, ps := range pss {
|
|
pluginSettings[ps.PluginID] = ps
|
|
}
|
|
}
|
|
|
|
// fill settings from app plugins
|
|
for _, plugin := range hs.pluginStore.Plugins(ctx, plugins.TypeApp) {
|
|
// ignore settings that already exist
|
|
if _, exists := pluginSettings[plugin.ID]; exists {
|
|
continue
|
|
}
|
|
|
|
// add new setting which is enabled depending on if AutoEnabled: true
|
|
pluginSetting := &pluginsettings.InfoDTO{
|
|
PluginID: plugin.ID,
|
|
OrgID: orgID,
|
|
Enabled: plugin.AutoEnabled,
|
|
Pinned: plugin.AutoEnabled,
|
|
PluginVersion: plugin.Info.Version,
|
|
}
|
|
|
|
pluginSettings[plugin.ID] = pluginSetting
|
|
}
|
|
|
|
// fill settings from all remaining plugins (including potential app child plugins)
|
|
for _, plugin := range hs.pluginStore.Plugins(ctx) {
|
|
// ignore settings that already exist
|
|
if _, exists := pluginSettings[plugin.ID]; exists {
|
|
continue
|
|
}
|
|
|
|
// add new setting which is enabled by default
|
|
pluginSetting := &pluginsettings.InfoDTO{
|
|
PluginID: plugin.ID,
|
|
OrgID: orgID,
|
|
Enabled: true,
|
|
Pinned: false,
|
|
PluginVersion: plugin.Info.Version,
|
|
}
|
|
|
|
// if plugin is included in an app, check app settings
|
|
if plugin.IncludedInAppID != "" {
|
|
// app child plugins are disabled unless app is enabled
|
|
pluginSetting.Enabled = false
|
|
if p, exists := pluginSettings[plugin.IncludedInAppID]; exists {
|
|
pluginSetting.Enabled = p.Enabled
|
|
}
|
|
}
|
|
pluginSettings[plugin.ID] = pluginSetting
|
|
}
|
|
|
|
return pluginSettings, nil
|
|
}
|
|
|
|
func (hs *HTTPServer) getEnabledOAuthProviders() map[string]interface{} {
|
|
providers := make(map[string]interface{})
|
|
for key, oauth := range hs.SocialService.GetOAuthInfoProviders() {
|
|
providers[key] = map[string]string{
|
|
"name": oauth.Name,
|
|
"icon": oauth.Icon,
|
|
}
|
|
}
|
|
return providers
|
|
}
|