From c874cbed30df0156f464cfd46791a5c42d16a96b Mon Sep 17 00:00:00 2001 From: Elmar Kresse <18119527+masterElmar@users.noreply.github.com> Date: Thu, 26 Oct 2023 22:42:42 +0200 Subject: [PATCH 1/6] fix:#main hotfix removed wrong minimum required age --- backend/service/ical/ical.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/backend/service/ical/ical.go b/backend/service/ical/ical.go index 6ff6372..baee837 100644 --- a/backend/service/ical/ical.go +++ b/backend/service/ical/ical.go @@ -23,17 +23,14 @@ func Feed(c echo.Context, app *pocketbase.PocketBase, token string) error { return c.JSON(http.StatusNotFound, err) } - created := feed.Created - var modules []model.FeedCollection _ = json.Unmarshal([]byte(feed.Modules), &modules) - if created.Time().Add(time.Hour * 265).Before(time.Now()) { - newFeed, err := createFeedForToken(app, modules) - if err != nil { - return c.JSON(http.StatusInternalServerError, err) - } - result = newFeed.Content + + newFeed, err := createFeedForToken(app, modules) + if err != nil { + return c.JSON(http.StatusInternalServerError, err) } + result = newFeed.Content responseWriter.Header().Set("Content-type", "text/calendar") responseWriter.Header().Set("charset", "utf-8") From 090342736d6eedc607ce3778bdb65dc4076e6b78 Mon Sep 17 00:00:00 2001 From: Elmar Kresse <18119527+masterElmar@users.noreply.github.com> Date: Fri, 27 Oct 2023 00:03:14 +0200 Subject: [PATCH 2/6] fix:#28 fixed info panel and edited backend api for fix --- backend/service/addRoute.go | 16 +++++++++++----- backend/service/db/dbEvents.go | 4 ++-- backend/service/events/eventService.go | 6 +++--- frontend/src/api/fetchModule.ts | 6 +++--- frontend/src/components/AdditionalModules.vue | 11 +++++------ .../editCalendar/EditAdditionalModules.vue | 7 +++---- 6 files changed, 27 insertions(+), 23 deletions(-) diff --git a/backend/service/addRoute.go b/backend/service/addRoute.go index 795d91d..ec62d89 100644 --- a/backend/service/addRoute.go +++ b/backend/service/addRoute.go @@ -5,13 +5,13 @@ import ( "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/apis" "github.com/pocketbase/pocketbase/core" + "htwkalender/model" "htwkalender/service/events" "htwkalender/service/fetch" "htwkalender/service/ical" "htwkalender/service/room" "io" "net/http" - "net/url" ) func AddRoutes(app *pocketbase.PocketBase) { @@ -191,12 +191,17 @@ func AddRoutes(app *pocketbase.PocketBase) { app.OnBeforeServe().Add(func(e *core.ServeEvent) error { _, err := e.Router.AddRoute(echo.Route{ - Method: http.MethodGet, + Method: http.MethodPost, Path: "/api/module", Handler: func(c echo.Context) error { - name := c.Request().Header.Get("Name") - name, err := url.QueryUnescape(name) - module, err := events.GetModuleByName(app, name) + + var requestModule model.Module + + if err := c.Bind(&requestModule); err != nil { + return apis.NewBadRequestError("Failed to read request body", err) + } + + module, err := events.GetModuleByName(app, requestModule) if err != nil { return c.JSON(400, err) @@ -271,6 +276,7 @@ func AddRoutes(app *pocketbase.PocketBase) { }, Middlewares: []echo.MiddlewareFunc{ apis.ActivityLogger(app), + apis.RequireAdminAuth(), }, }) if err != nil { diff --git a/backend/service/db/dbEvents.go b/backend/service/db/dbEvents.go index ee6f1d5..5358051 100644 --- a/backend/service/db/dbEvents.go +++ b/backend/service/db/dbEvents.go @@ -190,10 +190,10 @@ func DeleteAllEvents(app *pocketbase.PocketBase) error { return nil } -func FindAllEventsByModule(app *pocketbase.PocketBase, moduleName string) (model.Events, error) { +func FindAllEventsByModule(app *pocketbase.PocketBase, module model.Module) (model.Events, error) { var events model.Events - err := app.Dao().DB().Select("*").From("events").Where(dbx.NewExp("Name = {:moduleName}", dbx.Params{"moduleName": moduleName})).All(&events) + err := app.Dao().DB().Select("*").From("events").Where(dbx.NewExp("Name = {:moduleName} AND course = {:course}", dbx.Params{"moduleName": module.Name, "course": module.Course})).All(&events) if err != nil { print("Error while getting events from database: ", err) return nil, err diff --git a/backend/service/events/eventService.go b/backend/service/events/eventService.go index e114bff..4b646da 100644 --- a/backend/service/events/eventService.go +++ b/backend/service/events/eventService.go @@ -46,15 +46,15 @@ func GetAllModulesDistinct(app *pocketbase.PocketBase, c echo.Context) error { // If the module does not exist, an error is returned // If the module exists, the module is returned // Module is a struct that exists in database as events -func GetModuleByName(app *pocketbase.PocketBase, name string) (model.Module, error) { - events, err := db.FindAllEventsByModule(app, name) +func GetModuleByName(app *pocketbase.PocketBase, module model.Module) (model.Module, error) { + events, err := db.FindAllEventsByModule(app, module) if err != nil || len(events) == 0 { return model.Module{}, err } else { return model.Module{ UUID: events[0].UUID, - Name: name, + Name: events[0].Name, Events: events, Prof: events[0].Prof, Course: events[0].Course, diff --git a/frontend/src/api/fetchModule.ts b/frontend/src/api/fetchModule.ts index a6b2d86..e6a7f1c 100644 --- a/frontend/src/api/fetchModule.ts +++ b/frontend/src/api/fetchModule.ts @@ -1,12 +1,12 @@ import { Module } from "../model/module"; -export async function fetchModule(name: string): Promise { +export async function fetchModule(module: Module): Promise { const request = new Request("/api/module", { - method: "GET", + method: "POST", headers: { "Content-Type": "application/json", - Name: encodeURI(name), }, + body: JSON.stringify(module), }); return await fetch(request) diff --git a/frontend/src/components/AdditionalModules.vue b/frontend/src/components/AdditionalModules.vue index c989cb1..868fdf4 100644 --- a/frontend/src/components/AdditionalModules.vue +++ b/frontend/src/components/AdditionalModules.vue @@ -38,10 +38,9 @@ const ModuleInformation = defineAsyncComponent( () => import("./ModuleInformation.vue"), ); -async function showInfo(moduleName: string) { - const module: Ref = ref(new Module("", "", "", "", "", "", [])); - await fetchModule(moduleName).then((data) => { - module.value = data; +async function showInfo(module: Module) { + await fetchModule(module).then((data) => { + module = data; }); dialog.open(ModuleInformation, { props: { @@ -66,7 +65,7 @@ const selectAll = ref(false); const onSelectAllChange = (event: MultiSelectAllChangeEvent) => { selectedModules.value = event.checked - ? modules.value.map((module) => module) + ? modules.value.map((module: Module) => module) : []; selectAll.value = event.checked; }; @@ -112,7 +111,7 @@ function selectChange() { rounded outlined aria-label="Information" - @click.stop="showInfo(slotProps.option.name)" + @click.stop="showInfo(slotProps.option)" > diff --git a/frontend/src/components/editCalendar/EditAdditionalModules.vue b/frontend/src/components/editCalendar/EditAdditionalModules.vue index b19f63e..5b07d39 100644 --- a/frontend/src/components/editCalendar/EditAdditionalModules.vue +++ b/frontend/src/components/editCalendar/EditAdditionalModules.vue @@ -36,9 +36,8 @@ const ModuleInformation = defineAsyncComponent( () => import("../ModuleInformation.vue"), ); -async function showInfo(moduleName: string) { - const module: Ref = ref(new Module("", "", "", "", "", "", [])); - await fetchModule(moduleName).then((data) => { +async function showInfo(module: Module) { + await fetchModule(module).then((data) => { module.value = data; }); dialog.open(ModuleInformation, { @@ -110,7 +109,7 @@ function selectChange() { rounded outlined aria-label="Information" - @click.stop="showInfo(slotProps.option.name)" + @click.stop="showInfo(slotProps.option)" > From 7228d17d8475e52cdf4d161f69ae7650fb5fa10e Mon Sep 17 00:00:00 2001 From: masterelmar <18119527+masterElmar@users.noreply.github.com> Date: Sat, 28 Oct 2023 11:10:06 +0200 Subject: [PATCH 3/6] feat:#31 updated database start end to date --- .../migrations/1698444986_updated_events.go | 114 +++++ .../1698445123_collections_snapshot.go | 417 ++++++++++++++++++ backend/model/eventModel.go | 27 +- backend/service/date/dateFormat.go | 3 +- .../service/fetch/fetchSeminarEventService.go | 34 +- .../fetch/fetchSeminarEventService_test.go | 95 ++++ backend/service/ical/icalFileGeneration.go | 10 +- 7 files changed, 667 insertions(+), 33 deletions(-) create mode 100644 backend/migrations/1698444986_updated_events.go create mode 100644 backend/migrations/1698445123_collections_snapshot.go diff --git a/backend/migrations/1698444986_updated_events.go b/backend/migrations/1698444986_updated_events.go new file mode 100644 index 0000000..f0d23e3 --- /dev/null +++ b/backend/migrations/1698444986_updated_events.go @@ -0,0 +1,114 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/daos" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models/schema" +) + +func init() { + m.Register(func(db dbx.Builder) error { + dao := daos.New(db) + + collection, err := dao.FindCollectionByNameOrId("7her4515qsmrxe8") + if err != nil { + return err + } + + // remove + collection.Schema.RemoveField("7vsr9h6p") + + // remove + collection.Schema.RemoveField("wwpokofe") + + // add + new_start := &schema.SchemaField{} + json.Unmarshal([]byte(`{ + "system": false, + "id": "tvxitgwc", + "name": "start", + "type": "date", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": "", + "max": "" + } + }`), new_start) + collection.Schema.AddField(new_start) + + // add + new_end := &schema.SchemaField{} + json.Unmarshal([]byte(`{ + "system": false, + "id": "trbmsfcz", + "name": "end", + "type": "date", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": "", + "max": "" + } + }`), new_end) + collection.Schema.AddField(new_end) + + return dao.SaveCollection(collection) + }, func(db dbx.Builder) error { + dao := daos.New(db) + + collection, err := dao.FindCollectionByNameOrId("7her4515qsmrxe8") + if err != nil { + return err + } + + // add + del_Start := &schema.SchemaField{} + json.Unmarshal([]byte(`{ + "system": false, + "id": "7vsr9h6p", + "name": "Start", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }`), del_Start) + collection.Schema.AddField(del_Start) + + // add + del_End := &schema.SchemaField{} + json.Unmarshal([]byte(`{ + "system": false, + "id": "wwpokofe", + "name": "End", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }`), del_End) + collection.Schema.AddField(del_End) + + // remove + collection.Schema.RemoveField("tvxitgwc") + + // remove + collection.Schema.RemoveField("trbmsfcz") + + return dao.SaveCollection(collection) + }) +} diff --git a/backend/migrations/1698445123_collections_snapshot.go b/backend/migrations/1698445123_collections_snapshot.go new file mode 100644 index 0000000..2e2d92d --- /dev/null +++ b/backend/migrations/1698445123_collections_snapshot.go @@ -0,0 +1,417 @@ +package migrations + +import ( + "encoding/json" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/daos" + m "github.com/pocketbase/pocketbase/migrations" + "github.com/pocketbase/pocketbase/models" +) + +func init() { + m.Register(func(db dbx.Builder) error { + jsonData := `[ + { + "id": "cfq9mqlmd97v8z5", + "created": "2023-09-19 17:31:15.957Z", + "updated": "2023-10-27 22:15:09.073Z", + "name": "groups", + "type": "base", + "system": false, + "schema": [ + { + "system": false, + "id": "85msl21p", + "name": "university", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "2sii4dtp", + "name": "shortcut", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "uiwgo28f", + "name": "groupId", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "y0l1lrzs", + "name": "course", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "kr62mhbz", + "name": "faculty", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "ya6znpez", + "name": "facultyId", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + } + ], + "indexes": [ + "CREATE UNIQUE INDEX ` + "`" + `idx_rcaN2Oq` + "`" + ` ON ` + "`" + `groups` + "`" + ` (` + "`" + `course` + "`" + `)" + ], + "listRule": null, + "viewRule": null, + "createRule": null, + "updateRule": null, + "deleteRule": null, + "options": {} + }, + { + "id": "d65h4wh7zk13gxp", + "created": "2023-09-19 17:31:15.957Z", + "updated": "2023-10-27 22:15:09.073Z", + "name": "feeds", + "type": "base", + "system": false, + "schema": [ + { + "system": false, + "id": "cowxjfmc", + "name": "modules", + "type": "json", + "required": true, + "presentable": false, + "unique": false, + "options": {} + } + ], + "indexes": [], + "listRule": null, + "viewRule": "", + "createRule": null, + "updateRule": "", + "deleteRule": null, + "options": {} + }, + { + "id": "7her4515qsmrxe8", + "created": "2023-09-19 17:31:15.958Z", + "updated": "2023-10-27 22:16:26.924Z", + "name": "events", + "type": "base", + "system": false, + "schema": [ + { + "system": false, + "id": "m8ne8e3m", + "name": "Day", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "xnsxqp7j", + "name": "Week", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "aeuskrjo", + "name": "Name", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "klrzqyw0", + "name": "EventType", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "5zltexoy", + "name": "Prof", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "gy3nvfmx", + "name": "Rooms", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "hn7b8dfy", + "name": "Notes", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "axskpwm8", + "name": "BookedAt", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "vyyefxp7", + "name": "course", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "vlbpm9fz", + "name": "semester", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "0kahthzr", + "name": "uuid", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "tvxitgwc", + "name": "start", + "type": "date", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": "", + "max": "" + } + }, + { + "system": false, + "id": "trbmsfcz", + "name": "end", + "type": "date", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": "", + "max": "" + } + } + ], + "indexes": [ + "CREATE UNIQUE INDEX ` + "`" + `idx_orp1NWL` + "`" + ` ON ` + "`" + `events` + "`" + ` (\n ` + "`" + `Day` + "`" + `,\n ` + "`" + `Week` + "`" + `,\n ` + "`" + `Start` + "`" + `,\n ` + "`" + `End` + "`" + `,\n ` + "`" + `Name` + "`" + `,\n ` + "`" + `course` + "`" + `,\n ` + "`" + `Prof` + "`" + `,\n ` + "`" + `Rooms` + "`" + `,\n ` + "`" + `EventType` + "`" + `\n)" + ], + "listRule": null, + "viewRule": null, + "createRule": null, + "updateRule": null, + "deleteRule": null, + "options": {} + }, + { + "id": "_pb_users_auth_", + "created": "2023-10-27 22:15:08.738Z", + "updated": "2023-10-27 22:15:09.074Z", + "name": "users", + "type": "auth", + "system": false, + "schema": [ + { + "system": false, + "id": "users_name", + "name": "name", + "type": "text", + "required": false, + "presentable": false, + "unique": false, + "options": { + "min": null, + "max": null, + "pattern": "" + } + }, + { + "system": false, + "id": "users_avatar", + "name": "avatar", + "type": "file", + "required": false, + "presentable": false, + "unique": false, + "options": { + "maxSelect": 1, + "maxSize": 5242880, + "mimeTypes": [ + "image/jpeg", + "image/png", + "image/svg+xml", + "image/gif", + "image/webp" + ], + "thumbs": null, + "protected": false + } + } + ], + "indexes": [], + "listRule": "id = @request.auth.id", + "viewRule": "id = @request.auth.id", + "createRule": "", + "updateRule": "id = @request.auth.id", + "deleteRule": "id = @request.auth.id", + "options": { + "allowEmailAuth": true, + "allowOAuth2Auth": true, + "allowUsernameAuth": true, + "exceptEmailDomains": null, + "manageRule": null, + "minPasswordLength": 8, + "onlyEmailDomains": null, + "requireEmail": false + } + } + ]` + + collections := []*models.Collection{} + if err := json.Unmarshal([]byte(jsonData), &collections); err != nil { + return err + } + + return daos.New(db).ImportCollections(collections, true, nil) + }, func(db dbx.Builder) error { + return nil + }) +} diff --git a/backend/model/eventModel.go b/backend/model/eventModel.go index 5daf446..b25ccbf 100644 --- a/backend/model/eventModel.go +++ b/backend/model/eventModel.go @@ -3,6 +3,7 @@ package model import ( "github.com/pocketbase/pocketbase/models" "slices" + "time" ) type Events []Event @@ -12,19 +13,19 @@ func (m Events) Contains(event Event) bool { } type Event struct { - UUID string `db:"uuid" json:"uuid"` - Day string `db:"Day" json:"day"` - Week string `db:"Week" json:"week"` - Start string `db:"Start" json:"start"` - End string `db:"End" json:"end"` - Name string `db:"Name" json:"name"` - EventType string `db:"EventType" json:"eventType"` - Prof string `db:"Prof" json:"prof"` - Rooms string `db:"Rooms" json:"rooms"` - Notes string `db:"Notes" json:"notes"` - BookedAt string `db:"BookedAt" json:"bookedAt"` - Course string `db:"course" json:"course"` - Semester string `db:"semester" json:"semester"` + UUID string `db:"uuid" json:"uuid"` + Day string `db:"Day" json:"day"` + Week string `db:"Week" json:"week"` + Start time.Time `db:"start" json:"start"` + End time.Time `db:"end" json:"end"` + Name string `db:"Name" json:"name"` + EventType string `db:"EventType" json:"eventType"` + Prof string `db:"Prof" json:"prof"` + Rooms string `db:"Rooms" json:"rooms"` + Notes string `db:"Notes" json:"notes"` + BookedAt string `db:"BookedAt" json:"bookedAt"` + Course string `db:"course" json:"course"` + Semester string `db:"semester" json:"semester"` models.BaseModel } diff --git a/backend/service/date/dateFormat.go b/backend/service/date/dateFormat.go index 41d9a82..0fa9ee8 100644 --- a/backend/service/date/dateFormat.go +++ b/backend/service/date/dateFormat.go @@ -4,7 +4,8 @@ import "time" func GetDateFromWeekNumber(year int, weekNumber int, dayName string) (time.Time, error) { // Create a time.Date for the first day of the year - firstDayOfYear := time.Date(year, time.January, 1, 0, 0, 0, 0, time.UTC) + europeTime, _ := time.LoadLocation("Europe/Berlin") + firstDayOfYear := time.Date(year, time.January, 1, 0, 0, 0, 0, europeTime) // Calculate the number of days to add to reach the desired week daysToAdd := time.Duration((weekNumber-1)*7) * 24 * time.Hour diff --git a/backend/service/fetch/fetchSeminarEventService.go b/backend/service/fetch/fetchSeminarEventService.go index 183b1aa..0040df7 100644 --- a/backend/service/fetch/fetchSeminarEventService.go +++ b/backend/service/fetch/fetchSeminarEventService.go @@ -129,22 +129,21 @@ func convertWeeksToDates(events []model.Event, semester string, year string) []m start := addTimeToDate(eventDay, event.Start) end := addTimeToDate(eventDay, event.End) newEvent := event - newEvent.Start = start.String() - newEvent.End = end.String() + newEvent.Start = start + newEvent.End = end newEvent.Semester = semester newEvents = append(newEvents, newEvent) } return newEvents } -func addTimeToDate(date time.Time, timeString string) time.Time { - europeTime, _ := time.LoadLocation("Europe/Berlin") - //convert time functions to time - timeParts := strings.Split(timeString, ":") - hour, _ := strconv.Atoi(timeParts[0]) - minute, _ := strconv.Atoi(timeParts[1]) - - return time.Date(date.Year(), date.Month(), date.Day(), hour, minute, 0, 0, europeTime) +// addTimeToDate adds each value onto date +func addTimeToDate(date time.Time, addDate time.Time) time.Time { + newDate := date + newDate = newDate.Add(time.Second * time.Duration(addDate.Second())) + newDate = newDate.Add(time.Hour * time.Duration(addDate.Hour())) + newDate = newDate.Add(time.Minute * time.Duration(addDate.Minute())) + return newDate } func extractSemesterAndYear(semesterString string) (string, string) { @@ -191,8 +190,8 @@ func toEvents(tables [][]*html.Node, days []string) []model.Event { events = append(events, model.Event{ Day: days[table], Week: getTextContent(tableData[0]), - Start: getTextContent(tableData[1]), - End: getTextContent(tableData[2]), + Start: createTimeFromHourAndMinuteString(getTextContent(tableData[1])), + End: createTimeFromHourAndMinuteString(getTextContent(tableData[2])), Name: getTextContent(tableData[3]), EventType: getTextContent(tableData[4]), Prof: getTextContent(tableData[5]), @@ -208,6 +207,17 @@ func toEvents(tables [][]*html.Node, days []string) []model.Event { return events } +// createEventFromTableData should create an event from the table data +// tableTime represents Hour and Minute like HH:MM +// tableDate returns a Time +func createTimeFromHourAndMinuteString(tableTime string) time.Time { + europeTime, _ := time.LoadLocation("Europe/Berlin") + timeParts := strings.Split(tableTime, ":") + hour, _ := strconv.Atoi(timeParts[0]) + minute, _ := strconv.Atoi(timeParts[1]) + return time.Date(0, 0, 0, hour, minute, 0, 0, europeTime) +} + func splitEventsByWeek(events []model.Event) []model.Event { var newEvents []model.Event diff --git a/backend/service/fetch/fetchSeminarEventService_test.go b/backend/service/fetch/fetchSeminarEventService_test.go index 111f0b8..f8161d8 100644 --- a/backend/service/fetch/fetchSeminarEventService_test.go +++ b/backend/service/fetch/fetchSeminarEventService_test.go @@ -4,6 +4,7 @@ import ( "htwkalender/model" "reflect" "testing" + "time" ) func Test_extractSemesterAndYear(t *testing.T) { @@ -172,3 +173,97 @@ func Test_generateUUIDs(t *testing.T) { }) } } + +func Test_createTimeFromHourAndMinuteString(t *testing.T) { + europeTime, _ := time.LoadLocation("Europe/Berlin") + type args struct { + tableTime string + } + tests := []struct { + name string + args args + want time.Time + }{ + { + name: "Test 1", + args: args{ + tableTime: "08:00", + }, + want: time.Date(0, 0, 0, 8, 0, 0, 0, europeTime), + }, + { + name: "Test 2", + args: args{ + tableTime: "08:15", + }, + want: time.Date(0, 0, 0, 8, 15, 0, 0, europeTime), + }, + { + name: "Test 3", + args: args{ + tableTime: "08:30", + }, + want: time.Date(0, 0, 0, 8, 30, 0, 0, europeTime), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := createTimeFromHourAndMinuteString(tt.args.tableTime); !reflect.DeepEqual(got, tt.want) { + t.Errorf("createTimeFromHourAndMinuteString() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_addTimeToDate(t *testing.T) { + europeTime, _ := time.LoadLocation("Europe/Berlin") + type args struct { + date time.Time + time time.Time + } + tests := []struct { + name string + args args + want time.Time + }{ + { + name: "Test 1", + args: args{ + date: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), + time: time.Date(0, 0, 0, 8, 0, 0, 0, time.UTC), + }, + want: time.Date(2021, 1, 1, 8, 0, 0, 0, time.UTC), + }, + { + name: "Test 2", + args: args{ + date: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC), + time: time.Date(0, 0, 0, 8, 15, 0, 0, time.UTC), + }, + want: time.Date(2021, 1, 1, 8, 15, 0, 0, time.UTC), + }, + { + name: "Test 3", + args: args{ + date: time.Date(2002, 12, 31, 17, 0, 0, 0, time.UTC), + time: time.Date(0, 0, 0, 8, 0, 0, 0, time.UTC), + }, + want: time.Date(2003, 1, 1, 1, 0, 0, 0, time.UTC), + }, + { + name: "Test 4", + args: args{ + date: time.Date(2023, 10, 29, 0, 0, 0, 0, europeTime), + time: time.Date(0, 0, 0, 10, 0, 0, 0, time.UTC), + }, + want: time.Date(2023, 10, 29, 9, 0, 0, 0, europeTime), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := addTimeToDate(tt.args.date, tt.args.time); !reflect.DeepEqual(got, tt.want) { + t.Errorf("addTimeToDate() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/backend/service/ical/icalFileGeneration.go b/backend/service/ical/icalFileGeneration.go index 2b77c3a..a0efba4 100644 --- a/backend/service/ical/icalFileGeneration.go +++ b/backend/service/ical/icalFileGeneration.go @@ -4,10 +4,9 @@ import ( "github.com/jordic/goics" "htwkalender/model" "htwkalender/service/functions" - "time" ) -// local type for EmitICal function +// IcalModel local type for EmitICal function type IcalModel struct { Events model.Events Mapping []model.FeedCollection @@ -15,7 +14,6 @@ type IcalModel struct { // EmitICal implements the interface for goics func (icalModel IcalModel) EmitICal() goics.Componenter { - layout := "2006-01-02 15:04:05 -0700 MST" c := goics.NewComponent() c.SetType("VCALENDAR") c.AddProperty("VERSION", "2.0") @@ -27,11 +25,9 @@ func (icalModel IcalModel) EmitICal() goics.Componenter { for _, event := range icalModel.Events { s := goics.NewComponent() s.SetType("VEVENT") - timeEnd, _ := time.Parse(layout, event.End) - timeStart, _ := time.Parse(layout, event.Start) - k, v := goics.FormatDateTime("DTEND;TZID=Europe/Berlin", timeEnd) + k, v := goics.FormatDateTime("DTEND;TZID=Europe/Berlin", event.End) s.AddProperty(k, v) - k, v = goics.FormatDateTime("DTSTART;TZID=Europe/Berlin", timeStart) + k, v = goics.FormatDateTime("DTSTART;TZID=Europe/Berlin", event.Start) s.AddProperty(k, v) s.AddProperty("SUMMARY", replaceNameIfUserDefined(event.Name, icalModel.Mapping)) s.AddProperty("DESCRIPTION", generateDescription(event)) From 4aed6b58ee89c763bec1a08576685315a5334283 Mon Sep 17 00:00:00 2001 From: masterelmar <18119527+masterElmar@users.noreply.github.com> Date: Sat, 28 Oct 2023 14:48:25 +0200 Subject: [PATCH 4/6] fix:#31 switch time format in functions and calendar --- backend/model/eventModel.go | 31 +++++++------- backend/model/eventModel_test.go | 30 +++++++------- backend/service/addRoute.go | 12 +++--- .../service/fetch/fetchSeminarEventService.go | 40 +++++++++---------- .../fetch/fetchSeminarEventService_test.go | 2 +- backend/service/ical/icalFileGeneration.go | 9 +++-- 6 files changed, 66 insertions(+), 58 deletions(-) diff --git a/backend/model/eventModel.go b/backend/model/eventModel.go index b25ccbf..ae2314e 100644 --- a/backend/model/eventModel.go +++ b/backend/model/eventModel.go @@ -1,9 +1,10 @@ package model import ( - "github.com/pocketbase/pocketbase/models" "slices" - "time" + + "github.com/pocketbase/pocketbase/models" + "github.com/pocketbase/pocketbase/tools/types" ) type Events []Event @@ -13,19 +14,19 @@ func (m Events) Contains(event Event) bool { } type Event struct { - UUID string `db:"uuid" json:"uuid"` - Day string `db:"Day" json:"day"` - Week string `db:"Week" json:"week"` - Start time.Time `db:"start" json:"start"` - End time.Time `db:"end" json:"end"` - Name string `db:"Name" json:"name"` - EventType string `db:"EventType" json:"eventType"` - Prof string `db:"Prof" json:"prof"` - Rooms string `db:"Rooms" json:"rooms"` - Notes string `db:"Notes" json:"notes"` - BookedAt string `db:"BookedAt" json:"bookedAt"` - Course string `db:"course" json:"course"` - Semester string `db:"semester" json:"semester"` + UUID string `db:"uuid" json:"uuid"` + Day string `db:"Day" json:"day"` + Week string `db:"Week" json:"week"` + Start types.DateTime `db:"start" json:"start"` + End types.DateTime `db:"end" json:"end"` + Name string `db:"Name" json:"name"` + EventType string `db:"EventType" json:"eventType"` + Prof string `db:"Prof" json:"prof"` + Rooms string `db:"Rooms" json:"rooms"` + Notes string `db:"Notes" json:"notes"` + BookedAt string `db:"BookedAt" json:"bookedAt"` + Course string `db:"course" json:"course"` + Semester string `db:"semester" json:"semester"` models.BaseModel } diff --git a/backend/model/eventModel_test.go b/backend/model/eventModel_test.go index d73c109..4462f4e 100644 --- a/backend/model/eventModel_test.go +++ b/backend/model/eventModel_test.go @@ -1,8 +1,10 @@ package model import ( - "github.com/pocketbase/pocketbase/models" "testing" + + "github.com/pocketbase/pocketbase/models" + "github.com/pocketbase/pocketbase/tools/types" ) func TestEvents_Contains(t *testing.T) { @@ -23,20 +25,20 @@ func TestEvents_Contains(t *testing.T) { }, { name: "one event", - m: Events{{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}}, - args: args{event: Event{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}}, + m: Events{{Day: "test", Week: "test", Start: types.NowDateTime(), End: types.NowDateTime(), Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}}, + args: args{event: Event{Day: "test", Week: "test", Start: types.NowDateTime(), End: types.NowDateTime(), Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}}, want: true, }, { name: "two events", - m: Events{{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, {Day: "test2", Week: "test2", Start: "test2", End: "test2", Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}}, - args: args{event: Event{Day: "test2", Week: "test2", Start: "test2", End: "test2", Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}}, + m: Events{{Day: "test", Week: "test", Start: types.NowDateTime(), End: types.NowDateTime(), Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, {Day: "test2", Week: "test2", Start: types.NowDateTime(), End: types.NowDateTime(), Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}}, + args: args{event: Event{Day: "test2", Week: "test2", Start: types.NowDateTime(), End: types.NowDateTime(), Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}}, want: true, }, { name: "two events with different values", - m: Events{{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test", UUID: "439ßu56rf8u9ijn4f4-2345345"}, {Day: "test2", Week: "test2", Start: "test2", End: "test2", Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2", UUID: "432a39ßu545349ijn4f4-23dsa45"}}, - args: args{event: Event{Day: "test3", Week: "test3", Start: "test3", End: "test3", Name: "test3", Course: "test3", Prof: "test3", Rooms: "test3", EventType: "test3", UUID: "934mf43r34f-g68h7655tg3"}}, + m: Events{{Day: "test", Week: "test", Start: types.NowDateTime(), End: types.NowDateTime(), Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test", UUID: "439ßu56rf8u9ijn4f4-2345345"}, {Day: "test2", Week: "test2", Start: types.NowDateTime(), End: types.NowDateTime(), Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2", UUID: "432a39ßu545349ijn4f4-23dsa45"}}, + args: args{event: Event{Day: "test3", Week: "test3", Start: types.NowDateTime(), End: types.NowDateTime(), Name: "test3", Course: "test3", Prof: "test3", Rooms: "test3", EventType: "test3", UUID: "934mf43r34f-g68h7655tg3"}}, want: false, }, } @@ -54,8 +56,8 @@ func TestEvent_Equals(t *testing.T) { UUID string Day string Week string - Start string - End string + Start types.DateTime + End types.DateTime Name string EventType string Prof string @@ -83,20 +85,20 @@ func TestEvent_Equals(t *testing.T) { }, { name: "one empty one not", - fields: fields{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, + fields: fields{Day: "test", Week: "test", Start: types.NowDateTime(), End: types.NowDateTime(), Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, args: args{event: Event{}}, want: false, }, { name: "one event", - fields: fields{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, - args: args{event: Event{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}}, + fields: fields{Day: "test", Week: "test", Start: types.NowDateTime(), End: types.NowDateTime(), Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, + args: args{event: Event{Day: "test", Week: "test", Start: types.NowDateTime(), End: types.NowDateTime(), Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}}, want: true, }, { name: "two events", - fields: fields{Day: "test", Week: "test", Start: "test", End: "test", Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, - args: args{event: Event{Day: "test2", Week: "test2", Start: "test2", End: "test2", Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}}, + fields: fields{Day: "test", Week: "test", Start: types.NowDateTime(), End: types.NowDateTime(), Name: "test", Course: "test", Prof: "test", Rooms: "test", EventType: "test"}, + args: args{event: Event{Day: "test2", Week: "test2", Start: types.NowDateTime(), End: types.NowDateTime(), Name: "test2", Course: "test2", Prof: "test2", Rooms: "test2", EventType: "test2"}}, want: false, }, } diff --git a/backend/service/addRoute.go b/backend/service/addRoute.go index ec62d89..7d00483 100644 --- a/backend/service/addRoute.go +++ b/backend/service/addRoute.go @@ -1,10 +1,6 @@ package service import ( - "github.com/labstack/echo/v5" - "github.com/pocketbase/pocketbase" - "github.com/pocketbase/pocketbase/apis" - "github.com/pocketbase/pocketbase/core" "htwkalender/model" "htwkalender/service/events" "htwkalender/service/fetch" @@ -12,6 +8,11 @@ import ( "htwkalender/service/room" "io" "net/http" + + "github.com/labstack/echo/v5" + "github.com/pocketbase/pocketbase" + "github.com/pocketbase/pocketbase/apis" + "github.com/pocketbase/pocketbase/core" ) func AddRoutes(app *pocketbase.PocketBase) { @@ -42,7 +43,7 @@ func AddRoutes(app *pocketbase.PocketBase) { }, Middlewares: []echo.MiddlewareFunc{ apis.ActivityLogger(app), - apis.RequireAdminAuth(), + //apis.RequireAdminAuth(), }, }) if err != nil { @@ -253,6 +254,7 @@ func AddRoutes(app *pocketbase.PocketBase) { }, Middlewares: []echo.MiddlewareFunc{ apis.ActivityLogger(app), + apis.RequireAdminAuth(), }, }) if err != nil { diff --git a/backend/service/fetch/fetchSeminarEventService.go b/backend/service/fetch/fetchSeminarEventService.go index 0040df7..0c8e677 100644 --- a/backend/service/fetch/fetchSeminarEventService.go +++ b/backend/service/fetch/fetchSeminarEventService.go @@ -2,11 +2,6 @@ package fetch import ( "fmt" - "github.com/google/uuid" - "github.com/labstack/echo/v5" - "github.com/pocketbase/pocketbase" - "github.com/pocketbase/pocketbase/apis" - "golang.org/x/net/html" "htwkalender/model" "htwkalender/service/date" "htwkalender/service/db" @@ -16,6 +11,13 @@ import ( "strconv" "strings" "time" + + "github.com/google/uuid" + "github.com/labstack/echo/v5" + "github.com/pocketbase/pocketbase" + "github.com/pocketbase/pocketbase/apis" + "github.com/pocketbase/pocketbase/tools/types" + "golang.org/x/net/html" ) func GetSeminarEvents(c echo.Context, app *pocketbase.PocketBase) error { @@ -124,26 +126,23 @@ func convertWeeksToDates(events []model.Event, semester string, year string) []m // for each event we need to calculate the start and end date based on the week and the year for _, event := range events { + eventWeek, _ := strconv.Atoi(event.Week) eventDay, _ := date.GetDateFromWeekNumber(eventYear, eventWeek, event.Day) - start := addTimeToDate(eventDay, event.Start) - end := addTimeToDate(eventDay, event.End) + start := replaceTimeForDate(eventDay, event.Start.Time()) + end := replaceTimeForDate(eventDay, event.End.Time()) newEvent := event - newEvent.Start = start - newEvent.End = end + newEvent.Start, _ = types.ParseDateTime(start.In(time.UTC)) + newEvent.End, _ = types.ParseDateTime(end.In(time.UTC)) newEvent.Semester = semester newEvents = append(newEvents, newEvent) } return newEvents } -// addTimeToDate adds each value onto date -func addTimeToDate(date time.Time, addDate time.Time) time.Time { - newDate := date - newDate = newDate.Add(time.Second * time.Duration(addDate.Second())) - newDate = newDate.Add(time.Hour * time.Duration(addDate.Hour())) - newDate = newDate.Add(time.Minute * time.Duration(addDate.Minute())) - return newDate +// replaceTimeForDate replaces hour, minute, second, nsec for the selected date +func replaceTimeForDate(date time.Time, replacementTime time.Time) time.Time { + return time.Date(date.Year(), date.Month(), date.Day(), replacementTime.Hour(), replacementTime.Minute(), replacementTime.Second(), replacementTime.Nanosecond(), date.Location()) } func extractSemesterAndYear(semesterString string) (string, string) { @@ -187,11 +186,13 @@ func toEvents(tables [][]*html.Node, days []string) []model.Event { tableData := findTableData(tables[table][row]) if len(tableData) > 0 { + start, _ := types.ParseDateTime(createTimeFromHourAndMinuteString(getTextContent(tableData[1]))) + end, _ := types.ParseDateTime(createTimeFromHourAndMinuteString(getTextContent(tableData[2]))) events = append(events, model.Event{ Day: days[table], Week: getTextContent(tableData[0]), - Start: createTimeFromHourAndMinuteString(getTextContent(tableData[1])), - End: createTimeFromHourAndMinuteString(getTextContent(tableData[2])), + Start: start, + End: end, Name: getTextContent(tableData[3]), EventType: getTextContent(tableData[4]), Prof: getTextContent(tableData[5]), @@ -211,11 +212,10 @@ func toEvents(tables [][]*html.Node, days []string) []model.Event { // tableTime represents Hour and Minute like HH:MM // tableDate returns a Time func createTimeFromHourAndMinuteString(tableTime string) time.Time { - europeTime, _ := time.LoadLocation("Europe/Berlin") timeParts := strings.Split(tableTime, ":") hour, _ := strconv.Atoi(timeParts[0]) minute, _ := strconv.Atoi(timeParts[1]) - return time.Date(0, 0, 0, hour, minute, 0, 0, europeTime) + return time.Date(0, 0, 0, hour, minute, 0, 0, time.UTC) } func splitEventsByWeek(events []model.Event) []model.Event { diff --git a/backend/service/fetch/fetchSeminarEventService_test.go b/backend/service/fetch/fetchSeminarEventService_test.go index f8161d8..4974c03 100644 --- a/backend/service/fetch/fetchSeminarEventService_test.go +++ b/backend/service/fetch/fetchSeminarEventService_test.go @@ -261,7 +261,7 @@ func Test_addTimeToDate(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := addTimeToDate(tt.args.date, tt.args.time); !reflect.DeepEqual(got, tt.want) { + if got := replaceTimeForDate(tt.args.date, tt.args.time); !reflect.DeepEqual(got, tt.want) { t.Errorf("addTimeToDate() = %v, want %v", got, tt.want) } }) diff --git a/backend/service/ical/icalFileGeneration.go b/backend/service/ical/icalFileGeneration.go index a0efba4..9e9d59c 100644 --- a/backend/service/ical/icalFileGeneration.go +++ b/backend/service/ical/icalFileGeneration.go @@ -1,9 +1,11 @@ package ical import ( - "github.com/jordic/goics" "htwkalender/model" "htwkalender/service/functions" + "time" + + "github.com/jordic/goics" ) // IcalModel local type for EmitICal function @@ -14,6 +16,7 @@ type IcalModel struct { // EmitICal implements the interface for goics func (icalModel IcalModel) EmitICal() goics.Componenter { + europeTime, _ := time.LoadLocation("Europe/Berlin") c := goics.NewComponent() c.SetType("VCALENDAR") c.AddProperty("VERSION", "2.0") @@ -25,9 +28,9 @@ func (icalModel IcalModel) EmitICal() goics.Componenter { for _, event := range icalModel.Events { s := goics.NewComponent() s.SetType("VEVENT") - k, v := goics.FormatDateTime("DTEND;TZID=Europe/Berlin", event.End) + 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) + k, v = goics.FormatDateTime("DTSTART;TZID=Europe/Berlin", event.Start.Time().Local().In(europeTime)) s.AddProperty(k, v) s.AddProperty("SUMMARY", replaceNameIfUserDefined(event.Name, icalModel.Mapping)) s.AddProperty("DESCRIPTION", generateDescription(event)) From bed0466f9a22e18559ee4fc75da22a050aece3dd Mon Sep 17 00:00:00 2001 From: masterelmar <18119527+masterElmar@users.noreply.github.com> Date: Sat, 28 Oct 2023 15:25:56 +0200 Subject: [PATCH 5/6] fix:#32 readded security for delete all modules --- backend/service/addRoute.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/service/addRoute.go b/backend/service/addRoute.go index 7d00483..f2c0e0b 100644 --- a/backend/service/addRoute.go +++ b/backend/service/addRoute.go @@ -43,7 +43,7 @@ func AddRoutes(app *pocketbase.PocketBase) { }, Middlewares: []echo.MiddlewareFunc{ apis.ActivityLogger(app), - //apis.RequireAdminAuth(), + apis.RequireAdminAuth(), }, }) if err != nil { From 33ce55ae0972b95ac6a45991ae1a39eab063bf0f Mon Sep 17 00:00:00 2001 From: masterelmar <18119527+masterElmar@users.noreply.github.com> Date: Sat, 28 Oct 2023 15:32:13 +0200 Subject: [PATCH 6/6] test:#32 rewrite tests equal to function --- .../fetch/fetchSeminarEventService_test.go | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/backend/service/fetch/fetchSeminarEventService_test.go b/backend/service/fetch/fetchSeminarEventService_test.go index 4974c03..64aed6c 100644 --- a/backend/service/fetch/fetchSeminarEventService_test.go +++ b/backend/service/fetch/fetchSeminarEventService_test.go @@ -215,8 +215,7 @@ func Test_createTimeFromHourAndMinuteString(t *testing.T) { } } -func Test_addTimeToDate(t *testing.T) { - europeTime, _ := time.LoadLocation("Europe/Berlin") +func Test_replaceTimeInDate(t *testing.T) { type args struct { date time.Time time time.Time @@ -242,22 +241,6 @@ func Test_addTimeToDate(t *testing.T) { }, want: time.Date(2021, 1, 1, 8, 15, 0, 0, time.UTC), }, - { - name: "Test 3", - args: args{ - date: time.Date(2002, 12, 31, 17, 0, 0, 0, time.UTC), - time: time.Date(0, 0, 0, 8, 0, 0, 0, time.UTC), - }, - want: time.Date(2003, 1, 1, 1, 0, 0, 0, time.UTC), - }, - { - name: "Test 4", - args: args{ - date: time.Date(2023, 10, 29, 0, 0, 0, 0, europeTime), - time: time.Date(0, 0, 0, 10, 0, 0, 0, time.UTC), - }, - want: time.Date(2023, 10, 29, 9, 0, 0, 0, europeTime), - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {