summaryrefslogtreecommitdiff
path: root/lex-serve/main.go
diff options
context:
space:
mode:
authorMartin Fischer <martin@push-f.com>2025-04-11 16:33:59 +0200
committerMartin Fischer <martin@push-f.com>2025-04-13 20:19:48 +0200
commit50ea018252ce69542eab6a107b99ea8179810d1e (patch)
tree25091624110c413bd095581f79b50cd7ab030656 /lex-serve/main.go
parent16b01fd1dfb8797b5529ea444f5b26cd26be9c3c (diff)
refactor: introduce lex-serve package
Diffstat (limited to 'lex-serve/main.go')
-rw-r--r--lex-serve/main.go144
1 files changed, 144 insertions, 0 deletions
diff --git a/lex-serve/main.go b/lex-serve/main.go
new file mode 100644
index 0000000..d0fb690
--- /dev/null
+++ b/lex-serve/main.go
@@ -0,0 +1,144 @@
+package main
+
+import (
+ "embed"
+ "encoding/json"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "net/url"
+ "os"
+ "strings"
+ "text/template"
+)
+
+//go:embed countries.json
+var countriesJSON []byte
+
+func main() {
+ domain := os.Getenv("DOMAIN")
+ if domain == "" {
+ log.Fatal("DOMAIN environment variable must be set")
+ }
+
+ var handler = handler{domain: domain, lawsByCC: map[string]map[string]law{}}
+ err := json.Unmarshal(countriesJSON, &handler.countries)
+ if err != nil {
+ log.Fatal("countries.json ", err)
+ }
+
+ lawFiles, err := ioutil.ReadDir("laws")
+ if err != nil {
+ log.Fatal(err)
+ }
+ for _, file := range lawFiles {
+ text, err := ioutil.ReadFile("laws/" + file.Name())
+ if err != nil {
+ log.Fatal(file.Name(), err)
+ }
+ var laws []law
+ err = json.Unmarshal([]byte(text), &laws)
+ if err != nil {
+ log.Fatal(file.Name(), err)
+ }
+ cc := strings.SplitN(file.Name(), ".", 2)[0]
+ handler.lawsByCC[cc] = map[string]law{}
+ for _, law := range laws {
+ if law.Redir != "" {
+ handler.lawsByCC[cc][law.Redir] = law
+ }
+ }
+ }
+ http.HandleFunc("/", handler.handle)
+ println("listening on 8000")
+ log.Fatal(http.ListenAndServe(":8000", nil))
+}
+
+//go:embed templates
+var templates embed.FS
+
+var tpl, _ = template.New("").Funcs(template.FuncMap{
+ "ToUpper": strings.ToUpper,
+}).ParseFS(templates, "templates/*")
+
+type handler struct {
+ domain string
+ countries map[string]country
+ lawsByCC map[string]map[string]law
+}
+
+func (h *handler) handle(w http.ResponseWriter, r *http.Request) {
+ if r.Host == h.domain {
+ if r.URL.Path != "/" {
+ w.WriteHeader(http.StatusNotFound)
+ w.Write([]byte("page not found"))
+ return
+ }
+ err := tpl.ExecuteTemplate(w, "index.html.tmpl", map[string]any{
+ "Countries": h.countries,
+ "Domain": r.Host,
+ })
+ if err != nil {
+ log.Fatal(err)
+ }
+ return
+ }
+
+ cc, isSubdomain := strings.CutSuffix(r.Host, "."+h.domain)
+ if !isSubdomain {
+ w.Write([]byte("unknown host"))
+ return
+ }
+ key := strings.TrimLeft(r.URL.Path, "/")
+ if len(key) > 0 {
+ val, ok := h.lawsByCC[cc][key]
+ if !ok {
+ w.WriteHeader(http.StatusNotFound)
+ w.Write([]byte("unknown law"))
+ return
+ }
+ http.Redirect(w, r, val.URL, 302)
+ } else {
+ query := r.URL.Query().Get("q")
+ if query != "" {
+ country, ok := h.countries[cc]
+ if !ok {
+ w.WriteHeader(http.StatusNotFound)
+ w.Write([]byte("search not implemented for this country"))
+ return
+ }
+ if country.HasPlaceholder() {
+ http.Redirect(w, r, strings.Replace(country.SearchURL, "%s", url.QueryEscape(query), 1), 302)
+ return
+ } else {
+ w.WriteHeader(http.StatusBadRequest)
+ }
+ }
+ _, hasJSONLaws := h.lawsByCC[cc]
+ err := tpl.ExecuteTemplate(w, "search.html.tmpl", map[string]any{
+ "TLD": cc,
+ "Domain": h.domain,
+ "Country": h.countries[cc],
+ "HasJSONLaws": hasJSONLaws,
+ })
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+}
+
+type law struct {
+ URL string
+ Title string
+ Abbr string
+ Redir string
+}
+
+type country struct {
+ Name string
+ SearchURL string `json:"search_url"`
+}
+
+func (c country) HasPlaceholder() bool {
+ return strings.Contains(c.SearchURL, "%s")
+}