From 1ccb71d3a1188f814720542e15a6634db0764c30 Mon Sep 17 00:00:00 2001 From: Antonio De Lucreziis Date: Sat, 28 May 2022 19:09:50 +0200 Subject: [PATCH] Pagina utenti caricata da json --- .env.dev | 4 ++- .gitignore | 3 ++ README.md | 2 ++ config/config.go | 12 ++++++-- main.go | 36 +++++++++++++++++++--- public/js/utenti.js | 3 ++ public/style.css | 68 +++++++++++++++++++++++++++++++++++++++++- templates/templates.go | 41 +++++++++++++++---------- utenti.go | 27 +++++++++++++++++ util/objects.go | 2 ++ views/utenti.html | 27 ++++++++++++++--- 11 files changed, 197 insertions(+), 28 deletions(-) create mode 100644 public/js/utenti.js create mode 100644 utenti.go diff --git a/.env.dev b/.env.dev index 3c61a89..46a5fbb 100644 --- a/.env.dev +++ b/.env.dev @@ -7,4 +7,6 @@ GIT_URL=https://git.phc.dm.unipi.it CHAT_URL=https://chat.phc.dm.unipi.it # Other -EMAIL=macchinisti.phc@gmail.com +EMAIL=macchinisti@lists.dm.unipi.it + +USER_PAGES_BASE_URL=https://poisson.phc.dm.unipi.it/~ diff --git a/.gitignore b/.gitignore index 7a79b61..d8f1fe1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ # Miscellaneous tags + +# Local files +*.local* diff --git a/README.md b/README.md index 39ed93d..c5f65b4 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ Un comando comodo in fase di development che usa [`entr`](https://github.com/era ```bash shell $ find . -type f -name '*.go' | entr -r go run . +# Or also... +$ fd -e go | entr -r go run . ``` ### Environment Variables diff --git a/config/config.go b/config/config.go index 3dd86e5..4dd4ec5 100644 --- a/config/config.go +++ b/config/config.go @@ -16,6 +16,8 @@ var GitUrl string var ChatUrl string var Email string +var UserPagesBaseUrl string + func loadEnv(target *string, name, defaultValue string) { value := os.Getenv(name) if len(strings.TrimSpace(value)) == 0 { @@ -33,17 +35,23 @@ func Load() { loadEnv(&Mode, "MODE", "production") loadEnv(&Host, "HOST", "localhost:8080") + loadEnv(&GitUrl, "GIT_URL", "https://git.example.org") loadEnv(&ChatUrl, "CHAT_URL", "https://chat.example.org") loadEnv(&Email, "EMAIL", "mail@example.org") + + loadEnv(&UserPagesBaseUrl, "USER_PAGES_BASE_URL", "https://poisson.phc.dm.unipi.it/~") } func Object() util.H { return util.H{ - "Mode": Mode, - "Host": Host, + "Mode": Mode, + "Host": Host, + "GitUrl": GitUrl, "ChatUrl": ChatUrl, "Email": Email, + + "UserPagesBaseUrl": UserPagesBaseUrl, } } diff --git a/main.go b/main.go index fa1685f..f19c414 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "encoding/json" "html/template" "log" "net/http" @@ -38,10 +39,9 @@ func main() { // Routes actuallyStaticRoutes := map[string]string{ - "/": "home.html", - "/link": "link.html", - "/utenti": "utenti.html", - "/login": "login.html", + "/": "home.html", + "/link": "link.html", + "/login": "login.html", } for route, view := range actuallyStaticRoutes { @@ -55,6 +55,34 @@ func main() { }) } + r.Get("/api/utenti", func(w http.ResponseWriter, r *http.Request) { + utenti, err := GetUtenti() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if err := json.NewEncoder(w).Encode(utenti); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + }) + + r.Get("/utenti", func(w http.ResponseWriter, r *http.Request) { + utenti, err := GetUtenti() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if err := renderer.Render(w, "utenti.html", util.H{ + "Utenti": utenti, + }); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + }) + r.Get("/appunti", func(w http.ResponseWriter, r *http.Request) { searchQuery := "" diff --git a/public/js/utenti.js b/public/js/utenti.js new file mode 100644 index 0000000..7d846d1 --- /dev/null +++ b/public/js/utenti.js @@ -0,0 +1,3 @@ +// window.addEventListener('DOMContentLoaded', () => { + +// }) \ No newline at end of file diff --git a/public/style.css b/public/style.css index f2d4aba..625570a 100644 --- a/public/style.css +++ b/public/style.css @@ -475,6 +475,31 @@ button.icon { width: 2rem; } +select { + font-family: var(--font-sf); + font-weight: var(--font-weight-medium); + font-size: 16px; + + /* gray variant #b3b3b3 */ + border: 1px solid var(--bg-darker-3); + /* gray variant #bfbfbf */ + background: var(--bg-darker-2); + /* gray variant #333333 */ + color: var(--fg); + + height: 2rem; + + border-radius: 4px; + + padding: 0 0.25rem; + + transition: all 100ms ease-in-out; + + box-shadow: 0 4px 8px 0 #00000022; + + cursor: pointer; +} + /* Text Fields */ input[type=text], input[type=password] { @@ -511,9 +536,35 @@ input[type=password] { border-radius: 4px; box-shadow: 0 0 8px 0 #00000022; + + border: 1px solid var(--bg-darker-3); + background: var(--bg-darker-2); + color: var(--fg); } -.compound > button, .compound > .button, .compound > input { +.compound > .divider { + height: 2rem; + width: 1px; + + background: var(--bg-darker-3); +} + +.compound .icon { + width: 2.5rem; + + display: flex; + align-items: center; + justify-content: center; +} + +.compound > select { + background: none; + + margin-right: 0.25rem; +} + +.compound > button, .compound > .button, .compound > input, .compound > select { + border: none; box-shadow: none; } @@ -633,8 +684,23 @@ form .field-set input { padding-top: calc(100vh - 6rem); } +.page-utenti .user-list { + display: flex; + flex-direction: column; + width: 100%; +} + +.page-utenti .user-item { + flex-direction: row; + width: 100%; +} + .search { margin: 2rem 0; + display: flex; + flex-direction: row; + + gap: 1rem; } .search input[type=text] { diff --git a/templates/templates.go b/templates/templates.go index e0d5738..751e557 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -3,6 +3,7 @@ package templates import ( "html/template" "io" + "log" "path" "strings" @@ -10,20 +11,23 @@ import ( "git.phc.dm.unipi.it/phc/website/util" ) +// CachedTemplate holds a reference to the list of patterns to preload and a reference to the already parsed template type CachedTemplate struct { - LoadPatterns []string - cachedTmpl *template.Template + PreLoadTemplatePatterns []string + cachedTmpl *template.Template } +// NewCacheTemplate creates a new template from a list of patterns a loads it func NewCacheTemplate(loadPatterns ...string) *CachedTemplate { cachedTemplate := &CachedTemplate{ - LoadPatterns: loadPatterns, - cachedTmpl: nil, + PreLoadTemplatePatterns: loadPatterns, + cachedTmpl: nil, } template.Must(cachedTemplate.Load(template.New(""))) return cachedTemplate } +// Load returns the cached template or loads it from disk using the list of preload (glob) patterns. func (ct *CachedTemplate) Load(t *template.Template) (*template.Template, error) { if ct.cachedTmpl != nil { return ct.cachedTmpl, nil @@ -31,7 +35,7 @@ func (ct *CachedTemplate) Load(t *template.Template) (*template.Template, error) ct.cachedTmpl = t - for _, pattern := range ct.LoadPatterns { + for _, pattern := range ct.PreLoadTemplatePatterns { var err error ct.cachedTmpl, err = ct.cachedTmpl.ParseGlob(pattern) if err != nil { @@ -42,38 +46,43 @@ func (ct *CachedTemplate) Load(t *template.Template) (*template.Template, error) return ct.cachedTmpl, nil } +// Reload the pattern from disk (used for developing) func (ct *CachedTemplate) Reload() { ct.cachedTmpl = nil template.Must(ct.Load(nil)) } +// Template returns the cached template func (ct *CachedTemplate) Template() *template.Template { + log.Printf("preloadPatterns: %v", ct.PreLoadTemplatePatterns) return ct.cachedTmpl } -// Renderer holds cached templates for rendering -type Renderer struct { - rootPath string - loadPatterns []string - templateCache map[string]*CachedTemplate +// TODO: Add a render function to CachedTemplate instead of returning the template reference. In this way the Template Renderer would not have a "direct" dependency on "html/template"... + +// TemplateRenderer holds cached templates for rendering +type TemplateRenderer struct { + viewsDir string + preloadTemplatePatterns []string + templateCache map[string]*CachedTemplate } // NewRenderer constructs a template renderer with a base file -func NewRenderer(rootPath string, loadPatterns ...string) *Renderer { - return &Renderer{ +func NewRenderer(rootPath string, loadPatterns ...string) *TemplateRenderer { + return &TemplateRenderer{ rootPath, loadPatterns, map[string]*CachedTemplate{}, } } -func (r *Renderer) Load(name string) *CachedTemplate { +func (r *TemplateRenderer) Load(name string) *CachedTemplate { cachedTemplate, present := r.templateCache[name] if !present { loaders := []string{} - loaders = append(loaders, r.loadPatterns...) - loaders = append(loaders, path.Join(r.rootPath, name)) + loaders = append(loaders, r.preloadTemplatePatterns...) + loaders = append(loaders, path.Join(r.viewsDir, name)) cachedTemplate = NewCacheTemplate(loaders...) r.templateCache[name] = cachedTemplate } @@ -82,7 +91,7 @@ func (r *Renderer) Load(name string) *CachedTemplate { } // Render the template, also injects "Page" and "Config" values in the template -func (r *Renderer) Render(w io.Writer, name string, data util.H) error { +func (r *TemplateRenderer) Render(w io.Writer, name string, data util.H) error { cachedTemplate := r.Load(name) if config.Mode == "development" { diff --git a/utenti.go b/utenti.go new file mode 100644 index 0000000..a67260a --- /dev/null +++ b/utenti.go @@ -0,0 +1,27 @@ +package main + +import ( + "encoding/json" + "io/ioutil" +) + +type UserInfo struct { + Uid string `string:"uid"` + Nome string `json:"nome"` + Cognome string `json:"cognome"` +} + +func GetUtenti() ([]UserInfo, error) { + var users []UserInfo + + usersJsonData, err := ioutil.ReadFile("./utenti-poisson-2022.local.json") + if err != nil { + return nil, err + } + + if err := json.Unmarshal(usersJsonData, &users); err != nil { + return nil, err + } + + return users, nil +} diff --git a/util/objects.go b/util/objects.go index 1b9e290..becf244 100644 --- a/util/objects.go +++ b/util/objects.go @@ -1,7 +1,9 @@ package util +// H is a shortcut for creating a json-like object type H map[string]interface{} +// Apply is like Object.apply from JS and merges the given objects on top of target func (target H) Apply(sources ...H) H { for _, source := range sources { for k, v := range source { diff --git a/views/utenti.html b/views/utenti.html index 51dcdb8..b86b6ea 100644 --- a/views/utenti.html +++ b/views/utenti.html @@ -12,6 +12,17 @@ Questa è la lista di tutti gli utenti con un account su Poisson. Scrivi nome, cognome o username di un utente per filtrare la lista in tempo reale. Altrimenti di base in cima compariranno gli utenti con più "follower".

-
- TODO: Lista work in progress +
+ {{ $config := .Config }} + {{ range .Utenti }} + + {{ end }}
- + {{end}}