From 1582154d5fa08fee19caa2b5b36fd873e2af811f Mon Sep 17 00:00:00 2001 From: Elmar Kresse Date: Mon, 22 Jan 2024 15:04:50 +0100 Subject: [PATCH] feat:#150 extracted functions rewrote error pipe for feed routes --- backend/service/addCalDavRoutes.go | 183 ++++++++++++++++++++++++++++ backend/service/addRoute.go | 111 ++++------------- backend/service/addSchedule.go | 16 +-- backend/service/ical/ical.go | 26 +--- backend/service/room/roomService.go | 37 +++--- 5 files changed, 234 insertions(+), 139 deletions(-) create mode 100644 backend/service/addCalDavRoutes.go diff --git a/backend/service/addCalDavRoutes.go b/backend/service/addCalDavRoutes.go new file mode 100644 index 0000000..04ca9af --- /dev/null +++ b/backend/service/addCalDavRoutes.go @@ -0,0 +1,183 @@ +package service + +import ( + "github.com/labstack/echo/v5" + "github.com/pocketbase/pocketbase" + "github.com/pocketbase/pocketbase/apis" + "github.com/pocketbase/pocketbase/core" + "htwkalender/service/db" + "htwkalender/service/ical" + "io" + "net/http" +) + +func addFeedRoutes(app *pocketbase.PocketBase) { + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + _, err := e.Router.AddRoute(echo.Route{ + Method: http.MethodPost, + Path: "/api/createFeed", + Handler: func(c echo.Context) error { + requestBody, _ := io.ReadAll(c.Request().Body) + result, err := ical.CreateIndividualFeed(requestBody, app) + if err != nil { + return c.JSON(http.StatusInternalServerError, "Failed to create individual feed") + } + return c.JSON(http.StatusOK, result) + }, + Middlewares: []echo.MiddlewareFunc{ + apis.ActivityLogger(app), + }, + }) + if err != nil { + return err + } + return nil + }) + + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + _, err := e.Router.AddRoute(echo.Route{ + Method: http.MethodGet, + Path: "/api/feed", + Handler: func(c echo.Context) error { + token := c.QueryParam("token") + result, err := ical.Feed(app, token) + if err != nil { + return c.JSON(http.StatusInternalServerError, "Failed to get feed") + } + var responseWriter = c.Response().Writer + responseWriter.Header().Set("Content-type", "text/calendar") + responseWriter.Header().Set("charset", "utf-8") + responseWriter.Header().Set("Content-Disposition", "inline") + responseWriter.Header().Set("filename", "calendar.ics") + + responseWriter.WriteHeader(http.StatusOK) + _, err = responseWriter.Write([]byte(result)) + if err != nil { + return c.JSON(http.StatusInternalServerError, "Failed to write feed") + } + c.Response().Writer = responseWriter + return nil + }, + Middlewares: []echo.MiddlewareFunc{ + apis.ActivityLogger(app), + }, + }) + if err != nil { + return err + } + return nil + }) + + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + _, err := e.Router.AddRoute(echo.Route{ + Method: http.MethodHead, + Path: "/api/feed", + Handler: func(c echo.Context) error { + return c.JSON(http.StatusOK, "") + }, + Middlewares: []echo.MiddlewareFunc{ + apis.ActivityLogger(app), + }, + }) + if err != nil { + return err + } + return nil + }) + + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + _, err := e.Router.AddRoute(echo.Route{ + Method: "PROPFIND", + Path: "/api/feed", + Handler: func(c echo.Context) error { + return c.JSON(http.StatusOK, "") + }, + Middlewares: []echo.MiddlewareFunc{ + apis.ActivityLogger(app), + }, + }) + if err != nil { + return err + } + return nil + }) + + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + _, err := e.Router.AddRoute(echo.Route{ + Method: http.MethodDelete, + Path: "/api/feed", + Handler: func(c echo.Context) error { + token := c.QueryParam("token") + err := db.DeleteFeed(app.Dao(), token) + if err != nil { + return c.JSON(http.StatusNotFound, err) + } else { + return c.JSON(http.StatusOK, "Feed deleted") + } + }, + Middlewares: []echo.MiddlewareFunc{ + apis.ActivityLogger(app), + }, + }) + if err != nil { + return err + } + return nil + }) + + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + _, err := e.Router.AddRoute(echo.Route{ + Method: http.MethodPut, + Path: "/api/feed", + Handler: func(c echo.Context) error { + token := c.QueryParam("token") + return c.JSON(http.StatusOK, "token: "+token) + }, + Middlewares: []echo.MiddlewareFunc{ + apis.ActivityLogger(app), + }, + }) + if err != nil { + return err + } + return nil + }) + + // Route for Thunderbird to get calendar server information + // Response is a 200 OK without additional content + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + _, err := e.Router.AddRoute(echo.Route{ + Method: "PROPFIND", + Path: "/", + Handler: func(c echo.Context) error { + return c.JSON(http.StatusOK, "") + }, + Middlewares: []echo.MiddlewareFunc{ + apis.ActivityLogger(app), + }, + }) + if err != nil { + return err + } + return nil + }) + + // Route for Thunderbird to get calendar server information + // Response is a 200 OK without additional content + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + _, err := e.Router.AddRoute(echo.Route{ + Method: "PROPFIND", + Path: "/.well-known/caldav", + Handler: func(c echo.Context) error { + return c.JSON(http.StatusOK, "") + }, + Middlewares: []echo.MiddlewareFunc{ + apis.ActivityLogger(app), + }, + }) + if err != nil { + return err + } + return nil + }) +} diff --git a/backend/service/addRoute.go b/backend/service/addRoute.go index 2e0f4b5..35ef5e7 100644 --- a/backend/service/addRoute.go +++ b/backend/service/addRoute.go @@ -1,14 +1,12 @@ package service import ( - "htwkalender/service/db" "htwkalender/service/events" "htwkalender/service/fetch/sport" v1 "htwkalender/service/fetch/v1" v2 "htwkalender/service/fetch/v2" "htwkalender/service/ical" "htwkalender/service/room" - "io" "log/slog" "net/http" @@ -72,8 +70,11 @@ func AddRoutes(app *pocketbase.PocketBase) { Path: "/api/fetch/sports", Handler: func(c echo.Context) error { - sportEvents := sport.FetchAndUpdateSportEvents(app) - return c.JSON(200, sportEvents) + sportEvents, err := sport.FetchAndUpdateSportEvents(app) + if err != nil { + return c.JSON(http.StatusInternalServerError, "Failed to fetch sport events") + } + return c.JSON(http.StatusOK, sportEvents) }, Middlewares: []echo.MiddlewareFunc{ apis.ActivityLogger(app), @@ -91,7 +92,11 @@ func AddRoutes(app *pocketbase.PocketBase) { Method: http.MethodDelete, Path: "/api/modules", Handler: func(c echo.Context) error { - return events.DeleteAllEvents(app) + err := events.DeleteAllEvents(app) + if err != nil { + return c.JSON(http.StatusInternalServerError, "Failed to delete events") + } + return c.JSON(http.StatusOK, "Events deleted") }, Middlewares: []echo.MiddlewareFunc{ apis.ActivityLogger(app), @@ -109,7 +114,11 @@ func AddRoutes(app *pocketbase.PocketBase) { Method: http.MethodGet, Path: "/api/rooms", Handler: func(c echo.Context) error { - return room.GetRooms(c, app) + rooms, err := room.GetRooms(app) + if err != nil { + return c.JSON(http.StatusInternalServerError, "Failed to get rooms") + } + return c.JSON(http.StatusOK, rooms) }, Middlewares: []echo.MiddlewareFunc{ apis.ActivityLogger(app), @@ -129,7 +138,11 @@ func AddRoutes(app *pocketbase.PocketBase) { Handler: func(c echo.Context) error { roomParam := c.QueryParam("room") date := c.QueryParam("date") - return room.GetRoomScheduleForDay(c, app, roomParam, date) + roomSchedule, err := room.GetRoomScheduleForDay(app, roomParam, date) + if err != nil { + return c.JSON(http.StatusInternalServerError, "Failed to get room schedule for day") + } + return c.JSON(http.StatusOK, roomSchedule) }, Middlewares: []echo.MiddlewareFunc{ apis.ActivityLogger(app), @@ -150,30 +163,11 @@ func AddRoutes(app *pocketbase.PocketBase) { roomParam := c.QueryParam("room") to := c.QueryParam("to") from := c.QueryParam("from") - return room.GetRoomSchedule(c, app, roomParam, from, to) - }, - Middlewares: []echo.MiddlewareFunc{ - apis.ActivityLogger(app), - }, - }) - if err != nil { - return err - } - return nil - }) - - app.OnBeforeServe().Add(func(e *core.ServeEvent) error { - _, err := e.Router.AddRoute(echo.Route{ - Method: http.MethodPost, - Path: "/api/createFeed", - Handler: func(c echo.Context) error { - requestBody, _ := io.ReadAll(c.Request().Body) - result, err := ical.CreateIndividualFeed(requestBody, app) + roomSchedule, err := room.GetRoomSchedule(app, roomParam, from, to) if err != nil { - return c.JSON(http.StatusInternalServerError, err) + return c.JSON(http.StatusInternalServerError, "Failed to get room schedule") } - return c.JSON(http.StatusOK, result) - + return c.JSON(http.StatusOK, roomSchedule) }, Middlewares: []echo.MiddlewareFunc{ apis.ActivityLogger(app), @@ -185,64 +179,7 @@ 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/feed", - Handler: func(c echo.Context) error { - token := c.QueryParam("token") - return ical.Feed(c, app, token) - }, - Middlewares: []echo.MiddlewareFunc{ - apis.ActivityLogger(app), - }, - }) - if err != nil { - return err - } - return nil - }) - - app.OnBeforeServe().Add(func(e *core.ServeEvent) error { - _, err := e.Router.AddRoute(echo.Route{ - Method: http.MethodDelete, - Path: "/api/feed", - Handler: func(c echo.Context) error { - token := c.QueryParam("token") - err := db.DeleteFeed(app.Dao(), token) - if err != nil { - return c.JSON(http.StatusNotFound, err) - } else { - return c.JSON(http.StatusOK, "Feed deleted") - } - }, - Middlewares: []echo.MiddlewareFunc{ - apis.ActivityLogger(app), - }, - }) - if err != nil { - return err - } - return nil - }) - - app.OnBeforeServe().Add(func(e *core.ServeEvent) error { - _, err := e.Router.AddRoute(echo.Route{ - Method: http.MethodPut, - Path: "/api/feed", - Handler: func(c echo.Context) error { - token := c.QueryParam("token") - return c.JSON(http.StatusOK, "token: "+token) - }, - Middlewares: []echo.MiddlewareFunc{ - apis.ActivityLogger(app), - }, - }) - if err != nil { - return err - } - return nil - }) + addFeedRoutes(app) app.OnBeforeServe().Add(func(e *core.ServeEvent) error { _, err := e.Router.AddRoute(echo.Route{ diff --git a/backend/service/addSchedule.go b/backend/service/addSchedule.go index 9eb1a89..3c56d8b 100644 --- a/backend/service/addSchedule.go +++ b/backend/service/addSchedule.go @@ -10,7 +10,6 @@ import ( "htwkalender/service/fetch/sport" v2 "htwkalender/service/fetch/v2" "htwkalender/service/functions/time" - "log" "log/slog" "strconv" ) @@ -38,27 +37,28 @@ func AddSchedules(app *pocketbase.PocketBase) { // Every sunday at 2am fetch all sport events (5 segments - minute, hour, day, month, weekday) "0 2 * * 0" scheduler.MustAdd("fetchSportEvents", "0 3 * * 0", func() { slog.Info("Started fetching sport events schedule") - sport.FetchAndUpdateSportEvents(app) + sportEvents, err := sport.FetchAndUpdateSportEvents(app) + if err != nil { + slog.Error("Failed to fetch and save sport events: %v", err) + } + slog.Info("Successfully fetched " + strconv.FormatInt(int64(len(sportEvents)), 10) + " sport events") }) //delete all events and then fetch all events from remote this should be done every sunday at 2am scheduler.MustAdd("fetchEvents", "0 2 * * 0", func() { err := events.DeleteAllEvents(app) if err != nil { - log.Println(err) + slog.Error("Failed to delete all events: %v", err) } savedEvents, err := v2.FetchAllEventsAndSave(app, time.RealClock{}) if err != nil { - log.Println(err) + slog.Error("Failed to fetch and save events: %v", err) } else { - log.Println("Successfully saved: " + strconv.FormatInt(int64(len(savedEvents)), 10) + " events") + slog.Info("Successfully fetched " + strconv.FormatInt(int64(len(savedEvents)), 10) + " events") } - }) - scheduler.Start() return nil }) - } diff --git a/backend/service/ical/ical.go b/backend/service/ical/ical.go index ad788e6..7377f4b 100644 --- a/backend/service/ical/ical.go +++ b/backend/service/ical/ical.go @@ -5,23 +5,21 @@ import ( "encoding/json" "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 -func Feed(c echo.Context, app *pocketbase.PocketBase, token string) error { +func Feed(app *pocketbase.PocketBase, token string) (string, error) { var result string - var responseWriter = c.Response().Writer + feed, err := db.FindFeedByToken(token, app) if feed == nil && err != nil { - return c.JSON(http.StatusNotFound, err) + return "", err } modules := make(map[string]model.FeedCollection) @@ -34,17 +32,11 @@ func Feed(c echo.Context, app *pocketbase.PocketBase, token string) error { newFeed, err := createFeedForToken(app, modules) if err != nil { - return c.JSON(http.StatusInternalServerError, err) + return "", err } result = newFeed.Content - responseWriter.Header().Set("Content-type", "text/calendar") - responseWriter.Header().Set("charset", "utf-8") - responseWriter.Header().Set("Content-Disposition", "inline") - responseWriter.Header().Set("filename", "calendar.ics") - writeSuccess(result, responseWriter) - c.Response().Writer = responseWriter - return nil + return result, nil } func createFeedForToken(app *pocketbase.PocketBase, modules map[string]model.FeedCollection) (*model.FeedModel, error) { @@ -60,14 +52,6 @@ func createFeedForToken(app *pocketbase.PocketBase, modules map[string]model.Fee return feed, nil } -func writeSuccess(message string, w http.ResponseWriter) { - w.WriteHeader(http.StatusOK) - _, err := w.Write([]byte(message)) - if err != nil { - return - } -} - func CreateIndividualFeed(requestBody []byte, app *pocketbase.PocketBase) (string, error) { var modules []model.FeedCollection diff --git a/backend/service/room/roomService.go b/backend/service/room/roomService.go index e8ff456..47e6bad 100644 --- a/backend/service/room/roomService.go +++ b/backend/service/room/roomService.go @@ -1,45 +1,36 @@ package room import ( + "github.com/pocketbase/pocketbase" "htwkalender/model" "htwkalender/service/db" - "log/slog" - "net/http" - - "github.com/labstack/echo/v5" - "github.com/pocketbase/pocketbase" ) -func GetRooms(c echo.Context, app *pocketbase.PocketBase) error { +func GetRooms(app *pocketbase.PocketBase) ([]string, error) { rooms, err := db.GetRooms(app) - if err != nil { - slog.Error("Error getting rooms: ", err) - return c.JSON(http.StatusNotFound, "No rooms found") + return nil, err } else { - return c.JSON(http.StatusOK, rooms) + return rooms, nil } } -func GetRoomScheduleForDay(c echo.Context, app *pocketbase.PocketBase, room string, date string) error { - - events, err := db.GetRoomScheduleForDay(app, room, date) - +func GetRoomScheduleForDay(app *pocketbase.PocketBase, room string, date string) ([]model.AnonymizedEventDTO, error) { + roomSchedule, err := db.GetRoomScheduleForDay(app, room, date) if err != nil { - return c.JSON(http.StatusInternalServerError, err) - } else { - return c.JSON(http.StatusOK, anonymizeRooms(events)) + return nil, err } + anonymizedRoomSchedule := anonymizeRooms(roomSchedule) + return anonymizedRoomSchedule, nil } -func GetRoomSchedule(c echo.Context, app *pocketbase.PocketBase, room string, from string, to string) error { - events, err := db.GetRoomSchedule(app, room, from, to) - +func GetRoomSchedule(app *pocketbase.PocketBase, room string, from string, to string) ([]model.AnonymizedEventDTO, error) { + roomSchedule, err := db.GetRoomSchedule(app, room, from, to) if err != nil { - return c.JSON(http.StatusInternalServerError, err) - } else { - return c.JSON(http.StatusOK, anonymizeRooms(events)) + return nil, err } + anonymizedRoomSchedule := anonymizeRooms(roomSchedule) + return anonymizedRoomSchedule, nil } // Transform the events to anonymized events throwing away all unnecessary information