diff --git a/internal/config/config.go b/internal/config/config.go index a67f693..b172be5 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -24,7 +24,7 @@ type Config struct { Listen ListenConfig `yaml:"listen" recurse:"true"` Paths PathsConfig `yaml:"paths" recurse:"true"` HTTP HTTPConfig `yaml:"http" recurse:"true"` - Theme ThemeConfig `yaml:"theme" recurse:"true"` + Home HomeConfig `yaml:"home" recurse:"true"` Docker DockerConfig `yaml:"docker" recurse:"true"` SQL SQLConfig `yaml:"sql" recurse:"true"` diff --git a/internal/config/config.yml b/internal/config/config.yml index 7dab9a4..94bfb28 100644 --- a/internal/config/config.yml +++ b/internal/config/config.yml @@ -39,10 +39,24 @@ http: # This email address can be configured here. certbot_email: null -# By default, the default domain redirects to the distillery repository. -# If you want to change this, set an alternate domain name here. -theme: - home: null +# Configuration for the (public) homepage of the distillery. +home: + # the url to redirect to for more information about this instance of the distillery. + # to be configured by default. + redirect: null + + # configure the list of systems on the homepage. + list: + # is the list of WissKIs visible for the public? + # if this is disabled, only the generic text is shown. + public: null + + # is the list of WissKIs visible to logged in users? + # if this is disabled, only the generic text is shown. + private: null + + # Title of the list (whenever it is shown) + title: null docker: # The distillery uses several global docker networks. diff --git a/internal/config/home.go b/internal/config/home.go index 58e1f79..bfe0d17 100644 --- a/internal/config/home.go +++ b/internal/config/home.go @@ -2,9 +2,17 @@ package config import "github.com/FAU-CDI/wisski-distillery/internal/config/validators" -// ThemeConfig determines theming options -type ThemeConfig struct { - // By default, the default domain redirects to the distillery repository. - // If you want to change this, set an alternate domain name here. - SelfRedirect *validators.URL `yaml:"home" default:"https://github.com/FAU-CDI/wisski-distillery" validate:"https"` +// HomeConfig determines options for the homepage of the distillery +type HomeConfig struct { + SelfRedirect *validators.URL `yaml:"redirect" default:"https://github.com/FAU-CDI/wisski-distillery" validate:"https"` + List HomeListConfig `yaml:"list" recurse:"true"` +} + +type HomeListConfig struct { + // Is the list enabled for public visits? + Public validators.NullableBool `yaml:"public" default:"true" validate:"bool"` + // Is the list enabled for signed-in visits? + Private validators.NullableBool `yaml:"private" default:"true" validate:"bool"` + // Title of the list whenever it is shown + Title string `yaml:"title" default:"WissKIs on this Distillery" validate:"nonempty"` } diff --git a/internal/config/validators/bool.go b/internal/config/validators/bool.go new file mode 100644 index 0000000..779ecc4 --- /dev/null +++ b/internal/config/validators/bool.go @@ -0,0 +1,41 @@ +package validators + +import ( + "strconv" + + "gopkg.in/yaml.v3" +) + +// NullableBool represents a bool that can be null +type NullableBool struct { + Null, Value bool +} + +func (nb *NullableBool) UnmarshalYAML(value *yaml.Node) error { + nb.Null = false + if err := value.Decode(&nb.Value); err != nil { + nb.Null = true + nb.Value = false + } + + return nil +} + +func (nb *NullableBool) MarshalYAML() (interface{}, error) { + if nb.Null { + return nil, nil + } + return nb.Value, nil +} + +func ValidateBool(value *NullableBool, dflt string) (err error) { + if value.Null { + res, err := strconv.ParseBool(dflt) + if err != nil { + return err + } + value.Null = false + value.Value = res + } + return err +} diff --git a/internal/config/validators/collection.go b/internal/config/validators/collection.go index e38973f..7886f90 100644 --- a/internal/config/validators/collection.go +++ b/internal/config/validators/collection.go @@ -10,6 +10,8 @@ func New() validator.Collection { validator.Add(coll, "nonempty", ValidateNonempty) + validator.Add(coll, "bool", ValidateBool) + validator.Add(coll, "directory", ValidateDirectory) validator.Add(coll, "file", ValidateFile) diff --git a/internal/dis/component/server/home/home.go b/internal/dis/component/server/home/home.go index 0b518e5..d9c3cff 100644 --- a/internal/dis/component/server/home/home.go +++ b/internal/dis/component/server/home/home.go @@ -6,6 +6,7 @@ import ( "net/http" "github.com/FAU-CDI/wisski-distillery/internal/dis/component" + "github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth" "github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances" "github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating" "github.com/FAU-CDI/wisski-distillery/internal/status" @@ -17,6 +18,7 @@ type Home struct { Dependencies struct { Templating *templating.Templating Instances *instances.Instances + Auth *auth.Auth } instanceNames lazy.Lazy[map[string]struct{}] // instance names diff --git a/internal/dis/component/server/home/public.go b/internal/dis/component/server/home/public.go index beb3dd9..3a83f6d 100644 --- a/internal/dis/component/server/home/public.go +++ b/internal/dis/component/server/home/public.go @@ -28,7 +28,8 @@ var aboutTemplate = template.Must(template.New("about.html").Parse(aboutHTML)) // aboutContext is passed to about.html type aboutContext struct { - Instances []status.WissKI + Instances []status.WissKI // list of WissKI Instancaes + SignedIn bool // is there a signed in user? Logo template.HTML SelfRedirect string } @@ -38,6 +39,10 @@ type publicContext struct { templating.RuntimeFlags aboutContext + + ListEnabled bool // is the list of instances enabled? + ListTitle string // what is the title of the list of instances? + About template.HTML } @@ -66,7 +71,11 @@ func (home *Home) publicHandler(ctx context.Context) http.Handler { // prepare about pc.aboutContext.Logo = logoHTML pc.aboutContext.Instances = home.homeInstances.Get(nil) - pc.aboutContext.SelfRedirect = home.Config.Theme.SelfRedirect.String() + pc.aboutContext.SelfRedirect = home.Config.Home.SelfRedirect.String() + { + user, _ := home.Dependencies.Auth.UserOf(r) + pc.aboutContext.SignedIn = user != nil + } // render the about template @@ -77,6 +86,17 @@ func (home *Home) publicHandler(ctx context.Context) http.Handler { // and return about! pc.About = template.HTML(builder.String()) + // user is not signed in! + + if pc.aboutContext.SignedIn { + pc.ListEnabled = home.Config.Home.List.Private.Value + } else { + pc.ListEnabled = home.Config.Home.List.Public.Value + } + + // title of the list + pc.ListTitle = home.Config.Home.List.Title + return }) } diff --git a/internal/dis/component/server/home/public.html b/internal/dis/component/server/home/public.html index 822cd90..8712032 100644 --- a/internal/dis/component/server/home/public.html +++ b/internal/dis/component/server/home/public.html @@ -1,25 +1,27 @@ {{ .About }} -
-

WissKIs on this Distillery

-
+{{ if .ListEnabled }} +
+

{{ .ListTitle }}

+
-{{range .Instances}} - {{ if and .Running (not .NoPrefixes) }} -
-

{{.Slug}}

-

- {{.URL}}
- - {{ .Statistics.Bundles.Summary }} + {{range .Instances}} + {{ if and .Running (not .NoPrefixes) }} +

+

{{.Slug}}

+

+ {{.URL}}
+ + {{ .Statistics.Bundles.Summary }} - {{ $edit := .Statistics.Bundles.LastEdit }} - {{ if $edit.Valid }} -
- last edited {{ $edit.Time.Format "2006-01-02T15:04:05Z07:00" }} - {{ end }} -
-

-
+ {{ $edit := .Statistics.Bundles.LastEdit }} + {{ if $edit.Valid }} +
+ last edited {{ $edit.Time.Format "2006-01-02T15:04:05Z07:00" }} + {{ end }} +
+

+
+ {{ end }} {{ end }} -{{ end }} +{{ end }} \ No newline at end of file diff --git a/program.go b/program.go index 65cf155..e226760 100644 --- a/program.go +++ b/program.go @@ -59,6 +59,12 @@ var errUserIsNotRoot = exit.Error{ Message: "this command has to be executed as root. the current user is not root", } +// an error when cgo is enabled +var errCGoEnabled = exit.Error{ + ExitCode: exit.ExitGeneralArguments, + Message: "this command has to be executed as root. the current user is not root", +} + const warnNoDeployWdcli = "Warning: Not using %q executable at %q. This might leave the distillery in an inconsistent state. \n" func NewProgram() Program {