112 lines
2.8 KiB
Go
112 lines
2.8 KiB
Go
package calendar
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
ics "github.com/arran4/golang-ical"
|
|
)
|
|
|
|
// CalendarClass is a class that represents what "class" the specified event is
|
|
//
|
|
// Currently, I have only observed this value as being `PUBLIC`, but other
|
|
// values are handled as panics
|
|
type CalendarClass byte
|
|
|
|
const (
|
|
ClassPublic CalendarClass = iota
|
|
)
|
|
|
|
func ParseClass(raw string) CalendarClass {
|
|
switch raw {
|
|
case "PUBLIC":
|
|
return ClassPublic
|
|
}
|
|
panic("Unknown class: " + raw)
|
|
}
|
|
|
|
func (cc CalendarClass) String() string {
|
|
switch cc {
|
|
case ClassPublic:
|
|
return "PUBLIC"
|
|
default:
|
|
panic("Unknown class")
|
|
}
|
|
}
|
|
|
|
// CalendarEvent represents a single event in a calendar that is tied to a certain date
|
|
type CalendarEvent struct {
|
|
UID string
|
|
// A summary of the event, including the name of the event
|
|
// This value is set every time as far as I can tell
|
|
Summary string
|
|
// A fescription of the event, including more specific information. Not always
|
|
// set, so don't rely on it
|
|
Description string
|
|
// Access class? of the event
|
|
Class CalendarClass
|
|
LastModified time.Time
|
|
DateStamp time.Time
|
|
StartTime time.Time
|
|
EndTime time.Time
|
|
// Every event comes with a category. This usually contains the name of the
|
|
// class, along with some other information (Semester code, CRN, sections)
|
|
Category struct {
|
|
ClassName string
|
|
OtherData string
|
|
}
|
|
}
|
|
|
|
const calendarTimeFormat = "20060102T150405Z"
|
|
|
|
// FromVEvent parses an ICS VEvent's format and outputs a specific calendar event, or an error
|
|
func FromVEvent(external *ics.VEvent) (event CalendarEvent, err error) {
|
|
if len(external.Components) > 0 {
|
|
panic("Event has unhandled components")
|
|
}
|
|
|
|
for _, prop := range external.Properties {
|
|
if len(prop.ICalParameters) > 0 {
|
|
panic("Property has unhandled ICalParameters")
|
|
}
|
|
|
|
switch prop.IANAToken {
|
|
case "UID":
|
|
event.UID = prop.Value
|
|
case "SUMMARY":
|
|
event.Summary = prop.Value
|
|
case "DESCRIPTION":
|
|
event.Description = prop.Value
|
|
case "CLASS":
|
|
event.Class = ParseClass(prop.Value)
|
|
case "LAST-MODIFIED":
|
|
event.LastModified, err = time.Parse(calendarTimeFormat, prop.Value)
|
|
if err != nil {
|
|
return event, err
|
|
}
|
|
case "DTSTAMP":
|
|
event.DateStamp, err = time.Parse(calendarTimeFormat, prop.Value)
|
|
if err != nil {
|
|
return event, err
|
|
}
|
|
case "DTSTART":
|
|
event.StartTime, err = time.Parse(calendarTimeFormat, prop.Value)
|
|
if err != nil {
|
|
return event, err
|
|
}
|
|
case "DTEND":
|
|
event.EndTime, err = time.Parse(calendarTimeFormat, prop.Value)
|
|
if err != nil {
|
|
return event, err
|
|
}
|
|
case "CATEGORIES":
|
|
dashIndex := strings.Index(prop.Value, "-")
|
|
event.Category.ClassName = prop.Value[:dashIndex]
|
|
event.Category.OtherData = prop.Value[dashIndex:]
|
|
default:
|
|
panic("Unknown token when parsing event: " + prop.IANAToken)
|
|
}
|
|
}
|
|
return event, nil
|
|
}
|