package renderer
import (
"bytes"
"fmt"
"html/template"
"net/http"
"git.coopgo.io/coopgo-apps/parcoursmob/core/utils/icons"
"git.coopgo.io/coopgo-apps/parcoursmob/core/utils/identification"
cache "git.coopgo.io/coopgo-apps/parcoursmob/core/utils/storage"
xlsxrenderer "git.coopgo.io/coopgo-apps/parcoursmob/renderer/xlsx"
"git.coopgo.io/coopgo-platform/emailing"
"git.coopgo.io/coopgo-platform/groups-management/storage"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
)
type Renderer struct {
TemplatesDir string
GlobalConfig *viper.Viper
ThemeConfig *viper.Viper
Mailer *emailing.Mailer
FileStorage cache.FileStorage
XLSX *xlsxrenderer.XLSXRenderer
}
func NewRenderer(global *viper.Viper, templates_dir string, filestorage cache.FileStorage) *Renderer {
theme := viper.New()
theme.SetConfigName("config")
theme.AddConfigPath(templates_dir)
err := theme.ReadInConfig()
if err != nil {
panic(fmt.Errorf("fatal error config file: %w", err))
}
return &Renderer{
TemplatesDir: templates_dir,
GlobalConfig: global,
ThemeConfig: theme,
FileStorage: filestorage,
XLSX: xlsxrenderer.NewXLSXRenderer(global),
}
}
func (renderer *Renderer) Render(name string, w http.ResponseWriter, r *http.Request, files []string, state RenderState) {
genericFiles := renderer.ThemeConfig.GetStringSlice("views.generic.files")
prefixed_files := []string{}
for _, f := range genericFiles {
prefixed_files = append(prefixed_files, renderer.templateFile(f))
}
for _, f := range files {
prefixed_files = append(prefixed_files, renderer.templateFile(f))
}
t := template.New(name).Funcs(GetTemplateFuncMap(state.Group, renderer.GlobalConfig, renderer.FileStorage))
t = template.Must(t.ParseFiles(prefixed_files...))
// Render to buffer first to avoid write timeouts during template execution
var buf bytes.Buffer
err := t.ExecuteTemplate(&buf, "main", state)
if err != nil {
log.Error().Err(err).Msg("issue executing template")
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
_, err = buf.WriteTo(w)
if err != nil {
log.Error().Err(err).Msg("issue writing template to response")
}
}
func (renderer *Renderer) RenderNoLayout(name string, w http.ResponseWriter, r *http.Request, files []string, state RenderState) {
prefixed_files := []string{}
for _, f := range files {
prefixed_files = append(prefixed_files, renderer.templateFile(f))
}
t := template.New(name).Funcs(GetTemplateFuncMap(state.Group, renderer.GlobalConfig, renderer.FileStorage))
t = template.Must(t.ParseFiles(prefixed_files...))
// Render to buffer first to avoid write timeouts during template execution
var buf bytes.Buffer
err := t.ExecuteTemplate(&buf, "main", state)
if err != nil {
log.Error().Err(err).Msg("issue executing template")
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
_, err = buf.WriteTo(w)
if err != nil {
log.Error().Err(err).Msg("issue writing template to response")
}
}
func (r *Renderer) templateFile(file string) string {
return r.TemplatesDir + file
}
type RenderState struct {
icons.IconSet
LayoutState
UserID string
UserClaims map[string]any
Group storage.Group
Roles any
ViewState any // This is a state specific to a given view
DynamicData any // Data to be serialized as JSON in a