Add Calendar integration (read-only)
This commit is contained in:
+116
@@ -0,0 +1,116 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
pageTypeHandlers = append(pageTypeHandlers, &calendarsHandler{})
|
||||
}
|
||||
|
||||
// calendarsHandler renders folders whose .page-settings declares
|
||||
// type = calendars: the maintenance table and the sync status. Markdown
|
||||
// content and the listing stay visible, as in the fitness folder.
|
||||
type calendarsHandler struct{}
|
||||
|
||||
func (c *calendarsHandler) redirect(root, fsPath, urlPath string, r *http.Request) (string, bool) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (c *calendarsHandler) handle(root, fsPath, urlPath string, r *http.Request) *specialPage {
|
||||
s := readPageSettings(fsPath)
|
||||
if s == nil || s.Type != "calendars" {
|
||||
return nil
|
||||
}
|
||||
return &specialPage{Content: renderCalendarsPage(fsPath), SuppressTOC: true}
|
||||
}
|
||||
|
||||
type calFileRow struct {
|
||||
Name string
|
||||
Roles string
|
||||
Events string
|
||||
Updated string // file modification time
|
||||
Error string // last sync or parse error
|
||||
}
|
||||
|
||||
type calPageData struct {
|
||||
HasMaintenance bool
|
||||
Maintenance []maintSeriesRow
|
||||
Calendars []calFileRow
|
||||
// Sync is only shown for the configured calendars folder.
|
||||
IsSyncDir bool
|
||||
SyncEnabled bool
|
||||
LastRun string
|
||||
LastError string
|
||||
}
|
||||
|
||||
var calPageTmpl = template.Must(template.ParseFS(assets, "assets/calendar/page.html"))
|
||||
|
||||
func renderCalendarsPage(dir string) template.HTML {
|
||||
s := readCalendarSettings(dir)
|
||||
data := calPageData{
|
||||
HasMaintenance: len(s.Maintenance) > 0,
|
||||
Maintenance: maintenanceSeries(dir, s.Maintenance, time.Now()),
|
||||
IsSyncDir: calendarsDir != "" && dir == calendarsDir,
|
||||
SyncEnabled: s.CaldavURL != "",
|
||||
}
|
||||
|
||||
var results map[string]calSyncResult
|
||||
if data.IsSyncDir {
|
||||
var lastRun time.Time
|
||||
lastRun, data.LastError, results = calSyncSnapshot()
|
||||
if !lastRun.IsZero() {
|
||||
data.LastRun = lastRun.Format("2006-01-02 15:04")
|
||||
}
|
||||
}
|
||||
|
||||
roles := map[string][]string{}
|
||||
for role, names := range map[string][]string{"diary": s.Diary, "weight": s.Weight, "maintenance": s.Maintenance} {
|
||||
for _, n := range names {
|
||||
roles[n] = append(roles[n], role)
|
||||
}
|
||||
}
|
||||
entries, _ := os.ReadDir(dir)
|
||||
for _, e := range entries {
|
||||
name := e.Name()
|
||||
if e.IsDir() || strings.HasPrefix(name, ".") || !strings.EqualFold(filepath.Ext(name), ".ics") {
|
||||
continue
|
||||
}
|
||||
name = strings.TrimSuffix(name, filepath.Ext(name))
|
||||
sort.Strings(roles[name])
|
||||
row := calFileRow{Name: name, Roles: strings.Join(roles[name], ", "), Error: results[name].Error}
|
||||
if info, err := e.Info(); err == nil {
|
||||
row.Updated = info.ModTime().Format("2006-01-02 15:04")
|
||||
}
|
||||
if f := loadCalendar(filepath.Join(dir, e.Name())); f != nil {
|
||||
row.Events = strconv.Itoa(f.events)
|
||||
} else if row.Error == "" {
|
||||
row.Error = "cannot parse file"
|
||||
}
|
||||
data.Calendars = append(data.Calendars, row)
|
||||
delete(results, name)
|
||||
}
|
||||
// Calendars whose download failed before a file ever existed.
|
||||
for name, r := range results {
|
||||
if r.Error != "" {
|
||||
data.Calendars = append(data.Calendars, calFileRow{Name: name, Error: r.Error})
|
||||
}
|
||||
}
|
||||
sort.SliceStable(data.Calendars, func(i, j int) bool { return data.Calendars[i].Name < data.Calendars[j].Name })
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := calPageTmpl.Execute(&buf, data); err != nil {
|
||||
log.Printf("calendars page template: %v", err)
|
||||
return ""
|
||||
}
|
||||
return template.HTML(buf.String())
|
||||
}
|
||||
Reference in New Issue
Block a user