mirror of
https://github.com/thomiceli/opengist
synced 2024-11-08 12:55:50 +01:00
Add custom static links (#234)
This commit is contained in:
parent
c185cb8933
commit
3f5f4e01f1
10
config.yml
10
config.yml
@ -97,6 +97,14 @@ oidc.discovery-url:
|
||||
|
||||
|
||||
# Custom assets
|
||||
# Add your own custom assets to $opengist-home/custom/
|
||||
# Add your own custom assets, that are files relatives to $opengist-home/custom/
|
||||
custom.logo:
|
||||
custom.favicon:
|
||||
|
||||
# Static pages in footer (like legal notices, privacy policy, etc.)
|
||||
# The path can be a URL or a relative path to a file in the $opengist-home/custom/ directory
|
||||
custom.static-links:
|
||||
# - name: Gitea
|
||||
# path: https://gitea.com
|
||||
# - name: Legal notices
|
||||
# path: legal.html
|
||||
|
@ -1,36 +1,37 @@
|
||||
# Configuration Cheat Sheet
|
||||
|
||||
| YAML Config Key | Environment Variable | Default value | Description |
|
||||
|-----------------------|--------------------------|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| log-level | OG_LOG_LEVEL | `warn` | Set the log level to one of the following: `trace`, `debug`, `info`, `warn`, `error`, `fatal`, `panic`. |
|
||||
| log-output | OG_LOG_OUTPUT | `stdout,file` | Set the log output to one or more of the following: `stdout`, `file`. |
|
||||
| external-url | OG_EXTERNAL_URL | none | Public URL to access to Opengist. |
|
||||
| opengist-home | OG_OPENGIST_HOME | home directory | Path to the directory where Opengist stores its data. |
|
||||
| db-filename | OG_DB_FILENAME | `opengist.db` | Name of the SQLite database file. |
|
||||
| index.enabled | OG_INDEX_ENABLED | `true` | Enable or disable the code search index (`true` or `false`) |
|
||||
| index.dirname | OG_INDEX_DIRNAME | `opengist.index` | Name of the directory where the code search index is stored. |
|
||||
| git.default-branch | OG_GIT_DEFAULT_BRANCH | none | Default branch name used by Opengist when initializing Git repositories. If not set, uses the Git default branch name. More info [here](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup#_new_default_branch) |
|
||||
| sqlite.journal-mode | OG_SQLITE_JOURNAL_MODE | `WAL` | Set the journal mode for SQLite. More info [here](https://www.sqlite.org/pragma.html#pragma_journal_mode) |
|
||||
| http.host | OG_HTTP_HOST | `0.0.0.0` | The host on which the HTTP server should bind. |
|
||||
| http.port | OG_HTTP_PORT | `6157` | The port on which the HTTP server should listen. |
|
||||
| http.git-enabled | OG_HTTP_GIT_ENABLED | `true` | Enable or disable git operations (clone, pull, push) via HTTP. (`true` or `false`) |
|
||||
| ssh.git-enabled | OG_SSH_GIT_ENABLED | `true` | Enable or disable git operations (clone, pull, push) via SSH. (`true` or `false`) |
|
||||
| ssh.host | OG_SSH_HOST | `0.0.0.0` | The host on which the SSH server should bind. |
|
||||
| ssh.port | OG_SSH_PORT | `2222` | The port on which the SSH server should listen. |
|
||||
| ssh.external-domain | OG_SSH_EXTERNAL_DOMAIN | none | Public domain for the Git SSH connection, if it has to be different from the HTTP one. If not set, uses the URL from the request. |
|
||||
| ssh.keygen-executable | OG_SSH_KEYGEN_EXECUTABLE | `ssh-keygen` | Path to the SSH key generation executable. |
|
||||
| github.client-key | OG_GITHUB_CLIENT_KEY | none | The client key for the GitHub OAuth application. |
|
||||
| github.secret | OG_GITHUB_SECRET | none | The secret for the GitHub OAuth application. |
|
||||
| gitlab.client-key | OG_GITLAB_CLIENT_KEY | none | The client key for the GitLab OAuth application. |
|
||||
| gitlab.secret | OG_GITLAB_SECRET | none | The secret for the GitLab OAuth application. |
|
||||
| gitlab.url | OG_GITLAB_URL | `https://gitlab.com/` | The URL of the GitLab instance. |
|
||||
| gitlab.name | OG_GITLAB_NAME | `GitLab` | The name of the GitLab instance. It is displayed in the OAuth login button. |
|
||||
| gitea.client-key | OG_GITEA_CLIENT_KEY | none | The client key for the Gitea OAuth application. |
|
||||
| gitea.secret | OG_GITEA_SECRET | none | The secret for the Gitea OAuth application. |
|
||||
| gitea.url | OG_GITEA_URL | `https://gitea.com/` | The URL of the Gitea instance. |
|
||||
| gitea.name | OG_GITEA_NAME | `Gitea` | The name of the Gitea instance. It is displayed in the OAuth login button. |
|
||||
| oidc.client-key | OG_OIDC_CLIENT_KEY | none | The client key for the OpenID application. |
|
||||
| oidc.secret | OG_OIDC_SECRET | none | The secret for the OpenID application. |
|
||||
| oidc.discovery-url | OG_OIDC_DISCOVERY_URL | none | Discovery endpoint of the OpenID provider. |
|
||||
| custom.logo | OG_CUSTOM_LOGO | none | Path to an image, relative to $opengist-home/custom |
|
||||
| custom.favicon | OG_CUSTOM_FAVICON | none | Path to an image, relative to $opengist-home/custom |
|
||||
| YAML Config Key | Environment Variable | Default value | Description |
|
||||
|-----------------------|-------------------------------------|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| log-level | OG_LOG_LEVEL | `warn` | Set the log level to one of the following: `trace`, `debug`, `info`, `warn`, `error`, `fatal`, `panic`. |
|
||||
| log-output | OG_LOG_OUTPUT | `stdout,file` | Set the log output to one or more of the following: `stdout`, `file`. |
|
||||
| external-url | OG_EXTERNAL_URL | none | Public URL to access to Opengist. |
|
||||
| opengist-home | OG_OPENGIST_HOME | home directory | Path to the directory where Opengist stores its data. |
|
||||
| db-filename | OG_DB_FILENAME | `opengist.db` | Name of the SQLite database file. |
|
||||
| index.enabled | OG_INDEX_ENABLED | `true` | Enable or disable the code search index (`true` or `false`) |
|
||||
| index.dirname | OG_INDEX_DIRNAME | `opengist.index` | Name of the directory where the code search index is stored. |
|
||||
| git.default-branch | OG_GIT_DEFAULT_BRANCH | none | Default branch name used by Opengist when initializing Git repositories. If not set, uses the Git default branch name. More info [here](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup#_new_default_branch) |
|
||||
| sqlite.journal-mode | OG_SQLITE_JOURNAL_MODE | `WAL` | Set the journal mode for SQLite. More info [here](https://www.sqlite.org/pragma.html#pragma_journal_mode) |
|
||||
| http.host | OG_HTTP_HOST | `0.0.0.0` | The host on which the HTTP server should bind. |
|
||||
| http.port | OG_HTTP_PORT | `6157` | The port on which the HTTP server should listen. |
|
||||
| http.git-enabled | OG_HTTP_GIT_ENABLED | `true` | Enable or disable git operations (clone, pull, push) via HTTP. (`true` or `false`) |
|
||||
| ssh.git-enabled | OG_SSH_GIT_ENABLED | `true` | Enable or disable git operations (clone, pull, push) via SSH. (`true` or `false`) |
|
||||
| ssh.host | OG_SSH_HOST | `0.0.0.0` | The host on which the SSH server should bind. |
|
||||
| ssh.port | OG_SSH_PORT | `2222` | The port on which the SSH server should listen. |
|
||||
| ssh.external-domain | OG_SSH_EXTERNAL_DOMAIN | none | Public domain for the Git SSH connection, if it has to be different from the HTTP one. If not set, uses the URL from the request. |
|
||||
| ssh.keygen-executable | OG_SSH_KEYGEN_EXECUTABLE | `ssh-keygen` | Path to the SSH key generation executable. |
|
||||
| github.client-key | OG_GITHUB_CLIENT_KEY | none | The client key for the GitHub OAuth application. |
|
||||
| github.secret | OG_GITHUB_SECRET | none | The secret for the GitHub OAuth application. |
|
||||
| gitlab.client-key | OG_GITLAB_CLIENT_KEY | none | The client key for the GitLab OAuth application. |
|
||||
| gitlab.secret | OG_GITLAB_SECRET | none | The secret for the GitLab OAuth application. |
|
||||
| gitlab.url | OG_GITLAB_URL | `https://gitlab.com/` | The URL of the GitLab instance. |
|
||||
| gitlab.name | OG_GITLAB_NAME | `GitLab` | The name of the GitLab instance. It is displayed in the OAuth login button. |
|
||||
| gitea.client-key | OG_GITEA_CLIENT_KEY | none | The client key for the Gitea OAuth application. |
|
||||
| gitea.secret | OG_GITEA_SECRET | none | The secret for the Gitea OAuth application. |
|
||||
| gitea.url | OG_GITEA_URL | `https://gitea.com/` | The URL of the Gitea instance. |
|
||||
| gitea.name | OG_GITEA_NAME | `Gitea` | The name of the Gitea instance. It is displayed in the OAuth login button. |
|
||||
| oidc.client-key | OG_OIDC_CLIENT_KEY | none | The client key for the OpenID application. |
|
||||
| oidc.secret | OG_OIDC_SECRET | none | The secret for the OpenID application. |
|
||||
| oidc.discovery-url | OG_OIDC_DISCOVERY_URL | none | Discovery endpoint of the OpenID provider. |
|
||||
| custom.logo | OG_CUSTOM_LOGO | none | Path to an image, relative to $opengist-home/custom. |
|
||||
| custom.favicon | OG_CUSTOM_FAVICON | none | Path to an image, relative to $opengist-home/custom. |
|
||||
| custom.static-links | OG_CUSTOM_STATIC_LINK_#_(PATH,NAME) | none | Path and name to custom links, more info [here](custom-links.md). |
|
||||
|
31
docs/configuration/custom-assets.md
Normal file
31
docs/configuration/custom-assets.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Custom assets
|
||||
|
||||
To add custom assets to your Opengist instance, you can use the `$opengist-home/custom` directory (where `$opengist-home` is the directory where Opengist stores its data).
|
||||
|
||||
### Logo / Favicon
|
||||
|
||||
To add a custom logo or favicon, you can add your own image file to the `$opengist-home/custom` directory, then define the relative path in the config.
|
||||
|
||||
For example, if you have a logo file `logo.png` in the `$opengist-home/custom` directory, you can set the logo path in the config as follows:
|
||||
|
||||
#### YAML
|
||||
```yaml
|
||||
custom.logo: logo.png
|
||||
```
|
||||
|
||||
#### Environment variable
|
||||
```sh
|
||||
export OG_CUSTOM_LOGO=logo.png
|
||||
```
|
||||
|
||||
Same as the favicon:
|
||||
|
||||
#### YAML
|
||||
```yaml
|
||||
custom.favicon: favicon.png
|
||||
```
|
||||
|
||||
#### Environment variable
|
||||
```sh
|
||||
export OG_CUSTOM_FAVICON=favicon.png
|
||||
```
|
38
docs/configuration/custom-links.md
Normal file
38
docs/configuration/custom-links.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Custom links
|
||||
|
||||
On the footer of your Opengist instance, you can add links to custom static templates or any other website you want to link to.
|
||||
This can be useful for legal information, privacy policy, or any other information you want to provide to your users.
|
||||
|
||||
To add one or more links, you can add your own file to the `$opengist-home/custom` directory or set a URL, then define the relative path and its name in the config.
|
||||
|
||||
For example, if you have a legal information file `legal.html` in the `$opengist-home/custom` directory, and also wish to add a link to a Gitea instance, you can set the link in the config as follows:
|
||||
|
||||
#### YAML
|
||||
```yaml
|
||||
custom.static-links:
|
||||
- name: Legal notices
|
||||
path: legal.html
|
||||
- name: Gitea
|
||||
path: https://gitea.com
|
||||
```
|
||||
|
||||
#### Environment variable
|
||||
```sh
|
||||
OG_CUSTOM_STATIC_LINK_0_NAME="Legal Notices" \
|
||||
OG_CUSTOM_STATIC_LINK_0_PATH=legal.html \
|
||||
OG_CUSTOM_STATIC_LINK_1_NAME=Gitea \
|
||||
OG_CUSTOM_STATIC_LINK_1_PATH=https://gitea.com \
|
||||
./opengist
|
||||
```
|
||||
|
||||
## Templating custom HTML pages
|
||||
|
||||
In the start and end of the custom HTML files, you can use the syntax to include the header and footer of the Opengist instance:
|
||||
|
||||
```html
|
||||
{{ template "header" . }}
|
||||
|
||||
<!-- my content -->
|
||||
|
||||
{{ template "footer" . }}
|
||||
```
|
@ -63,8 +63,14 @@ type config struct {
|
||||
OIDCSecret string `yaml:"oidc.secret" env:"OG_OIDC_SECRET"`
|
||||
OIDCDiscoveryUrl string `yaml:"oidc.discovery-url" env:"OG_OIDC_DISCOVERY_URL"`
|
||||
|
||||
CustomLogo string `yaml:"custom.logo" env:"OG_CUSTOM_LOGO"`
|
||||
CustomFavicon string `yaml:"custom.favicon" env:"OG_CUSTOM_FAVICON"`
|
||||
CustomLogo string `yaml:"custom.logo" env:"OG_CUSTOM_LOGO"`
|
||||
CustomFavicon string `yaml:"custom.favicon" env:"OG_CUSTOM_FAVICON"`
|
||||
StaticLinks []StaticLink `yaml:"custom.static-links" env:"OG_CUSTOM_STATIC_LINK"`
|
||||
}
|
||||
|
||||
type StaticLink struct {
|
||||
Name string `yaml:"name" env:"OG_CUSTOM_STATIC_LINK_#_NAME"`
|
||||
Path string `yaml:"path" env:"OG_CUSTOM_STATIC_LINK_#_PATH"`
|
||||
}
|
||||
|
||||
func configWithDefaults() (*config, error) {
|
||||
@ -129,7 +135,6 @@ func InitConfig(configPath string, out io.Writer) error {
|
||||
if err = os.Setenv("OG_OPENGIST_HOME_INTERNAL", GetHomeDir()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -246,22 +251,63 @@ func loadConfigFromEnv(c *config, out io.Writer) error {
|
||||
}
|
||||
|
||||
envValue := os.Getenv(strings.ToUpper(tag))
|
||||
if envValue == "" {
|
||||
if envValue == "" && v.Field(i).Kind() != reflect.Slice {
|
||||
continue
|
||||
}
|
||||
|
||||
switch v.Field(i).Kind() {
|
||||
case reflect.String:
|
||||
v.Field(i).SetString(envValue)
|
||||
envVars = append(envVars, tag)
|
||||
case reflect.Bool:
|
||||
boolVal, err := strconv.ParseBool(envValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Field(i).SetBool(boolVal)
|
||||
envVars = append(envVars, tag)
|
||||
case reflect.Slice:
|
||||
if v.Type().Field(i).Type.Elem().Kind() == reflect.Struct {
|
||||
prefix := strings.ToUpper(tag) + "_"
|
||||
var sliceValue reflect.Value
|
||||
elemType := v.Type().Field(i).Type.Elem()
|
||||
|
||||
for index := 0; ; index++ {
|
||||
allFieldsPresent := true
|
||||
elemValue := reflect.New(elemType).Elem()
|
||||
|
||||
for j := 0; j < elemValue.NumField() && allFieldsPresent; j++ {
|
||||
elemField := elemValue.Type().Field(j)
|
||||
envName := fmt.Sprintf("%s%d_%s", prefix, index, strings.ToUpper(elemField.Name))
|
||||
envValue, present := os.LookupEnv(envName)
|
||||
|
||||
if !present {
|
||||
allFieldsPresent = false
|
||||
break
|
||||
}
|
||||
|
||||
envVars = append(envVars, envName)
|
||||
elemValue.Field(j).SetString(envValue)
|
||||
}
|
||||
|
||||
if !allFieldsPresent {
|
||||
break
|
||||
}
|
||||
|
||||
if sliceValue.Kind() != reflect.Slice {
|
||||
sliceValue = reflect.MakeSlice(v.Type().Field(i).Type, 0, index+1)
|
||||
}
|
||||
sliceValue = reflect.Append(sliceValue, elemValue)
|
||||
}
|
||||
|
||||
if sliceValue.IsValid() {
|
||||
v.Field(i).Set(sliceValue)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupported type: %s", v.Field(i).Kind())
|
||||
}
|
||||
|
||||
envVars = append(envVars, tag)
|
||||
}
|
||||
|
||||
if len(envVars) > 0 {
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/thomiceli/opengist/internal/index"
|
||||
"github.com/thomiceli/opengist/internal/utils"
|
||||
"github.com/thomiceli/opengist/templates"
|
||||
htmlpkg "html"
|
||||
"html/template"
|
||||
"io"
|
||||
@ -30,7 +31,6 @@ import (
|
||||
"github.com/thomiceli/opengist/internal/git"
|
||||
"github.com/thomiceli/opengist/internal/i18n"
|
||||
"github.com/thomiceli/opengist/public"
|
||||
"github.com/thomiceli/opengist/templates"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
@ -138,6 +138,10 @@ var (
|
||||
},
|
||||
"addMetadataToSearchQuery": addMetadataToSearchQuery,
|
||||
"indexEnabled": index.Enabled,
|
||||
"isUrl": func(s string) bool {
|
||||
_, err := url.ParseRequestURI(s)
|
||||
return err == nil
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@ -186,9 +190,22 @@ func NewServer(isDev bool) *Server {
|
||||
e.Use(middleware.Recover())
|
||||
e.Use(middleware.Secure())
|
||||
|
||||
e.Renderer = &Template{
|
||||
templates: template.Must(template.New("t").Funcs(fm).ParseFS(templates.Files, "*/*.html")),
|
||||
t := template.Must(template.New("t").Funcs(fm).ParseFS(templates.Files, "*/*.html"))
|
||||
customPattern := filepath.Join(config.GetHomeDir(), "custom", "*.html")
|
||||
matches, err := filepath.Glob(customPattern)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to check for custom templates")
|
||||
}
|
||||
if len(matches) > 0 {
|
||||
t, err = t.ParseGlob(customPattern)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to parse custom templates")
|
||||
}
|
||||
}
|
||||
e.Renderer = &Template{
|
||||
templates: t,
|
||||
}
|
||||
|
||||
e.HTTPErrorHandler = func(er error, ctx echo.Context) {
|
||||
if err, ok := er.(*echo.HTTPError); ok {
|
||||
if err.Code >= 500 {
|
||||
@ -211,14 +228,6 @@ func NewServer(isDev bool) *Server {
|
||||
if !dev {
|
||||
parseManifestEntries()
|
||||
}
|
||||
customFs := os.DirFS(filepath.Join(config.GetHomeDir(), "custom"))
|
||||
e.GET("/assets/*", func(c echo.Context) error {
|
||||
if _, err := public.Files.Open(path.Join("assets", c.Param("*"))); !dev && err == nil {
|
||||
return echo.WrapHandler(http.FileServer(http.FS(public.Files)))(c)
|
||||
}
|
||||
|
||||
return echo.WrapHandler(http.StripPrefix("/assets/", http.FileServer(http.FS(customFs))))(c)
|
||||
})
|
||||
|
||||
// Web based routes
|
||||
g1 := e.Group("")
|
||||
@ -309,6 +318,23 @@ func NewServer(isDev bool) *Server {
|
||||
}
|
||||
}
|
||||
|
||||
customFs := os.DirFS(filepath.Join(config.GetHomeDir(), "custom"))
|
||||
e.GET("/assets/*", func(ctx echo.Context) error {
|
||||
if _, err := public.Files.Open(path.Join("assets", ctx.Param("*"))); !dev && err == nil {
|
||||
return echo.WrapHandler(http.FileServer(http.FS(public.Files)))(ctx)
|
||||
}
|
||||
|
||||
// if the custom file is an .html template, render it
|
||||
if strings.HasSuffix(ctx.Param("*"), ".html") {
|
||||
if err := html(ctx, ctx.Param("*")); err != nil {
|
||||
return notFound("Page not found")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return echo.WrapHandler(http.StripPrefix("/assets/", http.FileServer(http.FS(customFs))))(ctx)
|
||||
})
|
||||
|
||||
// Git HTTP routes
|
||||
if config.C.HttpGit {
|
||||
e.Any("/:user/:gistname/*", gitHttp, gistSoftInit)
|
||||
|
9
templates/base/base_footer.html
vendored
9
templates/base/base_footer.html
vendored
@ -5,7 +5,7 @@
|
||||
|
||||
{{ define "footer" }}
|
||||
<div class="inline-flex py-8">
|
||||
<p class="text-slate-600 dark:text-slate-400 [&>*]:mx-1.5 flex">
|
||||
<p class="text-slate-600 dark:text-slate-400 [&>*]:mx-1.5 -ml-1.5 flex">
|
||||
<span>
|
||||
<a target="_blank" style="margin-left: 0 !important;" class="text-slate-600 dark:text-slate-400 hover:text-slate-800 dark:hover:text-slate-200 inline-flex" href="https://github.com/thomiceli/opengist">
|
||||
<span class="mr-1">{{ .locale.Tr "footer.powered-by" "<span class=\"font-bold dark:text-slate-300\">Opengist</span>" }} </span>
|
||||
@ -28,6 +28,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ if ne (len .c.StaticLinks) 0 }}
|
||||
<div class="ml-1.5">
|
||||
{{ range $index, $value := .c.StaticLinks }}
|
||||
⋅ <a href="{{ if isUrl .Path }}{{ .Path }}{{ else }}{{ $.c.ExternalUrl }}/assets/{{ .Path }}{{ end }}" class="text-slate-600 dark:text-slate-400 hover:text-slate-800 dark:hover:text-slate-200 inline-flex">{{ .Name }}</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user