diff --git a/backend/model/icalModel.go b/backend/model/icalModel.go index 2060712..53b7aa6 100644 --- a/backend/model/icalModel.go +++ b/backend/model/icalModel.go @@ -27,4 +27,5 @@ type FeedCollection struct { Name string `db:"Name" json:"name"` Course string `db:"course" json:"course"` UserDefinedName string `db:"userDefinedName" json:"userDefinedName"` + Reminder bool `db:"reminder" json:"reminder"` } diff --git a/backend/service/db/dbEvents.go b/backend/service/db/dbEvents.go index acad6af..47f59db 100644 --- a/backend/service/db/dbEvents.go +++ b/backend/service/db/dbEvents.go @@ -118,18 +118,23 @@ func buildIcalQueryForModules(modules []model.FeedCollection) dbx.Expression { // GetPlanForModules returns all events for the given modules with the given course // used for the ical feed -func GetPlanForModules(app *pocketbase.PocketBase, modules []model.FeedCollection) model.Events { +func GetPlanForModules(app *pocketbase.PocketBase, modules map[string]model.FeedCollection) model.Events { var events model.Events + modulesArray := make([]model.FeedCollection, 0, len(modules)) + for _, value := range modules { + modulesArray = append(modulesArray, value) + } + // iterate over modules in 100 batch sizes for i := 0; i < len(modules); i += 100 { var moduleBatch []model.FeedCollection if i+100 > len(modules) { - moduleBatch = modules[i:] + moduleBatch = modulesArray[i:] } else { - moduleBatch = modules[i : i+100] + moduleBatch = modulesArray[i : i+100] } var selectedModulesQuery = buildIcalQueryForModules(moduleBatch) diff --git a/backend/service/ical/ical.go b/backend/service/ical/ical.go index baee837..4fa472b 100644 --- a/backend/service/ical/ical.go +++ b/backend/service/ical/ical.go @@ -3,14 +3,15 @@ package ical import ( "bytes" "encoding/json" - "github.com/jordic/goics" - "github.com/labstack/echo/v5" - "github.com/pocketbase/pocketbase" - "github.com/pocketbase/pocketbase/apis" "htwkalender/model" "htwkalender/service/db" "net/http" "time" + + "github.com/jordic/goics" + "github.com/labstack/echo/v5" + "github.com/pocketbase/pocketbase" + "github.com/pocketbase/pocketbase/apis" ) const expirationTime = 5 * time.Minute @@ -23,8 +24,13 @@ func Feed(c echo.Context, app *pocketbase.PocketBase, token string) error { return c.JSON(http.StatusNotFound, err) } - var modules []model.FeedCollection - _ = json.Unmarshal([]byte(feed.Modules), &modules) + modules := make(map[string]model.FeedCollection) + var modulesArray []model.FeedCollection + _ = json.Unmarshal([]byte(feed.Modules), &modulesArray) + + for _, module := range modulesArray { + modules[module.UUID] = module + } newFeed, err := createFeedForToken(app, modules) if err != nil { @@ -41,7 +47,7 @@ func Feed(c echo.Context, app *pocketbase.PocketBase, token string) error { return nil } -func createFeedForToken(app *pocketbase.PocketBase, modules []model.FeedCollection) (*model.FeedModel, error) { +func createFeedForToken(app *pocketbase.PocketBase, modules map[string]model.FeedCollection) (*model.FeedModel, error) { res := db.GetPlanForModules(app, modules) b := bytes.Buffer{} goics.NewICalEncode(&b).Encode(IcalModel{Events: res, Mapping: modules}) diff --git a/backend/service/ical/icalFileGeneration.go b/backend/service/ical/icalFileGeneration.go index eb4e2e7..fa9e205 100644 --- a/backend/service/ical/icalFileGeneration.go +++ b/backend/service/ical/icalFileGeneration.go @@ -12,7 +12,7 @@ import ( // IcalModel local type for EmitICal function type IcalModel struct { Events model.Events - Mapping []model.FeedCollection + Mapping map[string]model.FeedCollection } // EmitICal implements the interface for goics @@ -27,13 +27,22 @@ func (icalModel IcalModel) EmitICal() goics.Componenter { c.AddProperty("X-WR-TIMEZONE", "Europe/Berlin") c.AddProperty("X-LIC-LOCATION", "Europe/Berlin") for _, event := range icalModel.Events { + mapEntry, mappingFound := icalModel.Mapping[event.UUID] + s := goics.NewComponent() s.SetType("VEVENT") k, v := goics.FormatDateTime("DTEND;TZID=Europe/Berlin", event.End.Time().Local().In(europeTime)) s.AddProperty(k, v) k, v = goics.FormatDateTime("DTSTART;TZID=Europe/Berlin", event.Start.Time().Local().In(europeTime)) s.AddProperty(k, v) - s.AddProperty("SUMMARY", replaceNameIfUserDefined(&event, icalModel.Mapping)) + + if mappingFound { + s.AddProperty("SUMMARY", replaceNameIfUserDefined(&event, mapEntry)) + addAlarmIfSpecified(s, event, mapEntry) + } else { + s.AddProperty("SUMMARY", event.Name) + } + s.AddProperty("DESCRIPTION", generateDescription(event)) s.AddProperty("LOCATION", event.Rooms) c.AddComponent(s) @@ -41,12 +50,22 @@ func (icalModel IcalModel) EmitICal() goics.Componenter { return c } -func replaceNameIfUserDefined(event *model.Event, mapping []model.FeedCollection) string { - for _, mapEntry := range mapping { - if mapEntry.Name == event.Name && !functions.OnlyWhitespace(mapEntry.UserDefinedName) { - return names.ReplaceTemplateSubStrings(mapEntry.UserDefinedName, *event) - } +func addAlarmIfSpecified(s *goics.Component, event model.Event, mapping model.FeedCollection) { + if mapping.Reminder { + a := goics.NewComponent() + a.SetType("VALARM") + a.AddProperty("TRIGGER", "-PT15M") + a.AddProperty("ACTION", "DISPLAY") + a.AddProperty("DESCRIPTION", "Next course: "+replaceNameIfUserDefined(&event, mapping)+" in "+event.Rooms) + s.AddComponent(a) } +} + +func replaceNameIfUserDefined(event *model.Event, mapping model.FeedCollection) string { + if !functions.OnlyWhitespace(mapping.UserDefinedName) { + return names.ReplaceTemplateSubStrings(mapping.UserDefinedName, *event) + } + return event.Name } diff --git a/frontend/src/components/RenameModules.vue b/frontend/src/components/RenameModules.vue index af333bf..fe98366 100644 --- a/frontend/src/components/RenameModules.vue +++ b/frontend/src/components/RenameModules.vue @@ -17,6 +17,7 @@ const tableData = ref( const columns = ref([ { field: "Course", header: "Course" }, { field: "Module", header: "Module" }, + { field: "Reminder", header: "Reminder"} ]); const helpVisible: Ref = ref(false); @@ -36,7 +37,7 @@ async function finalStep() {