Skip to content

Commit

Permalink
feat(webcal): add the webcal format type return
Browse files Browse the repository at this point in the history
  • Loading branch information
vareversat committed Jul 19, 2024
1 parent c436411 commit f0912e8
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 17 deletions.
Empty file removed Dockerfile.dev
Empty file.
1 change: 0 additions & 1 deletion compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ services:
- persistent-app-volume:/app
ports:
- "8080:8080"
- "6060:6060"
env_file:
- .env.dev

Expand Down
15 changes: 15 additions & 0 deletions debug.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# syntax=docker/dockerfile:1

FROM golang:1.22.4 as build
ARG VERSION
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
RUN go install github.com/swaggo/swag/cmd/swag@latest
COPY . .
RUN swag init -d ./internal/api/routers,./ -g main_router.go
# Debug mode
RUN CGO_ENABLED=0 go install -ldflags "-s -w -extldflags '-static'" github.com/go-delve/delve/cmd/dlv@latest
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/chabo-api -gcflags "all=-N -l" -ldflags="-X github.com/vareversat/chabo-api/internal/api/routers.version=$VERSION"

CMD [ "/go/bin/dlv", "--listen=:4000", "--headless=true", "--log=true", "--accept-multiclient", "--api-version=2", "exec", "/app/chabo-api" ]
26 changes: 26 additions & 0 deletions debug.compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
services:
app:
container_name: chabo-api
build:
context: .
dockerfile: debug.Dockerfile
args:
- VERSION=v0.0.0+dev
volumes:
- persistent-app-volume:/app
ports:
- "8080:8080"
- "4000:4000"
env_file:
- .env.dev

mongo:
container_name: mongo-server
image: mongo:6.0.16
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: my_password
MONGO_INITDB_DATABASE: chabo-api

volumes:
persistent-app-volume:
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
module github.com/vareversat/chabo-api

go 1.22

toolchain go1.22.0
go 1.22.0

require (
github.com/getsentry/sentry-go v0.28.1
github.com/gin-gonic/gin v1.10.0
github.com/stretchr/testify v1.9.0
github.com/swaggo/files v1.0.1
github.com/vareversat/gics v0.2.1
go.mongodb.org/mongo-driver v1.16.0
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/vareversat/gics v0.2.1 h1:LuKK83Kdx2t8pbowY147AuFcEU2KMff6+QjdtngdrHY=
github.com/vareversat/gics v0.2.1/go.mod h1:6WZtZqEvvT1CyeGPAXVclCppimbAKX5MQu7oIoxPzs0=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
Expand Down
54 changes: 44 additions & 10 deletions internal/api/controllers/forecast_controller.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package controllers

import (
"bytes"
"fmt"
"net/http"
"time"
Expand All @@ -16,6 +17,11 @@ type ForecastController struct {
ForecastUseCase domains.ForecastUseCase
}

const (
jsonFormat = "json"
webcalFormat = "webcal"
)

// GetAllForecasts godoc
//
// @Summary Get all forecasts
Expand All @@ -27,8 +33,9 @@ type ForecastController struct {
// @Failure 400 {object} domains.APIErrorResponse{} "Some params are missing and/or not properly formatted from the requests"
// @Failure 500 {object} domains.APIErrorResponse{} "An error occurred on the server side"
// @Param from query string false "The date to filter from (RFC3339)" Format(date-time)
// @Param limit query int true "Set the limit of the queried results" Format(int) default(10)
// @Param offset query int true "Set the offset of the queried results" Format(int) default(0)
// @Param limit query int true "Set the limit of the queried results" Format(int) default(10)
// @Param offset query int true "Set the offset of the queried results" Format(int) default(0)
// @Param format query string true "json or webcal output" Enums(json, webcal) default(json)
// @Param reason query string false "The closing reason" Enums(boat, maintenance, wine_festival_boats, special_event)
// @Param boat query string false "The boat name of the event"
// @Param maneuver query string false "The boat maneuver of the event" Enums(leaving_bordeaux, entering_in_bordeaux)
Expand All @@ -47,12 +54,14 @@ func (fC *ForecastController) GetAllForecasts() gin.HandlerFunc {
location, locationErr := utils.GetTimezoneFromHeader(c)
limit, limitErr := utils.GetIntParams(c, "limit")
offset, offsetErr := utils.GetIntParams(c, "offset")
reason := utils.GetStringParams(c, "reason")
boat := utils.GetStringParams(c, "boat")
maneuver := utils.GetStringParams(c, "maneuver")
parsedTime, timeErr := time.Parse(time.RFC3339, utils.GetStringParams(c, "from"))

if timeErr != nil && utils.GetStringParams(c, "from") != "" {
from, _ := utils.GetStringParams(c, "from", false)
reason, _ := utils.GetStringParams(c, "reason", false)
boat, _ := utils.GetStringParams(c, "boat", false)
maneuver, _ := utils.GetStringParams(c, "maneuver", false)
parsedTime, timeErr := time.Parse(time.RFC3339, from)
outputFormat := c.DefaultQuery("format", jsonFormat)

if timeErr != nil && from != "" {
c.JSON(
http.StatusBadRequest,
domains.APIErrorResponse{
Expand Down Expand Up @@ -126,9 +135,34 @@ func (fC *ForecastController) GetAllForecasts() gin.HandlerFunc {
Timezone: location.String(),
}

c.JSON(http.StatusOK, response)
switch outputFormat {
case jsonFormat:
c.JSON(http.StatusOK, response)
case webcalFormat:
cal, err := utils.ComputeCalendar(forecasts, location.String())
if err != nil {
c.JSON(http.StatusInternalServerError, domains.APIErrorResponse{Error: err.Error()})
sentry.CaptureException(err)
return
} else {
output := bytes.Buffer{}
cal.SerializeToICSFormat(&output)
c.String(http.StatusOK, output.String())
}
default:
c.JSON(
http.StatusBadRequest,
domains.APIErrorResponse{
Error: fmt.Sprintf(
"You must use '%s' or '%s' values for format param",
jsonFormat,
webcalFormat,
),
},
)
sentry.CaptureException(locationErr)
}
}

return gin.HandlerFunc(fn)
}

Expand Down
32 changes: 32 additions & 0 deletions internal/domains/forecast_domain.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package domains

import (
"bytes"
"context"
"fmt"
"os"
"reflect"
"time"
Expand Down Expand Up @@ -89,6 +91,36 @@ func (forecasts *Forecasts) AreEqual(other Forecasts) bool {
return true
}

func (f *Forecast) GetSummary() string {
switch f.ClosingReason {
case BoatReason:
var summary bytes.Buffer
summary.WriteString(`Le pont Chaban sera fermé en raison des manoeuvres suivantes :\n`)
for _, boat := range f.Boats {
if boat.Maneuver == Leaving {
summary.WriteString(fmt.Sprintf(`\n • %s`, "Départ du "))
} else {
summary.WriteString(fmt.Sprintf(`\n • %s`, "Arrivée du "))
}
summary.WriteString(fmt.Sprintf(`%s`, boat.Name))
summary.WriteString(
fmt.Sprintf(
` (passage approx. prévu aux alentours de %s)`,
boat.CrossingDateApproximation.Format("15:04:05"),
),
)
}
return summary.String()
case Maintenance:
return fmt.Sprintf("Le pont Chanban sera fermé pour maintenance")
case WineFestivalBoats:
return fmt.Sprintf(
"Le pont Chanban sera fermé pour l'arrivée des bateaux de la fête du vin",
)
}
return ""
}

func (f *Forecast) ChangeLocation(location *time.Location) {
f.CirculationClosingDate = f.CirculationClosingDate.In(location)
f.CirculationReopeningDate = f.CirculationReopeningDate.In(location)
Expand Down
10 changes: 7 additions & 3 deletions internal/utils/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@ func GetIntParams(c *gin.Context, paramName string) (int, error) {

// GetStringParams Get the string param paramName passed into the request.
// Return empty string if not specified or empty, the value either
func GetStringParams(c *gin.Context, paramName string) string {
func GetStringParams(c *gin.Context, paramName string, mandatory bool) (string, error) {

paramValue, _ := c.GetQuery(paramName)
paramValue, exists := c.GetQuery(paramName)

return paramValue
if !exists && mandatory {
return "", fmt.Errorf("you have to specify the %s in requests params", paramName)
}

return paramValue, nil

}

Expand Down
49 changes: 49 additions & 0 deletions internal/utils/webcal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package utils

import (
"time"

"github.com/vareversat/chabo-api/internal/domains"
"github.com/vareversat/gics"
"github.com/vareversat/gics/components"
"github.com/vareversat/gics/parameters"
"github.com/vareversat/gics/properties"
"github.com/vareversat/gics/types"
)

// ComputeCalendar take all the fetched forecasts and the requested timezone
// Return a gics.Calendar (webcal)
func ComputeCalendar(forecasts domains.Forecasts, timezone string) (gics.Calendar, error) {
calendarComponents := components.CalendarComponents{}
for _, forecast := range forecasts {
calendarComponents = append(calendarComponents, components.NewEventCalendarComponent(
properties.NewUidProperty(
forecast.ID,
),
properties.NewDateTimeStampProperty(time.Now().UTC()),
[]components.AlarmCalendarComponent{},
properties.NewDateTimeStartProperty(
forecast.CirculationClosingDate,
types.WithLocalTime,
parameters.NewTimeZoneIdentifierParam(timezone),
),
properties.NewDateTimeEndProperty(
forecast.CirculationReopeningDate,
types.WithLocalTime,
parameters.NewTimeZoneIdentifierParam(timezone),
),
properties.NewDescriptionProperty(forecast.GetSummary()),
properties.NewGeographicPositionProperty(44.858339101606994, -0.551626089048817),
properties.NewSummaryProperty("Fermeture du pont Chaban"),
properties.NewLocationProperty("Pont Jacques Chaban Delmas - Bordeaux"),
))
}

return gics.NewCalendar(
calendarComponents,
"-//Valentin REVERSAT//https://github.com/vareversat/gics//FR",
"PUBLISH",
"2.0",
)

}

0 comments on commit f0912e8

Please sign in to comment.