app/calendar/ics.go

76 lines
1.7 KiB
Go

package calendar
import (
"bytes"
"fmt"
"strings"
"text/template"
"time"
"kumoly.io/kumoly/app/store"
)
const ics_base = `BEGIN:VCALENDAR
PRODID:-//Kumoly//Kumoly App v0.0.1//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:{{.Name}}
X-WR-TIMEZONE:Asia/Taipei
X-WR-CALDESC:{{.Name}}{{/*
BEGIN:VTIMEZONE
TZID:{{.Timezone}}
X-LIC-LOCATION:{{.Timezone}}
BEGIN:STANDARD
TZOFFSETFROM:+0800
TZOFFSETTO:+0800
TZNAME:CST
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE*/}}{{with .Events}}{{ if gt (len .) 0 }}{{ range $event := . }}
BEGIN:VEVENT
DTSTART:{{$event.Start|icstime}}
DTEND:{{$event.End|icstime}}
DTSTAMP:{{now|icstime}}
UID:{{$event.ID}}
CREATED:{{$event.CreatedAt|icstime}}
DESCRIPTION:{{$event.ID}}
LAST-MODIFIED:{{$event.UpdatedAt|icstime}}
LOCATION:{{$event.Location}}
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:{{$event.Name}}
TRANSP:TRANSPARENT
END:VEVENT{{end}}{{end}}{{end}}
END:VCALENDAR`
var tmpl *template.Template
func init() {
tmpl = template.Must(template.New("").Funcs(template.FuncMap{
"icstime": icstime,
"now": func() time.Time { return time.Now() },
"tadd": func(t time.Time, min int) time.Time { return t.Add(time.Minute * time.Duration(min)) },
}).Parse(ics_base))
}
func ICS(cal_id string, from time.Time, to time.Time) (string, error) {
cal := &Calendar{}
store.DB.Preload("Events", `"start" > ? and "end" < ?`, from, to).
First(cal, "id = ?", cal_id)
buf := &bytes.Buffer{}
if err := tmpl.Execute(buf, cal); err != nil {
return "", err
}
return strings.ReplaceAll(buf.String(), "\n", "\r\n"), nil
}
func icstime(t time.Time) string {
return t.UTC().Format("20060102T150405Z")
}
func offsetStr(offset int) string {
return fmt.Sprintf("%+05d", offset/36)
}