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