index endpoint start

This commit is contained in:
Simon Martens
2024-11-16 02:30:20 +01:00
parent d4feb20f07
commit 527fbfa000
14 changed files with 230 additions and 25 deletions

51
.air.toml Normal file
View File

@@ -0,0 +1,51 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
args_bin = []
bin = "./tmp/main"
cmd = "go build -tags=\"dev\" -o ./tmp/main ."
delay = 1000
exclude_dir = ["assets", "views", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false
[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
main_only = false
time = false
[misc]
clean_on_exit = false
[proxy]
app_port = 0
enabled = false
proxy_port = 0
[screen]
clear_on_rebuild = false
keep_scroll = true

View File

@@ -1,4 +1,4 @@
package controller package controllers
import ( import (
"net/http" "net/http"

21
controllers/years.go Normal file
View File

@@ -0,0 +1,21 @@
package controllers
import (
"github.com/Theodor-Springmann-Stiftung/kgpz_web/app"
"github.com/gofiber/fiber/v2"
)
func GetYear(kgpz *app.KGPZ) fiber.Handler {
return func(c *fiber.Ctx) error {
y := c.Params("year", "1764")
if len(y) != 4 {
return c.SendStatus(fiber.StatusBadRequest)
}
issues := kgpz.Library.Issues.GetYear(y)
if len(issues.Issues) == 0 {
return c.SendStatus(fiber.StatusNotFound)
}
return c.Render("/", fiber.Map{"model": issues})
}
}

View File

@@ -31,7 +31,6 @@ type FileWatcher struct {
} }
func NewFileWatcher() (*FileWatcher, error) { func NewFileWatcher() (*FileWatcher, error) {
fw := &FileWatcher{mu: sync.Mutex{}} fw := &FileWatcher{mu: sync.Mutex{}}
fw.Watch() fw.Watch()
return fw, nil return fw, nil
@@ -96,8 +95,8 @@ func (fw *FileWatcher) Watch() error {
if !ok { if !ok {
return return
} }
log.Println("event:", event)
if !event.Has(fsnotify.Chmod) { if !event.Has(fsnotify.Chmod) {
log.Println("event:", event)
fw.mu.Lock() fw.mu.Lock()
for _, wf := range fw.wf { for _, wf := range fw.wf {
wf(event.Name) wf(event.Name)

View File

@@ -37,7 +37,7 @@ func main() {
kgpz := app.NewKGPZ(cfg) kgpz := app.NewKGPZ(cfg)
kgpz.Init() kgpz.Init()
server := server.Start(kgpz, cfg) server := server.Create(kgpz, cfg)
Start(kgpz, server) Start(kgpz, server)
} }

View File

@@ -1,5 +0,0 @@
# Notes on xml reading
The models expect certain files and a certain file XML structure and throw quite often if the structure is not as expected.
This is by design, as the models are supposed to be used in a controlled environment. Changes in the XML schema should be reflected in the models.
All collections in the models should be kept thread-safe.

View File

@@ -11,7 +11,31 @@ type IssueProvider struct {
type Issues struct { type Issues struct {
XMLName xml.Name `xml:"stuecke"` XMLName xml.Name `xml:"stuecke"`
Issue []Issue `xml:"stueck"` Issues []Issue `xml:"stueck"`
}
func (i *IssueProvider) GetYear(year string) YearViewModel {
res := YearViewModel{Year: year}
last := ""
for _, issue := range i.Items.Issues {
if len(issue.Datum.When) < 4 {
continue
}
date := issue.Datum.When[0:4]
if date != last {
res.PushAvailable(date)
last = date
}
if date == year {
res.PushIssue(issue)
}
}
res.SortAvailableYears()
return res
} }
type Issue struct { type Issue struct {
@@ -39,13 +63,13 @@ type Additional struct {
} }
func (i Issues) Append(data Issues) Issues { func (i Issues) Append(data Issues) Issues {
i.Issue = append(i.Issue, data.Issue...) i.Issues = append(i.Issues, data.Issues...)
return i return i
} }
func (i Issues) String() string { func (i Issues) String() string {
var res []string var res []string
for _, issue := range i.Issue { for _, issue := range i.Issues {
res = append(res, issue.String()) res = append(res, issue.String())
} }

View File

@@ -81,5 +81,5 @@ type Reference struct {
} }
type Value struct { type Value struct {
Value string `xml:",chardata"` Chardata string `xml:",chardata"`
} }

84
providers/year.go Normal file
View File

@@ -0,0 +1,84 @@
package providers
import (
"slices"
"strconv"
"time"
)
const TLAYOUT = "2006-01-02"
var TRANSLM = map[string][]string{
"January": {"Januar", "Jan"},
"February": {"Februar", "Feb"},
"March": {"März", "Mär"},
"April": {"April", "Apr"},
"May": {"Mai", "Mai"},
"June": {"Juni", "Jun"},
"July": {"Juli", "Jul"},
"August": {"August", "Aug"},
"September": {"September", "Sep"},
"October": {"Oktober", "Okt"},
"November": {"November", "Nov"},
"December": {"Dezember", "Dez"},
}
var TRANSLD = map[string][]string{
"Monday": {"Montag", "Mo"},
"Tuesday": {"Dienstag", "Di"},
"Wednesday": {"Mittwoch", "Mi"},
"Thursday": {"Donnerstag", "Do"},
"Friday": {"Freitag", "Fr"},
"Saturday": {"Samstag", "Sa"},
"Sunday": {"Sonntag", "So"},
}
type IssueViewModel struct {
Issue
Weekday []string
Day int
Month []string
}
func NewIssueView(i Issue) (IssueViewModel, error) {
t, err := time.Parse(TLAYOUT, i.Datum.When)
if err != nil {
return IssueViewModel{}, err
}
return IssueViewModel{
Issue: i,
Weekday: append(TRANSLD[t.Weekday().String()], t.Weekday().String()),
Day: t.Day(),
Month: append(TRANSLM[t.Month().String()], i.Datum.When[5:7]),
}, nil
}
type YearViewModel struct {
Year string
AvailableYears []int
Issues []IssueViewModel
}
func (y *YearViewModel) PushIssue(i Issue) {
iv, err := NewIssueView(i)
if err != nil {
return
}
y.Issues = append(y.Issues, iv)
}
func (y *YearViewModel) PushAvailable(s string) {
i, err := strconv.Atoi(s)
if err != nil {
return
}
if !slices.Contains(y.AvailableYears, i) {
y.AvailableYears = append(y.AvailableYears, i)
}
}
func (y *YearViewModel) SortAvailableYears() {
slices.Sort(y.AvailableYears)
}

View File

@@ -7,6 +7,7 @@ import (
"time" "time"
"github.com/Theodor-Springmann-Stiftung/kgpz_web/app" "github.com/Theodor-Springmann-Stiftung/kgpz_web/app"
"github.com/Theodor-Springmann-Stiftung/kgpz_web/controllers"
"github.com/Theodor-Springmann-Stiftung/kgpz_web/helpers" "github.com/Theodor-Springmann-Stiftung/kgpz_web/helpers"
"github.com/Theodor-Springmann-Stiftung/kgpz_web/providers" "github.com/Theodor-Springmann-Stiftung/kgpz_web/providers"
"github.com/Theodor-Springmann-Stiftung/kgpz_web/templating" "github.com/Theodor-Springmann-Stiftung/kgpz_web/templating"
@@ -40,27 +41,45 @@ const (
// - we invalidate all caches if data is valid // - we invalidate all caches if data is valid
// - we reload all clients // - we reload all clients
// - if data validity catastrophically fails, we restart the router to map error pages. // - if data validity catastrophically fails, we restart the router to map error pages.
// TODO: Use fiber
type Server struct { type Server struct {
Config *providers.ConfigProvider Config *providers.ConfigProvider
running chan bool running chan bool
shutdown *sync.WaitGroup shutdown *sync.WaitGroup
cache *memory.Storage cache *memory.Storage
mu sync.Mutex
watcher *helpers.FileWatcher watcher *helpers.FileWatcher
kgpz *app.KGPZ
} }
func Start(k *app.KGPZ, c *providers.ConfigProvider) *Server { func Create(k *app.KGPZ, c *providers.ConfigProvider) *Server {
if c == nil || k == nil {
log.Println("Error creating server")
return nil
}
return &Server{ return &Server{
Config: c, Config: c,
kgpz: k,
} }
} }
// INFO: hot reloading for poor people
// BUG: unable to close the old file watcher here, since the process gets aborted in the middle of creating the new one.
func (s *Server) Watcher() error { func (s *Server) Watcher() error {
s.mu.Lock()
defer s.mu.Unlock()
watcher, err := helpers.NewFileWatcher() watcher, err := helpers.NewFileWatcher()
if err != nil {
return err
}
s.watcher = watcher s.watcher = watcher
s.watcher.Append(func(path string) { s.watcher.Append(func(path string) {
log.Println("Restarting server") log.Println("Restarting server")
time.Sleep(200 * time.Millisecond)
s.Restart() s.Restart()
}) })
@@ -111,6 +130,7 @@ func (s *Server) Start() {
srv.Use(recover.New()) srv.Use(recover.New())
// TODO: Dont cache static assets, bc storage gets huge // TODO: Dont cache static assets, bc storage gets huge
// INFO: Maybe fiber does this already?
if s.Config.Debug { if s.Config.Debug {
srv.Use(cache.New(cache.Config{ srv.Use(cache.New(cache.Config{
Next: func(c *fiber.Ctx) bool { Next: func(c *fiber.Ctx) bool {
@@ -133,16 +153,15 @@ func (s *Server) Start() {
srv.Use(STATIC_PREFIX, static(&views.StaticFS)) srv.Use(STATIC_PREFIX, static(&views.StaticFS))
srv.Get("/", func(c *fiber.Ctx) error { srv.Get("/:year?", controllers.GetYear(s.kgpz))
return c.Render("/", fiber.Map{})
})
s.runner(srv) s.runner(srv)
if s.Config.Debug { if s.Config.Debug {
err := s.Watcher() err := s.Watcher()
if err != nil { if err != nil {
fmt.Println(err) log.Println("Error watching files")
log.Println(err)
} }
} }
} }
@@ -194,8 +213,6 @@ func (s *Server) runner(srv *fiber.App) {
defer cleanup.Done() defer cleanup.Done()
clean := <-s.running clean := <-s.running
srv.Server().CloseOnShutdown = true
if clean { if clean {
if err := srv.ShutdownWithTimeout(SERVER_TIMEOUT); err != nil { if err := srv.ShutdownWithTimeout(SERVER_TIMEOUT); err != nil {
fmt.Println(err) fmt.Println(err)

View File

@@ -73,9 +73,6 @@
- Was ist "Link auf seite teilen"? -> Permalink - Was ist "Link auf seite teilen"? -> Permalink
## Überarbeiten ## Überarbeiten
- Undifferenzierte Angabe von "Akteur" von Werken in der Kurzangabe, Differenzieren
- Jahr
- Kurztitel, Titel
- Sekundärüberlieferung in Stück/Beitrag - Sekundärüberlieferung in Stück/Beitrag
- Fehlende Daten in Stück/Beitrag - Fehlende Daten in Stück/Beitrag
- Kurzinformation Überlieferung - Kurzinformation Überlieferung

1
tmp/build-errors.log Normal file
View File

@@ -0,0 +1 @@
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1

BIN
tmp/main Executable file

Binary file not shown.

View File

@@ -1,3 +1,19 @@
{{ define "body" }} {{ define "body" }}
<p>Change! Hello from body</p> {{ range $year := .model.AvailableYears }}
<a href="/{{ $year }}">{{ $year }}</a>
{{ end }}
{{ range $issue := .model.Issues }}
<div>
<div>
{{ $issue.Number.Chardata }}
</div>
<div>
{{ index $issue.Month 1 }}
</div>
<div>
{{ index $issue.Weekday 1 }}
</div>
<div>{{ $issue.Day }}.{{ index $issue.Month 2 }}.</div>
</div>
{{ end }}
{{ end }} {{ end }}