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:{{(tadd $event.End 5)|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) }