From ad197f366d20e08f10c375a8ef0e90e9fb33457d Mon Sep 17 00:00:00 2001 From: Elmar Kresse Date: Fri, 17 May 2024 18:30:35 +0000 Subject: [PATCH] test:#324 change eventService and fetch routine --- backend/main.go | 2 +- backend/service/addRoute.go | 58 +++++++++++++------ backend/service/addSchedule.go | 6 +- backend/service/course/courseFunctions.go | 7 +-- backend/service/date/dateFormat.go | 2 +- backend/service/db/dbEvents.go | 17 +++++- backend/service/db/dbGroups.go | 6 +- backend/service/events/eventService.go | 38 +++++------- backend/service/feed/feedFunctions.go | 6 +- backend/service/fetch/sport/sportFetcher.go | 13 +++-- .../fetch/v1/fetchSeminarEventService.go | 10 ++-- .../fetch/v1/fetchSeminarGroupService.go | 6 +- backend/service/fetch/v2/fetcher.go | 2 +- backend/service/functions/time/parse.go | 2 +- 14 files changed, 102 insertions(+), 73 deletions(-) diff --git a/backend/main.go b/backend/main.go index d39757a..8b78ba1 100644 --- a/backend/main.go +++ b/backend/main.go @@ -41,6 +41,6 @@ func main() { service.AddSchedules(app) if err := app.Start(); err != nil { - slog.Error("Failed to start app: %v", err) + slog.Error("Failed to start app: ", "error", err) } } diff --git a/backend/service/addRoute.go b/backend/service/addRoute.go index 24991c3..eeb6884 100644 --- a/backend/service/addRoute.go +++ b/backend/service/addRoute.go @@ -17,6 +17,7 @@ package service import ( + "htwkalender/service/course" "htwkalender/service/events" "htwkalender/service/fetch/sport" v1 "htwkalender/service/fetch/v1" @@ -41,7 +42,7 @@ func AddRoutes(app *pocketbase.PocketBase) { Handler: func(c echo.Context) error { savedEvents, err := v2.ParseEventsFromRemote(app) if err != nil { - slog.Error("Failed to parse events from remote: %v", err) + slog.Error("Failed to parse events from remote: ", "error", err) return c.JSON(http.StatusBadRequest, "Failed to parse events from remote") } else { return c.JSON(http.StatusOK, savedEvents) @@ -58,6 +59,25 @@ func AddRoutes(app *pocketbase.PocketBase) { return nil }) + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + _, err := e.Router.AddRoute(echo.Route{ + Method: http.MethodGet, + Path: "/api/fetch/daily/events", + Handler: func(c echo.Context) error { + course.UpdateCourse(app) + return c.JSON(http.StatusOK, "Daily events fetched") + }, + Middlewares: []echo.MiddlewareFunc{ + apis.ActivityLogger(app), + apis.RequireAdminAuth(), + }, + }) + if err != nil { + return err + } + return nil + }) + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { _, err := e.Router.AddRoute(echo.Route{ Method: http.MethodGet, @@ -156,7 +176,7 @@ func AddRoutes(app *pocketbase.PocketBase) { date := c.QueryParam("date") roomSchedule, err := room.GetRoomScheduleForDay(app, roomParam, date) if err != nil { - slog.Error("Failed to get room schedule for day: %v", err) + slog.Error("Failed to get room schedule for day: ", "error", err) return c.JSON(http.StatusBadRequest, "Failed to get room schedule for day") } return c.JSON(http.StatusOK, roomSchedule) @@ -182,7 +202,7 @@ func AddRoutes(app *pocketbase.PocketBase) { from := c.QueryParam("from") roomSchedule, err := room.GetRoomSchedule(app, roomParam, from, to) if err != nil { - slog.Error("Failed to get room schedule: %v", err) + slog.Error("Failed to get room schedule:", "error", err) return c.JSON(http.StatusBadRequest, "Failed to get room schedule") } return c.JSON(http.StatusOK, roomSchedule) @@ -205,17 +225,17 @@ func AddRoutes(app *pocketbase.PocketBase) { Handler: func(c echo.Context) error { from, err := time.ParseTime(c.QueryParam("from")) if err != nil { - slog.Error("Failed to parse time: %v", err) + slog.Error("Failed to parse time: ", "error", err) return c.JSON(http.StatusBadRequest, "Failed to parse time") } to, err := time.ParseTime(c.QueryParam("to")) if err != nil { - slog.Error("Failed to parse time: %v", err) + slog.Error("Failed to parse time: ", "error", err) return c.JSON(http.StatusBadRequest, "Failed to parse time") } rooms, err := room.GetFreeRooms(app, from, to) if err != nil { - slog.Error("Failed to get free rooms: %v", err) + slog.Error("Failed to get free rooms: ", "error", err) return c.JSON(http.StatusBadRequest, "Failed to get free rooms") } return c.JSON(http.StatusOK, rooms) @@ -237,12 +257,14 @@ func AddRoutes(app *pocketbase.PocketBase) { Method: http.MethodGet, Path: "/api/course/modules", Handler: func(c echo.Context) error { - course := c.QueryParam("course") - semester := c.QueryParam("semester") - modules, err := events.GetModulesForCourseDistinct(app, course, semester) + modules, err := events.GetModulesForCourseDistinct( + app, + c.QueryParam("course"), + c.QueryParam("semester"), + ) if err != nil { - slog.Error("Failed to get modules for course and semester: %v", err) + slog.Error("Failed to get modules for course and semester: ", "error", err) return c.JSON(http.StatusBadRequest, "Failed to get modules for course and semester") } else { return c.JSON(http.StatusOK, modules) @@ -265,7 +287,7 @@ func AddRoutes(app *pocketbase.PocketBase) { Handler: func(c echo.Context) error { modules, err := events.GetAllModulesDistinct(app) if err != nil { - slog.Error("Failed to get modules: %v", err) + slog.Error("Failed to get modules: ", "error", err) return c.JSON(http.StatusBadRequest, "Failed to get modules") } return c.JSON(http.StatusOK, modules) @@ -288,7 +310,7 @@ func AddRoutes(app *pocketbase.PocketBase) { requestModule := c.QueryParam("uuid") module, err := events.GetModuleByUUID(app, requestModule) if err != nil { - slog.Error("Failed to get module: %v", err) + slog.Error("Failed to get module: ", "error", err) return c.JSON(http.StatusBadRequest, "Failed to get module") } else { return c.JSON(http.StatusOK, module) @@ -338,7 +360,7 @@ func AddRoutes(app *pocketbase.PocketBase) { courses, err := events.GetAllCoursesForSemesterWithEvents(app, semester) if err != nil { - slog.Error("Failed to get courses for semester with events: %v", err) + slog.Error("Failed to get courses for semester with events: ", "error", err) return c.JSON(http.StatusBadRequest, "Failed to get courses for semester with events") } else { return c.JSON(200, courses) @@ -359,11 +381,13 @@ func AddRoutes(app *pocketbase.PocketBase) { Method: http.MethodDelete, Path: "/api/events", Handler: func(c echo.Context) error { - course := c.QueryParam("course") - semester := c.QueryParam("semester") - err := events.DeleteAllEventsByCourseAndSemester(app, course, semester) + err := events.DeleteAllEventsByCourseAndSemester( + app, + c.QueryParam("course"), + c.QueryParam("semester"), + ) if err != nil { - slog.Error("Failed to delete events: %v", err) + slog.Error("Failed to delete events: ", "error", err) return c.JSON(http.StatusBadRequest, "Failed to delete events") } else { return c.JSON(http.StatusBadRequest, "Events deleted") diff --git a/backend/service/addSchedule.go b/backend/service/addSchedule.go index 3c38153..9d2b901 100644 --- a/backend/service/addSchedule.go +++ b/backend/service/addSchedule.go @@ -42,7 +42,7 @@ func AddSchedules(app *pocketbase.PocketBase) { slog.Info("Started updating courses schedule") groups, err := v1.FetchSeminarGroups(app) if err != nil { - slog.Warn("Failed to fetch seminar groups: %v", err) + slog.Warn("Failed to fetch seminar groups: ", "error", err) } slog.Info("Successfully fetched " + strconv.FormatInt(int64(len(groups)), 10) + " seminar groups") }) @@ -66,7 +66,7 @@ func AddSchedules(app *pocketbase.PocketBase) { slog.Info("Started fetching sport events schedule") sportEvents, err := sport.FetchAndUpdateSportEvents(app) if err != nil { - slog.Error("Failed to fetch and save sport events: %v", err) + slog.Error("Failed to fetch and save sport events:", "error", err) } slog.Info("Successfully fetched " + strconv.FormatInt(int64(len(sportEvents)), 10) + " sport events") }) @@ -75,7 +75,7 @@ func AddSchedules(app *pocketbase.PocketBase) { scheduler.MustAdd("fetchEvents", "0 22 * * 6", func() { savedEvents, err := v2.FetchAllEventsAndSave(app, time.RealClock{}) if err != nil { - slog.Error("Failed to fetch and save events: %v", err) + slog.Error("Failed to fetch and save events: ", "error", err) } else { slog.Info("Successfully fetched " + strconv.FormatInt(int64(len(savedEvents)), 10) + " events") } diff --git a/backend/service/course/courseFunctions.go b/backend/service/course/courseFunctions.go index 43720b7..d51ad00 100644 --- a/backend/service/course/courseFunctions.go +++ b/backend/service/course/courseFunctions.go @@ -20,17 +20,14 @@ import ( "github.com/pocketbase/pocketbase" "htwkalender/service/events" "log/slog" - "strconv" ) func UpdateCourse(app *pocketbase.PocketBase) { courses := events.GetAllCourses(app) for _, course := range courses { - savedEvents, err := events.UpdateModulesForCourse(app, course) + _, err := events.UpdateModulesForCourse(app, course) if err != nil { - slog.Warn("Update Course: "+course+" failed: %v", err) - } else { - slog.Info("Updated Course: " + course + " with " + strconv.FormatInt(int64(len(savedEvents)), 10) + " events") + slog.Warn("Update Course: "+course+" failed:", "error", err) } } } diff --git a/backend/service/date/dateFormat.go b/backend/service/date/dateFormat.go index a8e9c16..8eee644 100644 --- a/backend/service/date/dateFormat.go +++ b/backend/service/date/dateFormat.go @@ -29,7 +29,7 @@ func GetDateFromWeekNumber(year int, weekNumber int, dayName string) (time.Time, europeTime, err := time.LoadLocation("Europe/Berlin") if err != nil { - slog.Error("Failed to load location: ", err) + slog.Error("Failed to load location: ", "error", err) return time.Time{}, err } diff --git a/backend/service/db/dbEvents.go b/backend/service/db/dbEvents.go index 42869f3..0d1fe04 100644 --- a/backend/service/db/dbEvents.go +++ b/backend/service/db/dbEvents.go @@ -192,13 +192,26 @@ func GetPlanForModules(app *pocketbase.PocketBase, modules map[string]model.Feed return events, nil } +func GetAllEventsForCourse(app *pocketbase.PocketBase, course string) (model.Events, error) { + var events model.Events + + // get all events from event records in the events collection + err := app.Dao().DB().Select("*").From("events").Where(dbx.NewExp("course = {:course}", dbx.Params{"course": course})).All(&events) + if err != nil { + slog.Error("Error while getting events from database: ", "error", err) + return nil, fmt.Errorf("error while getting events from database for course %s", course) + } + + return events, nil +} + func GetAllModulesForCourse(app *pocketbase.PocketBase, course string, semester string) (model.Events, error) { var events model.Events // get all events from event records in the events collection err := app.Dao().DB().Select("*").From("events").Where(dbx.NewExp("course = {:course} AND semester = {:semester}", dbx.Params{"course": course, "semester": semester})).GroupBy("Name").Distinct(true).All(&events) if err != nil { - slog.Error("Error while getting events from database: ", err) + slog.Error("Error while getting events from database: ", "error", err) return nil, fmt.Errorf("error while getting events from database for course %s and semester %s", course, semester) } @@ -210,7 +223,7 @@ func GetAllModulesDistinctByNameAndCourse(app *pocketbase.PocketBase) ([]model.M err := app.Dao().DB().Select("Name", "EventType", "Prof", "course", "semester", "uuid").From("events").GroupBy("Name", "Course").Distinct(true).All(&modules) if err != nil { - slog.Error("Error while getting events from database: ", err) + slog.Error("Error while getting events from database: ", "error", err) return nil, fmt.Errorf("error while getting events distinct by name and course from data") } diff --git a/backend/service/db/dbGroups.go b/backend/service/db/dbGroups.go index 1f51c15..1e5d02c 100644 --- a/backend/service/db/dbGroups.go +++ b/backend/service/db/dbGroups.go @@ -85,7 +85,7 @@ func GetAllCourses(app *pocketbase.PocketBase) []string { // get all rooms from event records in the events collection err := app.Dao().DB().Select("course").From("groups").All(&courses) if err != nil { - slog.Error("Error while getting groups from database: ", err) + slog.Error("Error while getting groups from database: ", "error", err) return []string{} } @@ -107,7 +107,7 @@ func GetAllCoursesForSemester(app *pocketbase.PocketBase, semester string) []str // get all courses for a specific semester err := app.Dao().DB().Select("course").From("groups").Where(dbx.NewExp("semester = {:semester}", dbx.Params{"semester": semester})).All(&courses) if err != nil { - slog.Error("Error while getting groups from database: ", err) + slog.Error("Error while getting groups from database: ", "error", err) return []string{} } @@ -130,7 +130,7 @@ func GetAllCoursesForSemesterWithEvents(app *pocketbase.PocketBase, semester str // get all courses from events distinct for a specific semester err := app.Dao().DB().Select("course").From("events").Where(dbx.NewExp("semester = {:semester}", dbx.Params{"semester": semester})).Distinct(true).All(&courses) if err != nil { - slog.Error("Error while getting groups from database: ", err) + slog.Error("Error while getting groups from database: ", "error", err) return nil, err } diff --git a/backend/service/events/eventService.go b/backend/service/events/eventService.go index ce6dbbc..fedfa51 100644 --- a/backend/service/events/eventService.go +++ b/backend/service/events/eventService.go @@ -23,6 +23,7 @@ import ( "htwkalender/service/fetch/v1" "htwkalender/service/functions" "log/slog" + "strconv" ) func GetModulesForCourseDistinct(app *pocketbase.PocketBase, course string, semester string) (model.Events, error) { @@ -133,21 +134,13 @@ func UpdateModulesForCourse(app *pocketbase.PocketBase, course string) (model.Ev //if there are no events in the database, save the new events //get all events for the course and the semester - events, err := db.GetAllModulesForCourse(app, course, "ws") + dbEvents, err := db.GetAllEventsForCourse(app, course) if err != nil { return nil, err } - // append all events for the course and the semester to the events array for ss - summerEvents, err := db.GetAllModulesForCourse(app, course, "ss") - if err != nil { - return nil, err - } - - events = append(events, summerEvents...) - //if there are no events in the database, save the new events - if len(events) == 0 { + if len(dbEvents) == 0 { events, dbError := db.SaveSeminarGroupEvents(seminarGroup, app) if dbError != nil { return nil, dbError @@ -161,32 +154,33 @@ func UpdateModulesForCourse(app *pocketbase.PocketBase, course string) (model.Ev // check which events are not already in the database and need to be inserted/saved for _, event := range seminarGroup.Events { - if !ContainsEvent(events, event) { + if !ContainsEvent(dbEvents, event) { insertList = append(insertList, event) } } - // save all events that are in the insertList - savedEvents, err := db.SaveEvents(insertList, app) - if err != nil { - slog.Error("Failed to save events: %v", err) - return nil, err - } - // check which events are in the database but not in the seminarGroup and need to be deleted - for _, event := range events { - if !ContainsEvent(seminarGroup.Events, event) { - deleteList = append(deleteList, event) + for _, dbEvent := range dbEvents { + if !ContainsEvent(seminarGroup.Events, dbEvent) { + deleteList = append(deleteList, dbEvent) } } // delete all events that are in the deleteList err = db.DeleteEvents(deleteList, app) if err != nil { - slog.Error("Failed to delete events: %v", err) + slog.Error("Failed to delete events:", "error", err) return nil, err } + // save all events that are in the insertList + savedEvents, err := db.SaveEvents(insertList, app) + if err != nil { + slog.Error("Failed to save events: ", "error", err) + return nil, err + } + + slog.Info("Course: " + course + " - Event changes: " + strconv.FormatInt(int64(len(insertList)), 10) + " new events, " + strconv.FormatInt(int64(len(deleteList)), 10) + " deleted events") return savedEvents, nil } diff --git a/backend/service/feed/feedFunctions.go b/backend/service/feed/feedFunctions.go index 050c5e2..894f322 100644 --- a/backend/service/feed/feedFunctions.go +++ b/backend/service/feed/feedFunctions.go @@ -30,7 +30,7 @@ import ( func ClearFeeds(db *daos.Dao, months int, clock localTime.Clock) { feeds, err := database.GetAllFeeds(db) if err != nil { - slog.Error("CleanFeeds: failed to get all feeds", err) + slog.Error("CleanFeeds: failed to get all feeds", "error", err) return } for _, feed := range feeds { @@ -44,8 +44,8 @@ func ClearFeeds(db *daos.Dao, months int, clock localTime.Clock) { var sqlResult sql.Result sqlResult, err = db.DB().Delete("feeds", dbx.NewExp("id = {:id}", dbx.Params{"id": feed.GetId()})).Execute() if err != nil { - slog.Error("CleanFeeds: delete feed "+feed.GetId()+" failed", err) - slog.Error("SQL Result: ", sqlResult) + slog.Error("CleanFeeds: delete feed "+feed.GetId()+" failed", "error", err) + slog.Error("SQL Result: ", "error", sqlResult) } else { slog.Info("CleanFeeds: delete feed " + feed.GetId() + " successful") } diff --git a/backend/service/fetch/sport/sportFetcher.go b/backend/service/fetch/sport/sportFetcher.go index 583815c..c2dac05 100644 --- a/backend/service/fetch/sport/sportFetcher.go +++ b/backend/service/fetch/sport/sportFetcher.go @@ -209,7 +209,7 @@ func getWeekEvents(start time.Time, end time.Time, cycle string) ([]time.Time, [ for _, day := range days { weekDay, err := getDayInt(day) if err != nil { - slog.Error("Error while getting day int: "+day+" ", err) + slog.Error("Error while getting day int: "+day+" ", "error", err) } else { weekEvents = append(weekEvents, model.SportDayStartEnd{ Start: time.Date(start.Year(), start.Month(), start.Day(), startHour, startMinute, 0, 0, start.Location()), @@ -234,7 +234,8 @@ func getWeekEvents(start time.Time, end time.Time, cycle string) ([]time.Time, [ endI, endIErr = getDayInt(days[1]) if endIErr != nil || startIErr != nil { - slog.Error("Error while getting day int: "+days[0]+" - "+days[1]+" :", startIErr, endIErr) + slog.Error("StartError while getting day int: "+days[0]+" - "+days[1]+" :", "error", startIErr) + slog.Error("EndError while getting day int: "+days[0]+" - "+days[1]+" :", "error", endIErr) } else { //create a int array with all days from start to end day var daysBetween []int @@ -259,7 +260,7 @@ func getWeekEvents(start time.Time, end time.Time, cycle string) ([]time.Time, [ dayInt, err := getDayInt(day) if err != nil { - slog.Error("Error while getting day int: "+day+" ", err) + slog.Error("Error while getting day int: "+day+" ", "error", err) } else { dayNumbers = append(dayNumbers, dayInt) } @@ -271,7 +272,7 @@ func getWeekEvents(start time.Time, end time.Time, cycle string) ([]time.Time, [ weekDay, err := getDayInt(day) if err != nil { - slog.Error("Error while getting day int: "+day+" ", err) + slog.Error("Error while getting day int: "+day+" ", "error", err) } else { weekEvents = append(weekEvents, model.SportDayStartEnd{ Start: time.Date(start.Year(), start.Month(), start.Day(), startHour, startMinute, 0, 0, start.Location()), @@ -378,7 +379,7 @@ func fetchAllAvailableSportCourses() ([]string, error) { var doc, err = htmlRequest(url) if err != nil { - slog.Error("Error while fetching sport courses from webpage", err) + slog.Error("Error while fetching sport courses from webpage", "error", err) return nil, err } @@ -443,7 +444,7 @@ func htmlRequest(url string) (*goquery.Document, error) { defer func(Body io.ReadCloser) { readErr := Body.Close() if readErr != nil { - slog.Error("Error while closing response body from html request", readErr) + slog.Error("Error while closing response body from html request", "error", readErr) return } }(resp.Body) diff --git a/backend/service/fetch/v1/fetchSeminarEventService.go b/backend/service/fetch/v1/fetchSeminarEventService.go index c6ac6e4..ca02906 100644 --- a/backend/service/fetch/v1/fetchSeminarEventService.go +++ b/backend/service/fetch/v1/fetchSeminarEventService.go @@ -103,19 +103,18 @@ func parseSeminarGroup(result string) model.SeminarGroup { if eventTables == nil || allDayLabels == nil { return model.SeminarGroup{} } - - eventsWithCombinedWeeks := toEvents(eventTables, allDayLabels) + course := findFirstSpanWithClass(table, "header-2-0-1").FirstChild.Data + eventsWithCombinedWeeks := toEvents(eventTables, allDayLabels, course) splitEventsByWeekVal := splitEventsByWeek(eventsWithCombinedWeeks) events := splitEventsBySingleWeek(splitEventsByWeekVal) semesterString := findFirstSpanWithClass(table, "header-0-2-0").FirstChild.Data - course := findFirstSpanWithClass(table, "header-2-0-1").FirstChild.Data semester, year := extractSemesterAndYear(semesterString) events = convertWeeksToDates(events, semester, year) events = generateUUIDs(events, course) events, err = SplitEventType(events) if err != nil { - slog.Error("Error occurred while splitting event types: %s", err) + slog.Error("Error occurred while splitting event types:", "error", err) return model.SeminarGroup{} } @@ -204,7 +203,7 @@ func extractSemesterAndYear(semesterString string) (string, string) { return semesterShortcut, year } -func toEvents(tables [][]*html.Node, days []string) []model.Event { +func toEvents(tables [][]*html.Node, days []string, course string) []model.Event { var events []model.Event for table := range tables { @@ -225,6 +224,7 @@ func toEvents(tables [][]*html.Node, days []string) []model.Event { Rooms: getTextContent(tableData[6]), Notes: getTextContent(tableData[7]), BookedAt: getTextContent(tableData[8]), + Course: course, }) } } diff --git a/backend/service/fetch/v1/fetchSeminarGroupService.go b/backend/service/fetch/v1/fetchSeminarGroupService.go index 7809ec9..9e909e5 100644 --- a/backend/service/fetch/v1/fetchSeminarGroupService.go +++ b/backend/service/fetch/v1/fetchSeminarGroupService.go @@ -68,7 +68,7 @@ func FetchSeminarGroups(app *pocketbase.PocketBase) ([]*models.Record, error) { for i, semester := range semesterString { results[i], err = getSeminarHTML(semester) if err != nil { - slog.Error("Error while fetching seminar groups for: "+semester, err) + slog.Error("Error while fetching seminar groups for: "+semester, "error", err) return nil, err } groups = append(groups, parseSeminarGroups(results[i], semester)...) @@ -79,14 +79,14 @@ func FetchSeminarGroups(app *pocketbase.PocketBase) ([]*models.Record, error) { collection, dbError := db.FindCollection(app, "groups") if dbError != nil { - slog.Error("Error while searching collection groups", dbError) + slog.Error("Error while searching collection groups", "error", dbError) return nil, err } var insertedGroups []*models.Record insertedGroups, dbError = db.SaveGroups(groups, collection, app) if dbError != nil { - slog.Error("Error while saving groups", dbError) + slog.Error("Error while saving groups", "error", dbError) return nil, err } diff --git a/backend/service/fetch/v2/fetcher.go b/backend/service/fetch/v2/fetcher.go index 34dd2ad..b26fe8c 100644 --- a/backend/service/fetch/v2/fetcher.go +++ b/backend/service/fetch/v2/fetcher.go @@ -141,7 +141,7 @@ func parseEventForOneSemester(url string) ([]model.Event, error) { events = convertWeeksToDates(events, semester, year) events, err = v1.SplitEventType(events) if err != nil { - slog.Error("Error occurred while splitting event types: %s", err) + slog.Error("Error occurred while splitting event types: ", "error", err) return nil, err } events = switchNameAndNotesForExam(events) diff --git a/backend/service/functions/time/parse.go b/backend/service/functions/time/parse.go index 9a5fd93..46523bc 100644 --- a/backend/service/functions/time/parse.go +++ b/backend/service/functions/time/parse.go @@ -29,7 +29,7 @@ func ParseTime(timeString string) (time.Time, error) { func ParseAsTypesDatetime(time time.Time) types.DateTime { dateTime, err := types.ParseDateTime(time) if err != nil { - slog.Error("Failed to parse time as types.DateTime: %v", err) + slog.Error("Failed to parse time as types.DateTime", "error", err) return types.DateTime{} } return dateTime