Big refactoring of PARCOURSMOB - Initial commit

This commit is contained in:
2022-08-11 17:26:55 +02:00
commit 7225d027c9
65 changed files with 10276 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
package renderer
import "net/http"
const administrationMenu = "administration"
func (renderer *Renderer) Administration(w http.ResponseWriter, r *http.Request, groups any) {
files := renderer.ThemeConfig.GetStringSlice("views.administration.home.files")
state := NewState(r, renderer.ThemeConfig, administrationMenu)
state.ViewState = map[string]any{
"groups": groups,
}
renderer.Render("administration", w, r, files, state)
}
func (renderer *Renderer) AdministrationCreateGroup(w http.ResponseWriter, r *http.Request) {
files := renderer.ThemeConfig.GetStringSlice("views.administration.create_group.files")
state := NewState(r, renderer.ThemeConfig, administrationMenu)
renderer.Render("administration", w, r, files, state)
}
func (renderer *Renderer) AdministrationGroupDisplay(w http.ResponseWriter, r *http.Request, group any) {
files := renderer.ThemeConfig.GetStringSlice("views.administration.display_group.files")
state := NewState(r, renderer.ThemeConfig, administrationMenu)
state.ViewState = map[string]any{
"group": group,
}
renderer.Render("administration", w, r, files, state)
}

13
renderer/auth.go Normal file
View File

@@ -0,0 +1,13 @@
package renderer
import "net/http"
func (renderer *Renderer) AuthGroups(w http.ResponseWriter, r *http.Request, groups []any) {
files := renderer.ThemeConfig.GetStringSlice("views.auth.groups.files")
state := NewState(r, renderer.ThemeConfig, "")
state.ViewState = map[string]any{
"groups": groups,
}
renderer.RenderNoLayout("groups switch", w, r, files, state)
}

67
renderer/beneficiaries.go Normal file
View File

@@ -0,0 +1,67 @@
package renderer
import (
"encoding/json"
"html/template"
"net/http"
)
const beneficiariesMenu = "beneficiaries"
type BeneficiariesListState struct {
Count int `json:"count"`
CacheId string `json:"cache_id"`
Beneficiaries []any `json:"beneficiaries"`
}
func (s BeneficiariesListState) JSON() template.JS {
result, _ := json.Marshal(s)
return template.JS(result)
}
func (s BeneficiariesListState) JSONWithLimits(a int, b int) template.JS {
if b < len(s.Beneficiaries) {
s.Beneficiaries = s.Beneficiaries[a:b]
}
return s.JSON()
}
func (renderer *Renderer) BeneficiariesList(w http.ResponseWriter, r *http.Request, accounts []any, cacheid string) {
files := renderer.ThemeConfig.GetStringSlice("views.beneficiaries.list.files")
state := NewState(r, renderer.ThemeConfig, beneficiariesMenu)
state.ViewState = BeneficiariesListState{
Count: len(accounts),
CacheId: cacheid,
Beneficiaries: accounts,
}
renderer.Render("beneficiaries_list", w, r, files, state)
}
func (renderer *Renderer) BeneficiaryCreate(w http.ResponseWriter, r *http.Request) {
files := renderer.ThemeConfig.GetStringSlice("views.beneficiaries.create.files")
state := NewState(r, renderer.ThemeConfig, beneficiariesMenu)
renderer.Render("beneficiaries_create", w, r, files, state)
}
type BeneficiariesDisplayState struct {
Beneficiary any
}
func (renderer *Renderer) BeneficiaryDisplay(w http.ResponseWriter, r *http.Request, beneficiary any) {
files := renderer.ThemeConfig.GetStringSlice("views.beneficiaries.display.files")
state := NewState(r, renderer.ThemeConfig, beneficiariesMenu)
state.ViewState = beneficiary
renderer.Render("beneficiaries_display", w, r, files, state)
}
func (renderer *Renderer) BeneficiaryUpdate(w http.ResponseWriter, r *http.Request, beneficiary any) {
files := renderer.ThemeConfig.GetStringSlice("views.beneficiaries.update.files")
state := NewState(r, renderer.ThemeConfig, beneficiariesMenu)
state.ViewState = beneficiary
renderer.Render("beneficiaries_update", w, r, files, state)
}

20
renderer/dashboard.go Normal file
View File

@@ -0,0 +1,20 @@
package renderer
import (
"net/http"
)
const dashboardMenu = "dashboard"
func (renderer *Renderer) Dashboard(w http.ResponseWriter, r *http.Request, accounts []any, nbaccounts int) {
files := renderer.ThemeConfig.GetStringSlice("views.dashboard.files")
state := NewState(r, renderer.ThemeConfig, dashboardMenu)
state.ViewState = map[string]any{
"beneficiaries": map[string]any{
"count": nbaccounts,
"latest": accounts,
},
}
renderer.Render("dashboard", w, r, files, state)
}

77
renderer/func-maps.go Normal file
View File

@@ -0,0 +1,77 @@
package renderer
import (
"fmt"
"time"
)
func TimeFrom(d any) *time.Time {
if date, ok := d.(time.Time); ok {
return &date
} else if date, ok := d.(string); ok {
datetime, err := time.Parse("2006-01-02T15:04:05Z", date)
if err != nil {
panic(err)
}
return &datetime
}
return nil
}
func GenderISO5218(d any) string {
if date, ok := d.(string); ok {
switch date {
case "0":
return "Inconnu"
case "1":
return "Masculin"
case "2":
return "Féminin"
case "9":
return "Sans objet"
}
}
if date, ok := d.(int64); ok {
switch date {
case 0:
return "Inconnu"
case 1:
return "Masculin"
case 2:
return "Féminin"
case 9:
return "Sans objet"
}
}
return ""
}
func Dict(v ...interface{}) map[string]interface{} {
dict := map[string]interface{}{}
lenv := len(v)
for i := 0; i < lenv; i += 2 {
key := strval(v[i])
if i+1 >= lenv {
dict[key] = ""
continue
}
dict[key] = v[i+1]
}
return dict
}
func strval(v interface{}) string {
switch v := v.(type) {
case string:
return v
case []byte:
return string(v)
case error:
return v.Error()
case fmt.Stringer:
return v.String()
default:
return fmt.Sprintf("%v", v)
}
}

18
renderer/layout.go Normal file
View File

@@ -0,0 +1,18 @@
package renderer
type LayoutState struct {
AdministrationState AdministrationState
MenuItems []MenuItem
}
type MenuItem struct {
Title string
Link string
Active bool
Icon string
}
type AdministrationState struct {
Display bool
Active bool
}

184
renderer/renderer.go Normal file
View File

@@ -0,0 +1,184 @@
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/groups-management/storage"
"github.com/spf13/viper"
)
type Renderer struct {
TemplatesDir string
GlobalConfig *viper.Viper
ThemeConfig *viper.Viper
}
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,
"genderISO5218": GenderISO5218,
"dict": Dict,
},
)
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,
"genderISO5218": GenderISO5218,
"dict": Dict,
},
)
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
Group any
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
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"].(bool),
Active: menuState == administrationMenu,
},
MenuItems: []MenuItem{
{
Title: "Tableau de bord",
Link: "/app/",
Active: menuState == "dashboard",
Icon: "hero:outline/home",
},
},
}
if modules["beneficiaries"].(bool) {
ls.MenuItems = append(ls.MenuItems, MenuItem{
Title: "Bénéficiaires",
Link: "/app/beneficiaries/",
Active: menuState == "beneficiaries",
Icon: "hero:outline/user-group",
})
}
if modules["journeys"].(bool) {
ls.MenuItems = append(ls.MenuItems, MenuItem{
Title: "Déplacements",
Link: "/app/journeys/",
Active: menuState == "journeys",
Icon: "hero:outline/user-group",
})
}
if modules["vehicles"].(bool) {
ls.MenuItems = append(ls.MenuItems, MenuItem{
Title: "Véhicules",
Link: "/app/vehicles/",
Active: menuState == "vehicles",
Icon: "hero:outline/user-group",
})
}
if modules["vehicles_management"].(bool) {
ls.MenuItems = append(ls.MenuItems, MenuItem{
Title: "Gestion des véhicules",
Link: "/app/vehicles-management/",
Active: menuState == "vehicles_management",
Icon: "hero:outline/user-group",
})
}
if modules["events"].(bool) {
ls.MenuItems = append(ls.MenuItems, MenuItem{
Title: "Dispositifs",
Link: "/app/events/",
Active: menuState == "events",
Icon: "hero:outline/user-group",
})
}
return RenderState{
IconSet: icons.NewIconSet(iconset),
Group: group,
Roles: roles,
LayoutState: ls,
}
}

View File

@@ -0,0 +1,19 @@
package renderer
import "net/http"
const vehiclesmanagementMenu = "vehicles_management"
func (renderer *Renderer) VehiclesManagementOverview(w http.ResponseWriter, r *http.Request) {
files := renderer.ThemeConfig.GetStringSlice("views.vehicles_management.overview.files")
state := NewState(r, renderer.ThemeConfig, vehiclesmanagementMenu)
renderer.Render("fleet", w, r, files, state)
}
func (renderer *Renderer) VehiclesFleetAdd(w http.ResponseWriter, r *http.Request) {
files := renderer.ThemeConfig.GetStringSlice("views.vehicles_management.fleet_add.files")
state := NewState(r, renderer.ThemeConfig, vehiclesmanagementMenu)
renderer.Render("fleet", w, r, files, state)
}