//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format. //Copyright (C) 2024 HTWKalender support@htwkalender.de //This program is free software: you can redistribute it and/or modify //it under the terms of the GNU Affero General Public License as published by //the Free Software Foundation, either version 3 of the License, or //(at your option) any later version. //This program is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //GNU Affero General Public License for more details. //You should have received a copy of the GNU Affero General Public License //along with this program. If not, see . package service import ( "encoding/json" "errors" "github.com/gofiber/fiber/v3" "htwkalender/ical/model" "htwkalender/ical/service/ical" "log/slog" "net/http" ) // AddFeedRoutes add routes to the app instance for the data-manager ical service // with golang fiber func AddFeedRoutes(app model.AppType) { // Define a route for the GET method on the root path '/' app.Fiber.Get("/api/feed", func(c fiber.Ctx) error { token := c.Query("token") ifNoneMatch := c.Get("If-None-Match") // get request userAgent and check if it is Thunderbird userAgent := c.Get("User-Agent") slog.Info("User-Agent", "userAgent", userAgent) results, eTag, err := ical.Feed(app, token, userAgent) if errors.Is(err, ical.FeedDeletedError) { return c.SendStatus(fiber.StatusGone) } if err != nil { slog.Error("Failed to get feed", "error", err, "token", token) return c.SendStatus(fiber.StatusNotFound) } if ifNoneMatch == eTag && ifNoneMatch != "" { return c.SendStatus(fiber.StatusNotModified) } c.Response().Header.Set("Content-type", "text/calendar") c.Response().Header.Set("charset", "utf-8") c.Response().Header.Set("Content-Disposition", "inline") c.Response().Header.Set("filename", "calendar.ics") c.Response().Header.Set("ETag", eTag) return c.SendString(results) }) // Define a route for the POST method on the root path '/api/feed' app.Fiber.Post("/api/feed", func(c fiber.Ctx) error { var modules []model.FeedCollection //obtain the body of the request err := json.Unmarshal(c.Body(), &modules) if err != nil { slog.Error("Failed to parse request body", "error", err, "body", string(c.Body())) return c.SendStatus(fiber.StatusBadRequest) } //create a new feed token, err := ical.CreateFeed(app, modules) if err != nil { println(err) slog.Error("Failed to create feed", "error", err) return c.SendStatus(fiber.StatusBadRequest) } return c.JSON(token) }) // Define a route for the GET method on the root path '/' app.Fiber.Get("/api/feeds/records/:token", func(c fiber.Ctx) error { token := c.Params("token") results, err := ical.FeedRecord(app, token) if results.Deleted { return c.SendStatus(fiber.StatusNotFound) } if err != nil { slog.Error("Failed to get feed record", "error", err, "token", token) return c.SendStatus(fiber.StatusBadRequest) } c.Response().Header.Set("Content-type", "application/json; charset=UTF-8") return c.JSON(results) }) app.Fiber.Delete("/api/feed", func(c fiber.Ctx) error { token := c.Query("token") err := ical.DeleteFeedRecord(app, token) if err != nil { slog.Error("Feed could not be deleted", "error", err, "token", token) return c.JSON(http.StatusNotFound, "Feed could not be deleted") } else { return c.JSON(http.StatusOK, "Feed deleted") } }) app.Fiber.Put("/api/feed", func(c fiber.Ctx) error { token := c.Query("token") return c.JSON(http.StatusOK, "token: "+token) }) app.Fiber.Get("/api/feed/room", func(c fiber.Ctx) error { room := c.Query("id") ifNoneMatch := c.Get("If-None-Match") results, etag, err := ical.FeedRoom(app, room) if err != nil { slog.Error("Failed to get feed", "error", err, "room", room) return c.SendStatus(fiber.StatusNotFound) } if ifNoneMatch == etag && ifNoneMatch != "" { return c.SendStatus(fiber.StatusNotModified) } c.Response().Header.Set("Content-type", "text/calendar") c.Response().Header.Set("charset", "utf-8") c.Response().Header.Set("Content-Disposition", "inline") c.Response().Header.Set("filename", "calendar.ics") return c.SendString(results) }) app.Fiber.Head("/api/feed", func(c fiber.Ctx) error { return c.JSON(http.StatusOK, "") }) app.Fiber.Add([]string{"PROPFIND"}, "/api/feed", func(c fiber.Ctx) error { return c.JSON(http.StatusOK, "") }) // Route for Thunderbird to get calendar server information // Response is a 200 OK without additional content app.Fiber.Add([]string{"PROPFIND"}, "/.well-known/caldav", func(c fiber.Ctx) error { return c.JSON(http.StatusOK, "") }) // Route for Thunderbird to get calendar server information // Response is a 200 OK without additional content app.Fiber.Add([]string{"PROPFIND"}, "/", func(c fiber.Ctx) error { return c.JSON(http.StatusOK, "") }) }