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}}