aboutsummaryrefslogtreecommitdiff
path: root/internal/webui
diff options
context:
space:
mode:
Diffstat (limited to 'internal/webui')
-rw-r--r--internal/webui/html/root.html17
-rw-r--r--internal/webui/html/specificStop.html16
-rw-r--r--internal/webui/html/stop.html11
-rw-r--r--internal/webui/root.go21
-rw-r--r--internal/webui/root_test.go13
-rw-r--r--internal/webui/specificStop.go68
-rw-r--r--internal/webui/specificStop_test.go62
-rw-r--r--internal/webui/stop.go50
-rw-r--r--internal/webui/stop_test.go62
-rw-r--r--internal/webui/utils.go8
-rw-r--r--internal/webui/webui.go2
11 files changed, 293 insertions, 37 deletions
diff --git a/internal/webui/html/root.html b/internal/webui/html/root.html
index 97441c8..6b7bd6e 100644
--- a/internal/webui/html/root.html
+++ b/internal/webui/html/root.html
@@ -1,16 +1,9 @@
-{{ define "title"}}Horaires des prochains trains à Crépieux la Pape{{ end }}
+{{ define "title"}}Trains!{{ end }}
{{ template "base" . }}
{{ define "main" }}
-<h3>Horaires des prochains trains à Crépieux la Pape</h3>
-<table>
- <thead>
- <tr><th>Arrivée en gare</th><th>Direction</th></tr>
- </thead>
- <tbody>
- {{ range .Departures }}
- <tr{{ if .Odd }} style="color:#111111;"{{ end }}><td>{{ .Arrival }}</td><td>{{ .DisplayName }}</td></tr>
- {{ end }}
- </tbody>
-</table>
+<h3>Menu</h3>
+<ul>
+ <li><a href="/stop">Stop list</a></li>
+</ul>
{{ end }}
diff --git a/internal/webui/html/specificStop.html b/internal/webui/html/specificStop.html
new file mode 100644
index 0000000..5916927
--- /dev/null
+++ b/internal/webui/html/specificStop.html
@@ -0,0 +1,16 @@
+{{ define "title"}}Horaires des prochains trains à {{ .Stop }}{{ end }}
+{{ template "base" . }}
+
+{{ define "main" }}
+<h3>Horaires des prochains trains à {{ .Stop }}</h3>
+<table>
+ <thead>
+ <tr><th>Arrivée en gare</th><th>Direction</th></tr>
+ </thead>
+ <tbody>
+ {{ range $i, $elt := .Departures }}
+ <tr{{ if odd $i }} style="color:#111111;"{{ end }}><td>{{ .Arrival }}</td><td>{{ .Direction }}</td></tr>
+ {{ end }}
+ </tbody>
+</table>
+{{ end }}
diff --git a/internal/webui/html/stop.html b/internal/webui/html/stop.html
new file mode 100644
index 0000000..33a94c6
--- /dev/null
+++ b/internal/webui/html/stop.html
@@ -0,0 +1,11 @@
+{{ define "title"}}Choisir une gare{{ end }}
+{{ template "base" . }}
+
+{{ define "main" }}
+<h3>Choisir une gare</h3>
+<ul>
+ {{ range $i, $elt := .Stops }}
+ <li {{ if odd $i }}style="background-color:lightgray;"{{ end }}><a href="/stop/{{ $elt.Id }}">{{ $elt.Name }}</a></li>
+ {{ end }}
+</ul>
+{{ end }}
diff --git a/internal/webui/root.go b/internal/webui/root.go
index 94f2169..423ba93 100644
--- a/internal/webui/root.go
+++ b/internal/webui/root.go
@@ -3,18 +3,16 @@ package webui
import (
"fmt"
"html/template"
- "log"
"net/http"
"git.adyxax.org/adyxax/trains/pkg/model"
)
-var rootTemplate = template.Must(template.ParseFS(templatesFS, "html/base.html", "html/root.html"))
+var rootTemplate = template.Must(template.New("root").Funcs(funcMap).ParseFS(templatesFS, "html/base.html", "html/root.html"))
// The page template variable
-type Page struct {
- User *model.User
- Departures []model.Departure
+type RootPage struct {
+ User *model.User
}
// The root handler of the webui
@@ -25,16 +23,9 @@ func rootHandler(e *env, w http.ResponseWriter, r *http.Request) error {
http.Redirect(w, r, "/login", http.StatusFound)
return nil
}
- var departures []model.Departure
- if departures, err := e.navitia.GetDepartures(e.conf.TrainStop); err != nil {
- log.Printf("%s; data returned: %+v\n", err, departures)
- return newStatusError(http.StatusInternalServerError, fmt.Errorf("Could not get departures"))
- } else {
- w.Header().Set("Cache-Control", "no-store, no-cache")
- }
- p := Page{
- User: user,
- Departures: departures,
+ w.Header().Set("Cache-Control", "no-store, no-cache")
+ p := RootPage{
+ User: user,
}
err = rootTemplate.ExecuteTemplate(w, "root.html", p)
if err != nil {
diff --git a/internal/webui/root_test.go b/internal/webui/root_test.go
index 7e4ec71..e96f1c8 100644
--- a/internal/webui/root_test.go
+++ b/internal/webui/root_test.go
@@ -24,15 +24,8 @@ func TestRootHandler(t *testing.T) {
require.Nil(t, err)
e := env{
dbEnv: dbEnv,
- conf: &config.Config{TrainStop: "test"},
+ conf: &config.Config{},
}
- departures1 := []model.Departure{
- model.Departure{
- Direction: "test direction",
- Arrival: "20210503T150405",
- },
- }
- e.navitia = &NavitiaMockClient{departures: departures1, err: nil}
// test GET requests
runHttpTest(t, &e, rootHandler, &httpTestCase{
name: "a simple get when not logged in should redirect to the login page",
@@ -46,7 +39,7 @@ func TestRootHandler(t *testing.T) {
},
})
runHttpTest(t, &e, rootHandler, &httpTestCase{
- name: "a simple get when logged in should display the departure times",
+ name: "a simple get when logged in should display the menu",
input: httpTestInput{
method: http.MethodGet,
path: "/",
@@ -54,7 +47,7 @@ func TestRootHandler(t *testing.T) {
},
expect: httpTestExpect{
code: http.StatusOK,
- bodyString: "Horaires des prochains trains",
+ bodyString: "Menu",
},
})
}
diff --git a/internal/webui/specificStop.go b/internal/webui/specificStop.go
new file mode 100644
index 0000000..64dd04a
--- /dev/null
+++ b/internal/webui/specificStop.go
@@ -0,0 +1,68 @@
+package webui
+
+import (
+ "fmt"
+ "html/template"
+ "log"
+ "net/http"
+ "path"
+ "regexp"
+
+ "git.adyxax.org/adyxax/trains/pkg/model"
+)
+
+var validStopId = regexp.MustCompile(`^stop_area:[a-zA-Z]+:\d+$`)
+
+var specificStopTemplate = template.Must(template.New("specificStop").Funcs(funcMap).ParseFS(templatesFS, "html/base.html", "html/specificStop.html"))
+
+// The page template variable
+type SpecificStopPage struct {
+ User *model.User
+ Stop string
+ Departures []model.Departure
+}
+
+// The stop handler of the webui
+func specificStopHandler(e *env, w http.ResponseWriter, r *http.Request) error {
+ if path.Dir(r.URL.Path) == "/stop" {
+ user, err := tryAndResumeSession(e, r)
+ if err != nil {
+ http.Redirect(w, r, "/login", http.StatusFound)
+ return nil
+ }
+ switch r.Method {
+ case http.MethodGet:
+ id := path.Base(r.URL.Path)
+ if id == "" {
+ return newStatusError(http.StatusBadRequest, fmt.Errorf("No id in query string")) // TODO should we redirect to root page to chose a stop id?
+ }
+ if ok := validStopId.MatchString(id); !ok {
+ return newStatusError(http.StatusBadRequest, fmt.Errorf("Invalid stop id"))
+ }
+ stop, err := e.dbEnv.GetStop(id)
+ if err != nil {
+ return newStatusError(http.StatusBadRequest, fmt.Errorf("Stop id not found in database")) // TODO do better
+ }
+ if departures, err := e.navitia.GetDepartures(stop.Id); err != nil {
+ log.Printf("%s; data returned: %+v\n", err, departures)
+ return newStatusError(http.StatusInternalServerError, fmt.Errorf("Could not get departures"))
+ } else {
+ w.Header().Set("Cache-Control", "no-store, no-cache")
+ p := SpecificStopPage{
+ User: user,
+ Stop: stop.Name,
+ Departures: departures,
+ }
+ err = specificStopTemplate.ExecuteTemplate(w, "specificStop.html", p)
+ if err != nil {
+ return newStatusError(http.StatusInternalServerError, err)
+ }
+ return nil
+ }
+ default:
+ return newStatusError(http.StatusMethodNotAllowed, fmt.Errorf(http.StatusText(http.StatusMethodNotAllowed)))
+ }
+ } else {
+ return newStatusError(http.StatusNotFound, fmt.Errorf("Invalid path in specificStopHandler"))
+ }
+}
diff --git a/internal/webui/specificStop_test.go b/internal/webui/specificStop_test.go
new file mode 100644
index 0000000..45b2c2f
--- /dev/null
+++ b/internal/webui/specificStop_test.go
@@ -0,0 +1,62 @@
+package webui
+
+import (
+ "net/http"
+ "testing"
+
+ "git.adyxax.org/adyxax/trains/pkg/config"
+ "git.adyxax.org/adyxax/trains/pkg/database"
+ "git.adyxax.org/adyxax/trains/pkg/model"
+ "github.com/stretchr/testify/require"
+)
+
+func TestSpecificStopHandler(t *testing.T) {
+ // test environment setup
+ dbEnv, err := database.InitDB("sqlite3", "file::memory:?_foreign_keys=on")
+ require.Nil(t, err)
+ err = dbEnv.Migrate()
+ require.Nil(t, err)
+ user1, err := dbEnv.CreateUser(&model.UserRegistration{Username: "user1", Password: "password1", Email: "julien@adyxax.org"})
+ require.Nil(t, err)
+ _, err = dbEnv.Login(&model.UserLogin{Username: "user1", Password: "password1"})
+ require.Nil(t, err)
+ token1, err := dbEnv.CreateSession(user1)
+ require.Nil(t, err)
+ err = dbEnv.ReplaceAndImportStops([]model.Stop{model.Stop{Id: "stop_area:test:01", Name: "test"}})
+ require.Nil(t, err)
+ e := env{
+ dbEnv: dbEnv,
+ conf: &config.Config{},
+ }
+ departures1 := []model.Departure{
+ model.Departure{
+ Direction: "test direction",
+ Arrival: "20210503T150405",
+ },
+ }
+ e.navitia = &NavitiaMockClient{departures: departures1, err: nil}
+ // test GET requests
+ runHttpTest(t, &e, specificStopHandler, &httpTestCase{
+ name: "a simple get when not logged in should redirect to the login page",
+ input: httpTestInput{
+ method: http.MethodGet,
+ path: "/stop/stop_area:test:01",
+ },
+ expect: httpTestExpect{
+ code: http.StatusFound,
+ location: "/login",
+ },
+ })
+ runHttpTest(t, &e, specificStopHandler, &httpTestCase{
+ name: "a get of a subpath when logged in should display the departure times",
+ input: httpTestInput{
+ method: http.MethodGet,
+ path: "/stop/stop_area:test:01",
+ cookie: &http.Cookie{Name: sessionCookieName, Value: *token1},
+ },
+ expect: httpTestExpect{
+ code: http.StatusOK,
+ bodyString: "Horaires des prochains trains à test",
+ },
+ })
+}
diff --git a/internal/webui/stop.go b/internal/webui/stop.go
new file mode 100644
index 0000000..68d592e
--- /dev/null
+++ b/internal/webui/stop.go
@@ -0,0 +1,50 @@
+package webui
+
+import (
+ "fmt"
+ "html/template"
+ "net/http"
+
+ "git.adyxax.org/adyxax/trains/pkg/model"
+)
+
+var stopTemplate = template.Must(template.New("stop").Funcs(funcMap).ParseFS(templatesFS, "html/base.html", "html/stop.html"))
+
+// The page template variable
+type StopPage struct {
+ User *model.User
+ Stops []model.Stop
+}
+
+// The stop handler of the webui
+func stopHandler(e *env, w http.ResponseWriter, r *http.Request) error {
+ if r.URL.Path == "/stop" {
+ user, err := tryAndResumeSession(e, r)
+ if err != nil {
+ http.Redirect(w, r, "/login", http.StatusFound)
+ return nil
+ }
+ switch r.Method {
+ case http.MethodGet:
+ stops, err := e.dbEnv.GetStops()
+ if err != nil {
+ return newStatusError(http.StatusInternalServerError, fmt.Errorf("Could not get train stops"))
+ } else {
+ w.Header().Set("Cache-Control", "no-store, no-cache")
+ }
+ p := StopPage{
+ User: user,
+ Stops: stops,
+ }
+ err = stopTemplate.ExecuteTemplate(w, "stop.html", p)
+ if err != nil {
+ return newStatusError(http.StatusInternalServerError, err)
+ }
+ return nil
+ default:
+ return newStatusError(http.StatusMethodNotAllowed, fmt.Errorf(http.StatusText(http.StatusMethodNotAllowed)))
+ }
+ } else {
+ return newStatusError(http.StatusNotFound, fmt.Errorf("Invalid path in stopHandler"))
+ }
+}
diff --git a/internal/webui/stop_test.go b/internal/webui/stop_test.go
new file mode 100644
index 0000000..30e7593
--- /dev/null
+++ b/internal/webui/stop_test.go
@@ -0,0 +1,62 @@
+package webui
+
+import (
+ "net/http"
+ "testing"
+
+ "git.adyxax.org/adyxax/trains/pkg/config"
+ "git.adyxax.org/adyxax/trains/pkg/database"
+ "git.adyxax.org/adyxax/trains/pkg/model"
+ "github.com/stretchr/testify/require"
+)
+
+func TestStopHandler(t *testing.T) {
+ // test environment setup
+ dbEnv, err := database.InitDB("sqlite3", "file::memory:?_foreign_keys=on")
+ require.Nil(t, err)
+ err = dbEnv.Migrate()
+ require.Nil(t, err)
+ user1, err := dbEnv.CreateUser(&model.UserRegistration{Username: "user1", Password: "password1", Email: "julien@adyxax.org"})
+ require.Nil(t, err)
+ _, err = dbEnv.Login(&model.UserLogin{Username: "user1", Password: "password1"})
+ require.Nil(t, err)
+ token1, err := dbEnv.CreateSession(user1)
+ require.Nil(t, err)
+ err = dbEnv.ReplaceAndImportStops([]model.Stop{model.Stop{Id: "stop_area:test:01", Name: "test"}})
+ require.Nil(t, err)
+ e := env{
+ dbEnv: dbEnv,
+ conf: &config.Config{},
+ }
+ departures1 := []model.Departure{
+ model.Departure{
+ Direction: "test direction",
+ Arrival: "20210503T150405",
+ },
+ }
+ e.navitia = &NavitiaMockClient{departures: departures1, err: nil}
+ // test GET requests
+ runHttpTest(t, &e, stopHandler, &httpTestCase{
+ name: "a simple get when not logged in should redirect to the login page",
+ input: httpTestInput{
+ method: http.MethodGet,
+ path: "/stop",
+ },
+ expect: httpTestExpect{
+ code: http.StatusFound,
+ location: "/login",
+ },
+ })
+ runHttpTest(t, &e, stopHandler, &httpTestCase{
+ name: "a simple get when logged in should display the stops list",
+ input: httpTestInput{
+ method: http.MethodGet,
+ path: "/stop",
+ cookie: &http.Cookie{Name: sessionCookieName, Value: *token1},
+ },
+ expect: httpTestExpect{
+ code: http.StatusOK,
+ bodyString: "stop_area:test:01",
+ },
+ })
+}
diff --git a/internal/webui/utils.go b/internal/webui/utils.go
index be8baf3..28a7add 100644
--- a/internal/webui/utils.go
+++ b/internal/webui/utils.go
@@ -2,6 +2,7 @@ package webui
import (
"embed"
+ "html/template"
"log"
"net/http"
@@ -16,6 +17,13 @@ var templatesFS embed.FS
//go:embed static/*
var staticFS embed.FS
+// Template functions
+var funcMap = template.FuncMap{
+ "odd": func(i int) bool {
+ return i%2 == 1
+ },
+}
+
// the environment that will be passed to our handlers
type env struct {
conf *config.Config
diff --git a/internal/webui/webui.go b/internal/webui/webui.go
index b18bc5c..63173c6 100644
--- a/internal/webui/webui.go
+++ b/internal/webui/webui.go
@@ -18,6 +18,8 @@ func Run(c *config.Config, dbEnv *database.DBEnv) {
http.Handle("/", handler{&e, rootHandler})
http.Handle("/login", handler{&e, loginHandler})
http.Handle("/static/", http.FileServer(http.FS(staticFS)))
+ http.Handle("/stop", handler{&e, stopHandler})
+ http.Handle("/stop/", handler{&e, specificStopHandler})
if i, err := dbEnv.CountStops(); err == nil && i == 0 {
log.Printf("No trains stops data found, updating...")