mirror of
https://github.com/gohugoio/hugo.git
synced 2025-04-20 12:43:06 +00:00
parent
9bd4236e1b
commit
0bbdef986d
7 changed files with 239 additions and 5 deletions
|
@ -13,6 +13,12 @@
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
// Provider provides the configuration settings for Hugo.
|
// Provider provides the configuration settings for Hugo.
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
GetString(key string) string
|
GetString(key string) string
|
||||||
|
@ -25,3 +31,14 @@ type Provider interface {
|
||||||
Set(key string, value interface{})
|
Set(key string, value interface{})
|
||||||
IsSet(key string) bool
|
IsSet(key string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FromConfigString creates a config from the given YAML, JSON or TOML config. This is useful in tests.
|
||||||
|
func FromConfigString(config, configType string) (Provider, error) {
|
||||||
|
v := viper.New()
|
||||||
|
v.SetConfigType(configType)
|
||||||
|
if err := v.ReadConfig(strings.NewReader(config)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
85
config/privacy/privacyConfig.go
Normal file
85
config/privacy/privacyConfig.go
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
// Copyright 2018 The Hugo Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package privacy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
)
|
||||||
|
|
||||||
|
const privacyConfigKey = "privacy"
|
||||||
|
|
||||||
|
// Service is the common values for a service in a policy definition.
|
||||||
|
type Service struct {
|
||||||
|
Disable bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config is a privacy configuration for all the relevant services in Hugo.
|
||||||
|
type Config struct {
|
||||||
|
Disqus Disqus
|
||||||
|
GoogleAnalytics GoogleAnalytics
|
||||||
|
Instagram Instagram
|
||||||
|
SpeakerDeck SpeakerDeck
|
||||||
|
Tweet Tweet
|
||||||
|
Vimeo Vimeo
|
||||||
|
YouTube YouTube
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disqus holds the privacy configuration settings related to the Disqus template.
|
||||||
|
type Disqus struct {
|
||||||
|
Service `mapstructure:",squash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoogleAnalytics holds the privacy configuration settings related to the Google Analytics template.
|
||||||
|
type GoogleAnalytics struct {
|
||||||
|
Service `mapstructure:",squash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instagram holds the privacy configuration settings related to the Instagram shortcode.
|
||||||
|
type Instagram struct {
|
||||||
|
Service `mapstructure:",squash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SpeakerDeck holds the privacy configuration settings related to the SpeakerDeck shortcode.
|
||||||
|
type SpeakerDeck struct {
|
||||||
|
Service `mapstructure:",squash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tweet holds the privacy configuration settingsrelated to the Tweet shortcode.
|
||||||
|
type Tweet struct {
|
||||||
|
Service `mapstructure:",squash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vimeo holds the privacy configuration settingsrelated to the Vimeo shortcode.
|
||||||
|
type Vimeo struct {
|
||||||
|
Service `mapstructure:",squash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// YouTube holds the privacy configuration settingsrelated to the YouTube shortcode.
|
||||||
|
type YouTube struct {
|
||||||
|
Service `mapstructure:",squash"`
|
||||||
|
NoCookie bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeConfig(cfg config.Provider) (pc Config, err error) {
|
||||||
|
if !cfg.IsSet(privacyConfigKey) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m := cfg.GetStringMap(privacyConfigKey)
|
||||||
|
|
||||||
|
err = mapstructure.WeakDecode(m, &pc)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
93
config/privacy/privacyConfig_test.go
Normal file
93
config/privacy/privacyConfig_test.go
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
// Copyright 2018 The Hugo Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package privacy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDecodeConfigFromTOML(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
|
||||||
|
tomlConfig := `
|
||||||
|
|
||||||
|
someOtherValue = "foo"
|
||||||
|
|
||||||
|
[privacy]
|
||||||
|
[privacy.disqus]
|
||||||
|
disable = true
|
||||||
|
[privacy.googleAnalytics]
|
||||||
|
disable = true
|
||||||
|
[privacy.instagram]
|
||||||
|
disable = true
|
||||||
|
[privacy.speakerDeck]
|
||||||
|
disable = true
|
||||||
|
[privacy.tweet]
|
||||||
|
disable = true
|
||||||
|
[privacy.vimeo]
|
||||||
|
disable = true
|
||||||
|
[privacy.youtube]
|
||||||
|
disable = true
|
||||||
|
noCookie = true
|
||||||
|
`
|
||||||
|
cfg, err := config.FromConfigString(tomlConfig, "toml")
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
pc, err := DecodeConfig(cfg)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(pc)
|
||||||
|
|
||||||
|
assert.True(pc.Disqus.Disable)
|
||||||
|
assert.True(pc.GoogleAnalytics.Disable)
|
||||||
|
assert.True(pc.Instagram.Disable)
|
||||||
|
assert.True(pc.SpeakerDeck.Disable)
|
||||||
|
assert.True(pc.Tweet.Disable)
|
||||||
|
assert.True(pc.Vimeo.Disable)
|
||||||
|
|
||||||
|
assert.True(pc.YouTube.NoCookie)
|
||||||
|
assert.True(pc.YouTube.Disable)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeConfigFromTOMLCaseInsensitive(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
|
||||||
|
tomlConfig := `
|
||||||
|
|
||||||
|
someOtherValue = "foo"
|
||||||
|
|
||||||
|
[Privacy]
|
||||||
|
[Privacy.YouTube]
|
||||||
|
NoCOOKIE = true
|
||||||
|
`
|
||||||
|
cfg, err := config.FromConfigString(tomlConfig, "toml")
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
pc, err := DecodeConfig(cfg)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(pc)
|
||||||
|
assert.True(pc.YouTube.NoCookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeConfigDefault(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
|
||||||
|
pc, err := DecodeConfig(viper.New())
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(pc)
|
||||||
|
assert.False(pc.YouTube.NoCookie)
|
||||||
|
}
|
|
@ -365,3 +365,25 @@ map[string]interface {}{
|
||||||
}`, got["menu"])
|
}`, got["menu"])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrivacyConfig(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := require.New(t)
|
||||||
|
|
||||||
|
tomlConfig := `
|
||||||
|
|
||||||
|
someOtherValue = "foo"
|
||||||
|
|
||||||
|
[privacy]
|
||||||
|
[privacy.youtube]
|
||||||
|
noCookie = true
|
||||||
|
`
|
||||||
|
|
||||||
|
b := newTestSitesBuilder(t)
|
||||||
|
b.WithConfigFile("toml", tomlConfig)
|
||||||
|
b.Build(BuildCfg{SkipRender: true})
|
||||||
|
|
||||||
|
assert.True(b.H.Sites[0].Info.PrivacyConfig.YouTube.NoCookie)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -168,7 +168,9 @@ func (h *HugoSites) assemble(config *BuildCfg) error {
|
||||||
if len(h.Sites) > 1 {
|
if len(h.Sites) > 1 {
|
||||||
// The first is initialized during process; initialize the rest
|
// The first is initialized during process; initialize the rest
|
||||||
for _, site := range h.Sites[1:] {
|
for _, site := range h.Sites[1:] {
|
||||||
site.initializeSiteInfo()
|
if err := site.initializeSiteInfo(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config/privacy"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/resource"
|
"github.com/gohugoio/hugo/resource"
|
||||||
|
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
@ -386,6 +388,12 @@ type SiteInfo struct {
|
||||||
preserveTaxonomyNames bool
|
preserveTaxonomyNames bool
|
||||||
Data *map[string]interface{}
|
Data *map[string]interface{}
|
||||||
|
|
||||||
|
// This contains all privacy related settings that can be used to
|
||||||
|
// make the YouTube template etc.GDPR compliant.
|
||||||
|
// It is mostly in use by Hugo's built-in, but is also available
|
||||||
|
// for end users with {{ .Site.PrivacyConfig.YouTube.NoCookie }} etc.
|
||||||
|
PrivacyConfig privacy.Config
|
||||||
|
|
||||||
owner *HugoSites
|
owner *HugoSites
|
||||||
s *Site
|
s *Site
|
||||||
multilingual *Multilingual
|
multilingual *Multilingual
|
||||||
|
@ -1028,14 +1036,13 @@ func (s *Site) Initialise() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Site) initialize() (err error) {
|
func (s *Site) initialize() (err error) {
|
||||||
defer s.initializeSiteInfo()
|
|
||||||
s.Menus = Menus{}
|
s.Menus = Menus{}
|
||||||
|
|
||||||
if err = s.checkDirectories(); err != nil {
|
if err = s.checkDirectories(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return s.initializeSiteInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
// HomeAbsURL is a convenience method giving the absolute URL to the home page.
|
// HomeAbsURL is a convenience method giving the absolute URL to the home page.
|
||||||
|
@ -1058,7 +1065,7 @@ func (s *SiteInfo) SitemapAbsURL() string {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Site) initializeSiteInfo() {
|
func (s *Site) initializeSiteInfo() error {
|
||||||
var (
|
var (
|
||||||
lang = s.Language
|
lang = s.Language
|
||||||
languages helpers.Languages
|
languages helpers.Languages
|
||||||
|
@ -1113,6 +1120,11 @@ func (s *Site) initializeSiteInfo() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
privacyConfig, err := privacy.DecodeConfig(lang)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
s.Info = SiteInfo{
|
s.Info = SiteInfo{
|
||||||
Title: lang.GetString("title"),
|
Title: lang.GetString("title"),
|
||||||
Author: lang.GetStringMap("author"),
|
Author: lang.GetStringMap("author"),
|
||||||
|
@ -1139,6 +1151,7 @@ func (s *Site) initializeSiteInfo() {
|
||||||
Data: &s.Data,
|
Data: &s.Data,
|
||||||
owner: s.owner,
|
owner: s.owner,
|
||||||
s: s,
|
s: s,
|
||||||
|
PrivacyConfig: privacyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
rssOutputFormat, found := s.outputFormats[KindHome].GetByName(output.RSSFormat.Name)
|
rssOutputFormat, found := s.outputFormats[KindHome].GetByName(output.RSSFormat.Name)
|
||||||
|
@ -1146,6 +1159,8 @@ func (s *Site) initializeSiteInfo() {
|
||||||
if found {
|
if found {
|
||||||
s.Info.RSSLink = s.permalink(rssOutputFormat.BaseFilename())
|
s.Info.RSSLink = s.permalink(rssOutputFormat.BaseFilename())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Site) dataDir() string {
|
func (s *Site) dataDir() string {
|
||||||
|
|
|
@ -55,7 +55,7 @@ func TestShouldNotAddTrailingSlashToBaseURL(t *testing.T) {
|
||||||
d := deps.DepsCfg{Cfg: cfg, Fs: fs}
|
d := deps.DepsCfg{Cfg: cfg, Fs: fs}
|
||||||
s, err := NewSiteForCfg(d)
|
s, err := NewSiteForCfg(d)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
s.initializeSiteInfo()
|
require.NoError(t, s.initializeSiteInfo())
|
||||||
|
|
||||||
if s.Info.BaseURL() != template.URL(this.expected) {
|
if s.Info.BaseURL() != template.URL(this.expected) {
|
||||||
t.Errorf("[%d] got %s expected %s", i, s.Info.BaseURL(), this.expected)
|
t.Errorf("[%d] got %s expected %s", i, s.Info.BaseURL(), this.expected)
|
||||||
|
|
Loading…
Add table
Reference in a new issue