diff --git a/config/config.go b/config/config.go index 5b62b2b..95ac885 100644 --- a/config/config.go +++ b/config/config.go @@ -59,16 +59,13 @@ func (*AmCLI) Version() string { // AmConfig holds the configuration of the application as read from YAML. type AmConfig struct { Site struct { - BaseURL string `yaml:"baseURL"` - Title string `yaml:"title"` - TopRefresh int `yaml:"topRefresh"` - LoginCookieName string `yaml:"loginCookieName"` - LoginCookieAge int `yaml:"loginCookieAge"` - SessionExpire string `yaml:"sessionExpire"` - UserAgreement struct { - Title string `yaml:"title"` - Text string `yaml:"text"` - } `yaml:"userAgreement"` + BaseURL string `yaml:"baseURL"` + Title string `yaml:"title"` + TopRefresh int `yaml:"topRefresh"` + LoginCookieName string `yaml:"loginCookieName"` + LoginCookieAge int `yaml:"loginCookieAge"` + SessionExpire string `yaml:"sessionExpire"` + UserAgreementResource string `yaml:"userAgreementResource"` } `yaml:"site"` Database struct { Driver string `yaml:"driver"` @@ -98,8 +95,9 @@ type AmConfig struct { VeniceCompatibleImageURLs bool `yaml:"veniceCompatibleImageURLs"` } `yaml:"rendering"` Resources struct { - ViewTemplateDir string `yaml:"viewTemplateDir"` - ExternalContentPath string `yaml:"externalContentPath"` + ViewTemplateDir string `yaml:"viewTemplateDir"` + ExternalContentPath string `yaml:"externalContentPath"` + ExternalResourcePath string `yaml:"externalResourcePath"` } `yaml:"resources"` Posting struct { ExternalDictionary string `yaml:"externalDictionary"` diff --git a/config/default.yaml b/config/default.yaml index d27ab46..1751f92 100644 --- a/config/default.yaml +++ b/config/default.yaml @@ -13,10 +13,7 @@ site: loginCookieName: AmsterdamAuth loginCookieAge: 365 sessionExpire: "3h" - userAgreement: - title: "Amsterdam User Agreement" - text: > - Text of this agreement is TBD. + userAgreementResource: "useragreement.html" database: driver: "mysql" dsn: "amsdb:x00yes2k@tcp(localhost)/amsterdam?parseTime=true&loc=UTC" @@ -46,6 +43,7 @@ rendering: resources: viewTemplateDir: "" externalContentPath: "" + externalResourcePath: "" posting: externalDictionary: "" uploads: diff --git a/login.go b/login.go index 19c7972..666616d 100644 --- a/login.go +++ b/login.go @@ -14,6 +14,7 @@ import ( "net/url" "time" + "git.erbosoft.com/amy/amsterdam/config" "git.erbosoft.com/amy/amsterdam/database" "git.erbosoft.com/amy/amsterdam/email" "git.erbosoft.com/amy/amsterdam/ui" @@ -316,7 +317,7 @@ func NewAccountUserAgreement(ctxt ui.AmContext) (string, any) { } // Load the user agreement from the resources. - agreementTitle, agreementBody, err := ui.AmLoadHTMLResource("useragreement.html") + agreementTitle, agreementBody, err := ui.AmLoadHTMLResource(config.GlobalConfig.Site.UserAgreementResource) if err != nil { return "error", err } diff --git a/ui/static.go b/ui/static.go index 44f53bd..7683d5e 100644 --- a/ui/static.go +++ b/ui/static.go @@ -16,10 +16,13 @@ import ( "io" "io/fs" "net/http" + "os" "path/filepath" "strings" + "git.erbosoft.com/amy/amsterdam/config" "github.com/labstack/echo/v4" + log "github.com/sirupsen/logrus" "golang.org/x/net/html" ) @@ -29,8 +32,27 @@ var static_data embed.FS //go:embed resources/* var static_resources embed.FS +// external_resources is the link to the external resource path. +var external_resources fs.FS = nil + func setupResources() { - // do nothing yet + // Open the external resource path. + if config.GlobalConfig.Resources.ExternalResourcePath != "" { + finfo, err := os.Stat(config.GlobalConfig.Resources.ExternalResourcePath) + if err == nil { + if finfo.IsDir() { + root, err := os.OpenRoot(config.GlobalConfig.Resources.ExternalResourcePath) + if err != nil { + panic(err) + } + external_resources = root.FS() + } else { + log.Errorf("external resource path \"%s\" is not a directory, ignored", config.GlobalConfig.Resources.ExternalResourcePath) + } + } else { + log.Errorf("external resource path \"%s\" is not valid, ignored (%v)", config.GlobalConfig.Resources.ExternalResourcePath, err) + } + } } // AmStaticFileHandler returns a handler for the files in the static embedded filesystem. @@ -95,9 +117,26 @@ func breakUpHTML(r io.Reader) (string, string, error) { // AmLoadHTMLResource loads an HTML resource and splits it into title and body. func AmLoadHTMLResource(resourceName string) (string, string, error) { - f, err := static_resources.Open(filepath.Join("resources", resourceName)) - if err != nil { - return "", "", err + var f fs.File = nil + var err error + if external_resources != nil { + f, err = external_resources.Open(resourceName) + if err != nil { + f = nil + pe := err.(*fs.PathError) + if pe.Err == os.ErrInvalid || pe.Err == os.ErrNotExist { + err = nil + } + } + if err != nil { + return "", "", err + } + } + if f == nil { + f, err = static_resources.Open(filepath.Join("resources", resourceName)) + if err != nil { + return "", "", err + } } title, body, err := breakUpHTML(f) f.Close()