package renderer import ( "fmt" "html/template" "net/http" "git.coopgo.io/coopgo-apps/parcoursmob/utils/icons" "git.coopgo.io/coopgo-apps/parcoursmob/utils/identification" "git.coopgo.io/coopgo-platform/emailing" "git.coopgo.io/coopgo-platform/groups-management/storage" "github.com/coreos/go-oidc" "github.com/spf13/viper" ) type Renderer struct { TemplatesDir string GlobalConfig *viper.Viper ThemeConfig *viper.Viper Mailer *emailing.Mailer } func NewRenderer(global *viper.Viper, templates_dir string) *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, } } 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)) } w.WriteHeader(http.StatusOK) t := template.New(name).Funcs( template.FuncMap{ "timeFrom": TimeFrom, "timeFormat": TimeFormat, "genderISO5218": GenderISO5218, "dict": Dict, "json": JSON, "walkingLength": WalkingLength, "divideFloat64": Divide[float64], "divideInt": Divide[int], }, ) t = template.Must(t.ParseFiles(prefixed_files...)) err := t.ExecuteTemplate(w, "main", state) if err != nil { fmt.Println(err) } } 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)) } w.WriteHeader(http.StatusOK) t := template.New(name).Funcs( template.FuncMap{ "timeFrom": TimeFrom, "timeFormat": TimeFormat, "genderISO5218": GenderISO5218, "dict": Dict, "json": JSON, "divideFloat64": Divide[float64], "divideInt": Divide[int], }, ) t = template.Must(t.ParseFiles(prefixed_files...)) err := t.ExecuteTemplate(w, "main", state) if err != nil { fmt.Println(err) } } 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 } func NewState(r *http.Request, themeConfig *viper.Viper, menuState string) RenderState { iconset := themeConfig.GetStringMapString("icons.svg") // Get State elements from Request var userid string var claims map[string]any u := r.Context().Value(identification.IdtokenKey) if u != nil { if current_user_token, ok := u.(*oidc.IDToken); ok { userid = current_user_token.Subject } c := r.Context().Value(identification.ClaimsKey) if c != nil { if current_user_claims, ok := c.(map[string]any); ok { claims = current_user_claims } } } g := r.Context().Value(identification.GroupKey) if g == nil { return RenderState{ IconSet: icons.NewIconSet(iconset), LayoutState: LayoutState{}, } } var roles map[string]any ro, ok := r.Context().Value(identification.RolesKey).(map[string]any) if ok { roles = ro } group := g.(storage.Group) modules := group.Data["modules"].(map[string]any) ls := LayoutState{ AdministrationState: AdministrationState{ Display: modules["administration"] != nil && modules["administration"].(bool), Active: menuState == administrationMenu, }, //TODO from configuration for icons at least MenuItems: []MenuItem{ { Title: "Tableau de bord", Link: "/app/", Active: menuState == dashboardMenu, Icon: "hero:outline/home", }, }, } if modules["beneficiaries"] != nil && modules["beneficiaries"].(bool) { ls.MenuItems = append(ls.MenuItems, MenuItem{ Title: "Bénéficiaires", Link: "/app/beneficiaries/", Active: menuState == beneficiariesMenu, Icon: "hero:outline/user-group", }) } if modules["journeys"] != nil && modules["journeys"].(bool) { ls.MenuItems = append(ls.MenuItems, MenuItem{ Title: "Déplacements", Link: "/app/journeys/", Active: menuState == journeysMenu, Icon: "hero:outline/map", }) } if modules["vehicles"] != nil && modules["vehicles"].(bool) { ls.MenuItems = append(ls.MenuItems, MenuItem{ Title: "Véhicules partagés", Link: "/app/vehicles/", Active: menuState == vehiclesMenu, Icon: "tabler-icons:car", }) } if modules["vehicles_management"] != nil && modules["vehicles_management"].(bool) { ls.MenuItems = append(ls.MenuItems, MenuItem{ Title: "Gestion des véhicules", Link: "/app/vehicles-management/", Active: menuState == vehiclesmanagementMenu, Icon: "hero:outline/briefcase", }) } if modules["agenda"] != nil && modules["agenda"].(bool) { ls.MenuItems = append(ls.MenuItems, MenuItem{ Title: "Agenda dispositifs", Link: "/app/agenda/", Active: menuState == agendaMenu, Icon: "hero:outline/calendar", }) } if modules["support"] != nil && modules["support"].(bool) { ls.MenuItems = append(ls.MenuItems, MenuItem{ Title: "Support", Link: "/app/support/", Active: menuState == commentMenu, Icon: "hero:outline/support", }) } if modules["group_module"] != nil && modules["group_module"].(bool) { ls.MenuItems = append(ls.MenuItems, MenuItem{ Title: "Groupes / Communautés", Link: "/app/group_module/", Active: menuState == groupMenu, Icon: "hero:outline/group_module", }) } if modules["directory"] != nil && modules["directory"].(bool) { ls.MenuItems = append(ls.MenuItems, MenuItem{ Title: "Répertoire solutions", Link: "/app/directory/", Active: menuState == directoryMenu, Icon: "hero:outline/document-text", }) } return RenderState{ IconSet: icons.NewIconSet(iconset), Group: group, Roles: roles, UserID: userid, UserClaims: claims, LayoutState: ls, } }