mirror of
https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender.git
synced 2026-01-18 04:22:27 +01:00
feat:#49 added new ical lib for description formatting
This commit is contained in:
@@ -17,121 +17,153 @@
|
||||
package ical
|
||||
|
||||
import (
|
||||
ics "github.com/arran4/golang-ical"
|
||||
"htwkalender/ical/model"
|
||||
"htwkalender/ical/service/functions"
|
||||
clock "htwkalender/ical/service/functions/time"
|
||||
"htwkalender/ical/service/names"
|
||||
"time"
|
||||
|
||||
"github.com/jordic/goics"
|
||||
_ "time/tzdata"
|
||||
)
|
||||
|
||||
// IcalModel local type for EmitICal function
|
||||
type IcalModel struct {
|
||||
Events model.Events
|
||||
Mapping map[string]model.FeedCollection
|
||||
}
|
||||
func GenerateIcalFeed(events model.Events, mapping map[string]model.FeedCollection, userAgent string) *ics.Calendar {
|
||||
|
||||
// EmitICal implements the interface for goics
|
||||
func (icalModel IcalModel) EmitICal() goics.Componenter {
|
||||
internalClock := clock.RealClock{}
|
||||
c := generateIcalEmit(icalModel, internalClock)
|
||||
return c
|
||||
}
|
||||
cal := ics.NewCalendarFor("HTWK Kalender")
|
||||
cal.SetMethod(ics.MethodPublish)
|
||||
cal.SetProductId("-//HTWK Kalender//htwkalender.de//DE")
|
||||
cal.SetTzid("Europe/Berlin")
|
||||
cal.SetXWRCalName("HTWK Kalender")
|
||||
cal.SetXWRTimezone("Europe/Berlin")
|
||||
cal.SetVersion("2.0")
|
||||
cal.SetCalscale("GREGORIAN")
|
||||
|
||||
vTimeZone := ics.NewTimezone("Europe/Berlin")
|
||||
|
||||
vTimeZone.Components = []ics.Component{
|
||||
&ics.Daylight{
|
||||
ComponentBase: ics.ComponentBase{
|
||||
Properties: []ics.IANAProperty{
|
||||
{
|
||||
BaseProperty: ics.BaseProperty{
|
||||
IANAToken: string(ics.PropertyDtstart),
|
||||
Value: "19700329T020000",
|
||||
},
|
||||
},
|
||||
{
|
||||
BaseProperty: ics.BaseProperty{
|
||||
IANAToken: string(ics.PropertyRrule),
|
||||
Value: "FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU",
|
||||
},
|
||||
},
|
||||
{
|
||||
BaseProperty: ics.BaseProperty{
|
||||
IANAToken: string(ics.PropertyTzname),
|
||||
Value: "CEST",
|
||||
},
|
||||
},
|
||||
{
|
||||
BaseProperty: ics.BaseProperty{
|
||||
IANAToken: string(ics.PropertyTzoffsetfrom),
|
||||
Value: "+0100",
|
||||
},
|
||||
},
|
||||
{
|
||||
BaseProperty: ics.BaseProperty{
|
||||
IANAToken: string(ics.PropertyTzoffsetto),
|
||||
Value: "+0200",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
&ics.Standard{
|
||||
ComponentBase: ics.ComponentBase{
|
||||
Properties: []ics.IANAProperty{
|
||||
{
|
||||
BaseProperty: ics.BaseProperty{
|
||||
IANAToken: string(ics.PropertyDtstart),
|
||||
Value: "19701025T030000",
|
||||
},
|
||||
},
|
||||
{
|
||||
BaseProperty: ics.BaseProperty{
|
||||
IANAToken: string(ics.PropertyRrule),
|
||||
Value: "FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU",
|
||||
},
|
||||
},
|
||||
{
|
||||
BaseProperty: ics.BaseProperty{
|
||||
IANAToken: string(ics.PropertyTzname),
|
||||
Value: "CET",
|
||||
},
|
||||
},
|
||||
{
|
||||
BaseProperty: ics.BaseProperty{
|
||||
IANAToken: string(ics.PropertyTzoffsetfrom),
|
||||
Value: "+0200",
|
||||
},
|
||||
},
|
||||
{
|
||||
BaseProperty: ics.BaseProperty{
|
||||
IANAToken: string(ics.PropertyTzoffsetto),
|
||||
Value: "+0100",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
cal.AddVTimezone(vTimeZone)
|
||||
|
||||
func generateIcalEmit(icalModel IcalModel, internalClock clock.Clock) *goics.Component {
|
||||
europeTime, _ := time.LoadLocation("Europe/Berlin")
|
||||
c := goics.NewComponent()
|
||||
c.SetType("VCALENDAR")
|
||||
// PRODID is required by the standard
|
||||
c.AddProperty("PRODID", "-//HTWK Kalender//htwkalender.de//DE")
|
||||
internalClock := clock.RealClock{}
|
||||
|
||||
c.AddProperty("VERSION", "2.0")
|
||||
c.AddProperty("CALSCALE", "GREGORIAN")
|
||||
c.AddProperty("TZID", "EUROPE/BERLIN")
|
||||
c.AddProperty("X-WR-CALNAME", "HTWK Kalender")
|
||||
c.AddProperty("X-WR-TIMEZONE", "EUROPE/BERLIN")
|
||||
//add v time zone
|
||||
icalModel.vtimezone(c)
|
||||
for _, event := range events {
|
||||
mapEntry, mappingFound := mapping[event.UUID]
|
||||
|
||||
for _, event := range icalModel.Events {
|
||||
mapEntry, mappingFound := icalModel.Mapping[event.UUID]
|
||||
|
||||
s := goics.NewComponent()
|
||||
s.SetType("VEVENT")
|
||||
|
||||
s.AddProperty(goics.FormatDateTime("DTSTAMP", internalClock.Now().Local().In(europeTime)))
|
||||
|
||||
// create a unique id for the event by hashing the event start, end, course and name
|
||||
var eventHash = functions.HashString(time.Time(event.Start).String() + time.Time(event.End).String() + event.Course + event.Name + event.Rooms)
|
||||
|
||||
s.AddProperty("UID", eventHash+"@htwkalender.de")
|
||||
s.AddProperty(goics.FormatDateTime("DTEND", time.Time(event.End).Local().In(europeTime)))
|
||||
s.AddProperty(goics.FormatDateTime("DTSTART", time.Time(event.Start).Local().In(europeTime)))
|
||||
icalEvent := ics.NewEvent(eventHash + "@htwkalender.de")
|
||||
|
||||
icalEvent.SetDtStampTime(internalClock.Now().Local().In(europeTime))
|
||||
icalEvent.SetStartAt(time.Time(event.Start).Local().In(europeTime))
|
||||
icalEvent.SetEndAt(time.Time(event.End).Local().In(europeTime))
|
||||
|
||||
if mappingFound {
|
||||
addPropertyIfNotEmpty(s, "SUMMARY", replaceNameIfUserDefined(&event, mapEntry))
|
||||
addAlarmIfSpecified(s, event, mapEntry, internalClock)
|
||||
addPropertyIfNotEmpty(icalEvent, ics.ComponentPropertySummary, replaceNameIfUserDefined(&event, mapEntry))
|
||||
addAlarmIfSpecified(icalEvent, event, mapEntry, internalClock)
|
||||
} else {
|
||||
addPropertyIfNotEmpty(s, "SUMMARY", event.Name)
|
||||
addPropertyIfNotEmpty(icalEvent, ics.ComponentPropertySummary, event.Name)
|
||||
}
|
||||
|
||||
addPropertyIfNotEmpty(s, "DESCRIPTION", generateDescription(event))
|
||||
addPropertyIfNotEmpty(s, "LOCATION", event.Rooms)
|
||||
c.AddComponent(s)
|
||||
generateUserAgentSpecificDescription(icalEvent, event, userAgent)
|
||||
addPropertyIfNotEmpty(icalEvent, ics.ComponentPropertyLocation, event.Rooms)
|
||||
|
||||
cal.AddVEvent(icalEvent)
|
||||
|
||||
}
|
||||
return c
|
||||
return cal
|
||||
}
|
||||
|
||||
func (icalModel IcalModel) vtimezone(c *goics.Component) {
|
||||
tz := goics.NewComponent()
|
||||
tz.SetType("VTIMEZONE")
|
||||
tz.AddProperty("TZID", "EUROPE/BERLIN")
|
||||
//add standard time
|
||||
icalModel.standard(tz)
|
||||
//add daylight time
|
||||
icalModel.daylight(tz)
|
||||
|
||||
c.AddComponent(tz)
|
||||
}
|
||||
|
||||
func (icalModel IcalModel) standard(tz *goics.Component) {
|
||||
st := NewHtwkalenderComponent()
|
||||
st.SetType("STANDARD")
|
||||
st.AddProperty("DTSTART", "19701025T030000")
|
||||
st.AddProperty("RRULE", "FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU")
|
||||
st.AddProperty("TZOFFSETFROM", "+0200")
|
||||
st.AddProperty("TZOFFSETTO", "+0100")
|
||||
st.AddProperty("TZNAME", "CET")
|
||||
tz.AddComponent(st)
|
||||
}
|
||||
|
||||
// create an override for goics component function Write
|
||||
// to add the RRULE property
|
||||
|
||||
func (icalModel IcalModel) daylight(tz *goics.Component) {
|
||||
dt := NewHtwkalenderComponent()
|
||||
dt.SetType("DAYLIGHT")
|
||||
dt.AddProperty("DTSTART", "19700329T020000")
|
||||
dt.AddProperty("TZOFFSETFROM", "+0100")
|
||||
dt.AddProperty("TZOFFSETTO", "+0200")
|
||||
dt.AddProperty("TZNAME", "CEST")
|
||||
dt.AddProperty("RRULE", "FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU")
|
||||
tz.AddComponent(dt)
|
||||
// AddPropertyIfNotEmpty adds a property to the component if the value is not empty
|
||||
// or contains only whitespaces
|
||||
func addPropertyIfNotEmpty(component *ics.VEvent, key ics.ComponentProperty, value string) {
|
||||
if !functions.OnlyWhitespace(value) {
|
||||
component.AddProperty(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// if reminder is specified in the configuration for this event, an alarm will be added to the event
|
||||
func addAlarmIfSpecified(s *goics.Component, event model.Event, mapping model.FeedCollection, clock clock.Clock) {
|
||||
func addAlarmIfSpecified(icalEvent *ics.VEvent, event model.Event, mapping model.FeedCollection, clock clock.Clock) {
|
||||
// if event.Start > now
|
||||
// then add alarm
|
||||
if time.Time(event.Start).Local().After(clock.Now().Local()) && mapping.Reminder {
|
||||
a := goics.NewComponent()
|
||||
a.SetType("VALARM")
|
||||
a.AddProperty("TRIGGER", "-P0DT0H15M0S")
|
||||
a.AddProperty("ACTION", "DISPLAY")
|
||||
a.AddProperty("DESCRIPTION", "Next course: "+replaceNameIfUserDefined(&event, mapping)+" in "+event.Rooms)
|
||||
s.AddComponent(a)
|
||||
alarm := icalEvent.AddAlarm()
|
||||
alarm.AddProperty(ics.ComponentPropertyTrigger, "-P0DT0H15M0S")
|
||||
alarm.AddProperty(ics.ComponentPropertyAction, "DISPLAY")
|
||||
alarm.AddProperty(ics.ComponentPropertyDescription, "Next course: "+replaceNameIfUserDefined(&event, mapping)+" in "+event.Rooms)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,30 +176,3 @@ func replaceNameIfUserDefined(event *model.Event, mapping model.FeedCollection)
|
||||
|
||||
return event.Name
|
||||
}
|
||||
|
||||
// AddPropertyIfNotEmpty adds a property to the component if the value is not empty
|
||||
// or contains only whitespaces
|
||||
func addPropertyIfNotEmpty(component *goics.Component, key string, value string) {
|
||||
if !functions.OnlyWhitespace(value) {
|
||||
component.AddProperty(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
func generateDescription(event model.Event) string {
|
||||
var description string
|
||||
|
||||
if !functions.OnlyWhitespace(event.Prof) {
|
||||
description += "Profs: " + event.Prof + "\n"
|
||||
}
|
||||
if !functions.OnlyWhitespace(event.Course) {
|
||||
description += "Gruppen: " + event.Course + "\n"
|
||||
}
|
||||
if !functions.OnlyWhitespace(event.EventType) {
|
||||
description += "Typ: " + event.EventType + event.Compulsory + "\n"
|
||||
}
|
||||
if !functions.OnlyWhitespace(event.Notes) {
|
||||
description += "Notizen: " + event.Notes + "\n"
|
||||
}
|
||||
|
||||
return description
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user