From 8bb8d90a88c416dfb7c2f0bedf894d6597b71e35 Mon Sep 17 00:00:00 2001 From: Arnaud Delcasse Date: Mon, 12 Dec 2022 00:06:27 +0100 Subject: [PATCH] Initial commit --- README.md | 4 + bookings.go | 34 ++ carpool-bookings.go | 50 +++ cars.go | 6 + .../README.md | 3 + .../go.mod | 15 + .../go.sum | 6 + .../main.go | 117 ++++++ go.mod | 10 + go.sum | 6 + journeys.go | 58 +++ preferences.go | 9 + prices.go | 15 + schedules.go | 19 + server.go | 346 ++++++++++++++++++ trips.go | 43 +++ users.go | 21 ++ 17 files changed, 762 insertions(+) create mode 100644 README.md create mode 100644 bookings.go create mode 100644 carpool-bookings.go create mode 100644 cars.go create mode 100644 cmd/standardcovoiturage-to-rdex-gateway/README.md create mode 100644 cmd/standardcovoiturage-to-rdex-gateway/go.mod create mode 100644 cmd/standardcovoiturage-to-rdex-gateway/go.sum create mode 100644 cmd/standardcovoiturage-to-rdex-gateway/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 journeys.go create mode 100644 preferences.go create mode 100644 prices.go create mode 100644 schedules.go create mode 100644 server.go create mode 100644 trips.go create mode 100644 users.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..0bbebeb --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# COOPGO Standard Covoiturage + +Implementation of the [Standard Covoiturage](https://github.com/fabmob/standard-covoiturage/) specification. This library is part of the COOPGO Technical Platform and provides cleint and server implementations of the standard. + diff --git a/bookings.go b/bookings.go new file mode 100644 index 0000000..2f8c904 --- /dev/null +++ b/bookings.go @@ -0,0 +1,34 @@ +package standardcovoiturage + +import "time" + +type BookingStatus int64 + +const ( + BookingWaitingConfirmation BookingStatus = iota + BookingConfirmed + BookingCancelled + BookingCompletedPendingValidation + BookingValidated +) + +type Booking struct { + ID string `json:"id"` // TODO check uuidv4 + Driver User `json:"driver"` + Passenger User `json:"passenger"` + PassengerPickupDate time.Time `json:"passengerPickupDate"` + PassengerPickupLat float64 `json:"passengerPickupLat"` + PassengerPickupLng float64 `json:"passengerPickupLng"` + PassengerDropLat float64 `json:"passengerDropLat"` + PassengerDropLng float64 `json:"passengerDropLng"` + PassengerPickupAddress *string `json:"passengerPickupAddress,omitempty"` + PassengerDropAddress *string `json:"passengerDropAddress,omitempty"` + Status BookingStatus `json:"status"` + Distance *int64 `json:"distance,omitempty"` + Duration *time.Duration `json:"duration,omitempty"` + WebUrl *string `json:"webUrl,omitempty"` + Price Price `json:"price"` + Car *Car `json:"car"` + DriverJourneyID string `json:"driverJourneyId"` + PassengerJourneyID string `json:"passengerJourneyId"` +} diff --git a/carpool-bookings.go b/carpool-bookings.go new file mode 100644 index 0000000..4738358 --- /dev/null +++ b/carpool-bookings.go @@ -0,0 +1,50 @@ +package standardcovoiturage + +import "time" + +type CarpoolBookingStatus int64 + +const ( + CarpoolBookingWaitingConfirmation CarpoolBookingStatus = iota + CarpoolBookingConfirmed + CarpoolBookingCancelled + CarpoolBookingCompletedPendingValidation + CarpoolBookingValidated +) + +type CarpoolBookingEventData struct { + CarpoolBooking + DriverCarpoolBooking + PassengerCarpoolBooking +} + +type CarpoolBookingEvent struct { + ID string `json:"id"` // TODO validate UUID + IDToken string `json:"idToken"` + Data CarpoolBookingEventData `json:"data"` +} + +type CarpoolBooking struct { + ID string `json:"id"` + PassengerPickupDate time.Time `json:"passengerPickupDate"` + PassengerPickupLat float64 `json:"passengerPickupLat"` + PassengerPickupLng float64 `json:"passengerPickupLng"` + PassengerDropLat float64 `json:"passengerDropLat"` + PassengerDropLng float64 `json:"passengerDropLng"` + PassengerPickupAddress *string `json:"passengerPickupAddress,omitempty"` + PassengerDropAddress *string `json:"passengerDropAddress,omitempty"` + Status CarpoolBookingStatus `json:"status"` + Distance *int64 `json:"distance,omitempty"` + Duration *time.Duration `json:"duration,omitempty"` + WebUrl string `json:"webUrl"` +} + +type PassengerCarpoolBooking struct { + Passenger User `json:"passenger"` +} + +type DriverCarpoolBooking struct { + Driver User `json:"driver"` + Price Price `json:"price"` + Car *Car `json:"car,omitempty"` +} diff --git a/cars.go b/cars.go new file mode 100644 index 0000000..ed888e4 --- /dev/null +++ b/cars.go @@ -0,0 +1,6 @@ +package standardcovoiturage + +type Car struct { + Model *string `json:"model,omitempty"` + Brand *string `json:"brand,omitempty"` +} diff --git a/cmd/standardcovoiturage-to-rdex-gateway/README.md b/cmd/standardcovoiturage-to-rdex-gateway/README.md new file mode 100644 index 0000000..8bea258 --- /dev/null +++ b/cmd/standardcovoiturage-to-rdex-gateway/README.md @@ -0,0 +1,3 @@ +# Standard covoiturage to RDEX Gateway + +Standard covoiturage to RDEX Gateway is a converter from the new standard covoiturage to RDEX API calls for searching carpool journeys. \ No newline at end of file diff --git a/cmd/standardcovoiturage-to-rdex-gateway/go.mod b/cmd/standardcovoiturage-to-rdex-gateway/go.mod new file mode 100644 index 0000000..76584cf --- /dev/null +++ b/cmd/standardcovoiturage-to-rdex-gateway/go.mod @@ -0,0 +1,15 @@ +module git.coopgo.io/coopgo-platform/standard-covoiturage/cmd/standardcovoiturage-to-rdex-bridge + +replace git.coopgo.io/coopgo-platform/standard-covoiturage => ../../ + +go 1.18 + +require ( + git.coopgo.io/coopgo-platform/standard-covoiturage v0.0.0 + gitlab.scity.coop/go-libs/rdex-golang v0.0.0-20210202230228-0ccbfcbe2163 +) + +require ( + github.com/gorilla/schema v1.2.0 // indirect + golang.org/x/crypto v0.1.0 // indirect +) diff --git a/cmd/standardcovoiturage-to-rdex-gateway/go.sum b/cmd/standardcovoiturage-to-rdex-gateway/go.sum new file mode 100644 index 0000000..3db48bb --- /dev/null +++ b/cmd/standardcovoiturage-to-rdex-gateway/go.sum @@ -0,0 +1,6 @@ +github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= +github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= +gitlab.scity.coop/go-libs/rdex-golang v0.0.0-20210202230228-0ccbfcbe2163 h1:F0XUsnMwOtDLaS1riH/fEopzly+KdwZpUHIvL0f/RHQ= +gitlab.scity.coop/go-libs/rdex-golang v0.0.0-20210202230228-0ccbfcbe2163/go.mod h1:EOh0Z3TK1/Z48oDidtIV3reDcflpYCIdZk+2Mj76a/4= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= diff --git a/cmd/standardcovoiturage-to-rdex-gateway/main.go b/cmd/standardcovoiturage-to-rdex-gateway/main.go new file mode 100644 index 0000000..2f68d40 --- /dev/null +++ b/cmd/standardcovoiturage-to-rdex-gateway/main.go @@ -0,0 +1,117 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "time" + + standardcovoiturage "git.coopgo.io/coopgo-platform/standard-covoiturage" + "gitlab.scity.coop/go-libs/rdex-golang" +) + +func main() { + handler := CarpoolHandler{} + server := standardcovoiturage.NewServer(handler) + server.AddOperator("fakeoperator", "mysupersecretapikey") + + http.Handle("/", server) + + err := http.ListenAndServe(":3333", nil) + panic(err) +} + +type CarpoolHandler struct{} + +func (h CarpoolHandler) GetDriverJourneys(ctx context.Context, departureLat float64, departureLng float64, arrivalLat float64, arrivalLng float64, departureDate time.Time, timeDelta *time.Duration, departureRadius *float64, count *int64) ([]standardcovoiturage.DriverJourney, error) { + carpoolrequest := "https://api.rdex.ridygo.fr/journeys.json" + + client := &http.Client{} + req, err := http.NewRequest("GET", carpoolrequest, nil) + if err != nil { + fmt.Println(err) + } + + req.URL.RawQuery = fmt.Sprintf( + "p[driver][state]=1&frequency=punctual&p[passenger][state]=0&p[from][latitude]=%f&p[from][longitude]=%f&p[to][latitude]=%f&p[to][longitude]=%f&p[outward][mindate]=%s&p[outward][maxdate]=%s", + departureLat, departureLng, + arrivalLat, arrivalLng, + departureDate.Format("2006-01-02"), departureDate.Format("2006-01-02")) + + req.Header.Set("X-API-KEY", "123456") + resp, err := client.Do(req) + if err != nil { + fmt.Println(err) + } + + var carpoolresults []rdex.RDEXJourney + + if err == nil && resp.StatusCode == http.StatusOK { + err = json.NewDecoder(resp.Body).Decode(&carpoolresults) + if err != nil { + fmt.Println(err) + } + + if carpoolresults == nil { + carpoolresults = []rdex.RDEXJourney{} + } + } else { + carpoolresults = []rdex.RDEXJourney{} + } + + results := []standardcovoiturage.DriverJourney{} + for _, c := range carpoolresults { + + journey := standardcovoiturage.DriverJourney{ + AvailableSteats: c.Driver.Seats, + DriverTrip: standardcovoiturage.DriverTrip{ + Trip: standardcovoiturage.Trip{ + Operator: c.Operator, + WebUrl: c.URL, + PassengerPickupLat: c.From.Latitude, + PassengerPickupLng: c.From.Longitude, + }, + Driver: standardcovoiturage.User{ + ID: *c.Driver.UUID, + Operator: c.Operator, + Alias: *c.Driver.Alias, + Picture: c.Driver.Image, + }, + }, + } + + results = append(results, journey) + } + + return results, nil +} + +// func (h CarpoolHandler) GetDriverJourneys(ctx context.Context, departureLat float64, departureLng float64, arrivalLat float64, arrivalLng float64, departureDate time.Time, timeDelta *time.Duration, departureRadius *float64, count *int64) ([]standardcovoiturage.DriverJourney, error) { +// availableSeats := int64(1) + +// return []standardcovoiturage.DriverJourney{ +// { +// AvailableSteats: &availableSeats, +// DriverTrip: standardcovoiturage.DriverTrip{ +// Driver: standardcovoiturage.User{ +// ID: "1234567890", +// Operator: "fakeoperator", +// Alias: "Fake user", +// }, +// Trip: standardcovoiturage.Trip{ +// Operator: "fakeoperator", +// PassengerPickupLat: 2.0, +// PassengerPickupLng: 2.0, +// PassengerDropLat: 3.0, +// PassengerDropLng: 3.0, +// Duration: 3600, +// }, +// }, +// JourneySchedule: standardcovoiturage.JourneySchedule{ +// PassengerPickupDate: time.Now(), +// Type: standardcovoiturage.Planned, +// }, +// }, +// }, nil +// } diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5d69ce0 --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module git.coopgo.io/coopgo-platform/standard-covoiturage + +go 1.18 + +require golang.org/x/crypto v0.1.0 + +require ( + github.com/gorilla/schema v1.2.0 // indirect + gitlab.scity.coop/go-libs/rdex-golang v0.0.0-20210202230228-0ccbfcbe2163 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..3db48bb --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= +github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= +gitlab.scity.coop/go-libs/rdex-golang v0.0.0-20210202230228-0ccbfcbe2163 h1:F0XUsnMwOtDLaS1riH/fEopzly+KdwZpUHIvL0f/RHQ= +gitlab.scity.coop/go-libs/rdex-golang v0.0.0-20210202230228-0ccbfcbe2163/go.mod h1:EOh0Z3TK1/Z48oDidtIV3reDcflpYCIdZk+2Mj76a/4= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= diff --git a/journeys.go b/journeys.go new file mode 100644 index 0000000..9459a95 --- /dev/null +++ b/journeys.go @@ -0,0 +1,58 @@ +package standardcovoiturage + +import ( + "fmt" + "time" +) + +type JourneyScheduleType int64 + +const ( + Planned JourneyScheduleType = iota + Dynamic + Line +) + +func (t JourneyScheduleType) MarshalJSON() ([]byte, error) { + types := map[JourneyScheduleType]string{ + Planned: "\"PLANNED\"", + Dynamic: "\"DYNAMIC\"", + Line: "\"Line\"", + } + + return []byte(types[t]), nil +} + +type JSONTime time.Time + +func (t JSONTime) MarshalJSON() ([]byte, error) { + //do your serializing here + stamp := fmt.Sprintf("%v", time.Time(t).Unix()) + return []byte(stamp), nil +} + +type JourneySchedule struct { + ID *string `json:"id,omitempty"` + PassengerPickupDate JSONTime `json:"passengerPickupDate"` + PassengerDepartureDate *JSONTime `json:"passengerDepartureDate,omitempty"` + DriverDepartureDate *JSONTime `json:"driverDepartureDate,omitempty"` + WebUrl *string `json:"webUrl,omitempty"` + Type JourneyScheduleType `json:"type"` +} + +type DriverJourney struct { + DriverTrip + JourneySchedule + + AvailableSteats *int `json:"requestedSeats,omitempty"` + Price *Price `json:"price,omitempty"` +} + +type PassengerJourney struct { + PassengerTrip + JourneySchedule + + //TODO how to handle requested driverDepartureDate + + RequestedSteats *int64 `json:"requestedSeats,omitempty"` +} diff --git a/preferences.go b/preferences.go new file mode 100644 index 0000000..74b6ddf --- /dev/null +++ b/preferences.go @@ -0,0 +1,9 @@ +package standardcovoiturage + +type Preferences struct { + Smoking *bool `json:"smoking,omitempty"` + Animals *bool `json:"animals,omitempty"` + Music *bool `json:"music,omitempty"` + IsTalker *bool `json:"isTalker,omitempty"` + LuggageSize *int64 `json:"luggageSize,omitempty"` +} diff --git a/prices.go b/prices.go new file mode 100644 index 0000000..37166e6 --- /dev/null +++ b/prices.go @@ -0,0 +1,15 @@ +package standardcovoiturage + +type PriceType int64 + +const ( + Free PriceType = iota + Paying + Unknown +) + +type Price struct { + Type *PriceType `json:"type,omitempty"` + Amount *float64 `json:"amount,omitempty"` + Currency *string `json:"currency,omitempty"` +} diff --git a/schedules.go b/schedules.go new file mode 100644 index 0000000..0a8561c --- /dev/null +++ b/schedules.go @@ -0,0 +1,19 @@ +package standardcovoiturage + +type Day int64 + +const ( + Monday Day = iota + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday +) + +type Schedule struct { + PassengerPickupDay *Day `json:"passengerPickupDay,omitempty"` + + JourneySchedules *[]JourneySchedule `json:"journeySchedules,omitempty"` +} diff --git a/server.go b/server.go new file mode 100644 index 0000000..251d310 --- /dev/null +++ b/server.go @@ -0,0 +1,346 @@ +package standardcovoiturage + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "net/http" + "strings" + "time" + + "github.com/gorilla/schema" + "golang.org/x/crypto/bcrypt" +) + +const OperatorContextKey = "operator" + +type Handler interface { + GetDriverJourneys(ctx context.Context, departureLat float64, departureLng float64, arrivalLat float64, arrivalLng float64, departureDate time.Time, timeDelta *time.Duration, departureRadius *float64, arrivalRadius *float64, count *int64) ([]DriverJourney, error) + GetPassengerJourneys(ctx context.Context, departureLat float64, departureLng float64, arrivalLat float64, arrivalLng float64, departureDate time.Time, timeDelta *time.Duration, departureRadius *float64, arrivalRadius *float64, count *int64) ([]PassengerJourney, error) + GetDriverRegularTrips(ctx context.Context, departureLat float64, departureLng float64, arrivalLat float64, arrivalLng float64, departureTimeOfDay string, departureWeekDays *[]string, timeDelta *time.Duration, departureRadius *float64, arrivalRadius *float64, minDepartureDate *time.Time, maxDepartureDate *time.Time, count *int64) ([]DriverTrip, error) + GetPassengerRegularTrips(ctx context.Context, departureLat float64, departureLng float64, arrivalLat float64, arrivalLng float64, departureTimeOfDay string, departureWeekDays *[]string, timeDelta *time.Duration, departureRadius *float64, arrivalRadius *float64, minDepartureDate *time.Time, maxDepartureDate *time.Time, count *int64) ([]PassengerTrip, error) +} + +type AuthorizedOperator struct { + Operator string + ApiKey string // encoded using bcrypt +} + +type GetDriverJourneysRequest struct { + DepartureLat float64 `schema:"departureLat,required"` + DepartureLng float64 `schema:"departureLng,required"` + ArrivalLat float64 `schema:"arrivalLat,required"` + ArrivalLng float64 `schema:"arrivalLng,required"` + DepartureDate int64 `schema:"departureDate,required"` + TimeDelta *int64 `schema:"timeDelta"` + DepartureRadius *float64 `schema:"departureRadius"` + ArrivalRadius *float64 `schema:"arrivalRadius"` + Count *int64 `schema:"count"` +} + +type GetPassengerJourneysRequest struct { + DepartureLat float64 `schema:"departureLat,required"` + DepartureLng float64 `schema:"departureLng,required"` + ArrivalLat float64 `schema:"arrivalLat,required"` + ArrivalLng float64 `schema:"arrivalLng,required"` + DepartureDate int64 `schema:"departureDate,required"` + TimeDelta *int64 `schema:"timeDelta"` + DepartureRadius *float64 `schema:"departureRadius"` + ArrivalRadius *float64 `schema:"arrivalRadius"` + Count *int64 `schema:"count"` +} + +type GetDriverRegularTripsRequest struct { + DepartureLat float64 `schema:"departureLat,required"` + DepartureLng float64 `schema:"departureLng,required"` + ArrivalLat float64 `schema:"arrivalLat,required"` + ArrivalLng float64 `schema:"arrivalLng,required"` + DepartureTimeOfDay string `schema:"departureTimeOfDay,required"` + DepartureWeekDays *[]string `schema:"departureWeekdays"` + TimeDelta *int64 `schema:"timeDelta"` + DepartureRadius *float64 `schema:"departureRadius"` + ArrivalRadius *float64 `schema:"arrivalRadius"` + MinDepartureDate *int64 `schema:"minDepartureDate"` + MaxDepartureDate *int64 `schema:"maxDepartureDate"` + Count *int64 `schema:"count"` +} + +type GetPassengerRegularTripsRequest struct { + DepartureLat float64 `schema:"departureLat,required"` + DepartureLng float64 `schema:"departureLng,required"` + ArrivalLat float64 `schema:"arrivalLat,required"` + ArrivalLng float64 `schema:"arrivalLng,required"` + DepartureTimeOfDay string `schema:"departureTimeOfDay,required"` + DepartureWeekDays *[]string `schema:"departureWeekdays"` + TimeDelta *int64 `schema:"timeDelta"` + DepartureRadius *float64 `schema:"departureRadius"` + ArrivalRadius *float64 `schema:"arrivalRadius"` + MinDepartureDate *int64 `schema:"minDepartureDate"` + MaxDepartureDate *int64 `schema:"maxDepartureDate"` + Count *int64 `schema:"count"` +} + +type Server struct { + Handler Handler + AuthorizedOperators []AuthorizedOperator +} + +func NewServer(handler Handler) *Server { + return &Server{ + Handler: handler, + } +} + +func (s *Server) FindApiKey(key string) (operator string, err error) { + for _, o := range s.AuthorizedOperators { + if e := bcrypt.CompareHashAndPassword([]byte(o.ApiKey), []byte(key)); e == nil { + return o.Operator, nil + } + } + + return "", errors.New("operator not found") +} + +func (s *Server) AddOperator(operator string, apiKey string) error { + encryptedKey, err := bcrypt.GenerateFromPassword([]byte(apiKey), bcrypt.DefaultCost) + if err != nil { + return err + } + s.AuthorizedOperators = append(s.AuthorizedOperators, AuthorizedOperator{ + Operator: operator, + ApiKey: string(encryptedKey), + }) + + return nil +} + +func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + apiKey := r.Header.Get("X-Api-Key") + operator, err := s.FindApiKey(apiKey) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusUnauthorized) + return + } + + ctx := context.WithValue(r.Context(), OperatorContextKey, operator) + + p := strings.Split(r.URL.Path, "/")[1:] + n := len(p) + switch { + case r.Method == "GET" && n == 1 && p[0] == "driver_journeys": + s.getDriverJourneys(w, r.WithContext(ctx)) + return + case r.Method == "GET" && n == 1 && p[0] == "passenger_journeys": + s.getPassengerJourneys(w, r.WithContext(ctx)) + return + case r.Method == "GET" && n == 1 && p[0] == "driver_regular_trips": + s.getDriverRegularTrips(w, r.WithContext(ctx)) + return + case r.Method == "GET" && n == 1 && p[0] == "passenger_regular_trips": + s.getPassengerRegularTrips(w, r.WithContext(ctx)) + return + default: + w.WriteHeader(http.StatusNotFound) + } +} + +func (s *Server) getDriverJourneys(w http.ResponseWriter, r *http.Request) { + var request GetDriverJourneysRequest + + var decoder = schema.NewDecoder() + + if err := decoder.Decode(&request, r.URL.Query()); err != nil { + fmt.Println(err) + badRequest(w, fmt.Errorf("could not parse the request : %s", err)) + return + } + + departureDate := time.Unix(request.DepartureDate, 0) + var timeDelta *time.Duration + timeDelta = nil + if request.TimeDelta != nil { + duration := time.Duration(*request.TimeDelta) + timeDelta = &duration + } + + driverJourneys, err := s.Handler.GetDriverJourneys( + r.Context(), + request.DepartureLat, + request.DepartureLng, + request.ArrivalLat, + request.ArrivalLng, + departureDate, + timeDelta, + request.DepartureRadius, + request.ArrivalRadius, + request.Count) + + if err != nil { + fmt.Println(err) + jsonResponse(w, err, http.StatusInternalServerError) + return + } + + jsonResponse(w, driverJourneys, http.StatusOK) +} + +func (s *Server) getPassengerJourneys(w http.ResponseWriter, r *http.Request) { + var request GetPassengerJourneysRequest + + var decoder = schema.NewDecoder() + + if err := decoder.Decode(&request, r.URL.Query()); err != nil { + fmt.Println(err) + badRequest(w, fmt.Errorf("could not parse the request : %s", err)) + return + } + + departureDate := time.Unix(request.DepartureDate, 0) + var timeDelta *time.Duration + timeDelta = nil + if request.TimeDelta != nil { + duration := time.Duration(*request.TimeDelta) + timeDelta = &duration + } + + passengerJourneys, err := s.Handler.GetPassengerJourneys( + r.Context(), + request.DepartureLat, + request.DepartureLng, + request.ArrivalLat, + request.ArrivalLng, + departureDate, + timeDelta, + request.DepartureRadius, + request.ArrivalRadius, + request.Count) + + if err != nil { + fmt.Println(err) + jsonResponse(w, err, http.StatusInternalServerError) + return + } + + jsonResponse(w, passengerJourneys, http.StatusOK) +} + +func (s *Server) getDriverRegularTrips(w http.ResponseWriter, r *http.Request) { + var request GetDriverRegularTripsRequest + + var decoder = schema.NewDecoder() + + if err := decoder.Decode(&request, r.URL.Query()); err != nil { + fmt.Println(err) + badRequest(w, fmt.Errorf("could not parse the request : %s", err)) + return + } + + var minDepartureDate *time.Time + if request.MinDepartureDate != nil { + d := time.Unix(*request.MinDepartureDate, 0) + minDepartureDate = &d + } + + var maxDepartureDate *time.Time + if request.MinDepartureDate != nil { + d := time.Unix(*request.MinDepartureDate, 0) + maxDepartureDate = &d + } + + var timeDelta *time.Duration + timeDelta = nil + if request.TimeDelta != nil { + duration := time.Duration(*request.TimeDelta) + timeDelta = &duration + } + + driverJourneys, err := s.Handler.GetDriverRegularTrips( + r.Context(), + request.DepartureLat, + request.DepartureLng, + request.ArrivalLat, + request.ArrivalLng, + request.DepartureTimeOfDay, + request.DepartureWeekDays, + timeDelta, + request.DepartureRadius, + request.ArrivalRadius, + minDepartureDate, + maxDepartureDate, + request.Count) + + if err != nil { + fmt.Println(err) + jsonResponse(w, err, http.StatusInternalServerError) + return + } + + jsonResponse(w, driverJourneys, http.StatusOK) +} + +func (s *Server) getPassengerRegularTrips(w http.ResponseWriter, r *http.Request) { + var request GetPassengerRegularTripsRequest + + var decoder = schema.NewDecoder() + + if err := decoder.Decode(&request, r.URL.Query()); err != nil { + fmt.Println(err) + badRequest(w, fmt.Errorf("could not parse the request : %s", err)) + return + } + + var minDepartureDate *time.Time + if request.MinDepartureDate != nil { + d := time.Unix(*request.MinDepartureDate, 0) + minDepartureDate = &d + } + + var maxDepartureDate *time.Time + if request.MinDepartureDate != nil { + d := time.Unix(*request.MinDepartureDate, 0) + maxDepartureDate = &d + } + + var timeDelta *time.Duration + timeDelta = nil + if request.TimeDelta != nil { + duration := time.Duration(*request.TimeDelta) + timeDelta = &duration + } + + passengerTrips, err := s.Handler.GetPassengerRegularTrips( + r.Context(), + request.DepartureLat, + request.DepartureLng, + request.ArrivalLat, + request.ArrivalLng, + request.DepartureTimeOfDay, + request.DepartureWeekDays, + timeDelta, + request.DepartureRadius, + request.ArrivalRadius, + minDepartureDate, + maxDepartureDate, + request.Count) + + if err != nil { + fmt.Println(err) + jsonResponse(w, err, http.StatusInternalServerError) + return + } + + jsonResponse(w, passengerTrips, http.StatusOK) +} + +func jsonResponse(w http.ResponseWriter, response any, statuscode int) { + w.WriteHeader(http.StatusBadRequest) + w.Header().Set("Content-Type", "application/json") + err := json.NewEncoder(w).Encode(response) + fmt.Println(err) +} + +func badRequest(w http.ResponseWriter, err error) { + jsonResponse(w, map[string]any{"error": err.Error()}, http.StatusBadRequest) +} diff --git a/trips.go b/trips.go new file mode 100644 index 0000000..0ae8424 --- /dev/null +++ b/trips.go @@ -0,0 +1,43 @@ +package standardcovoiturage + +import "time" + +type Trip struct { + Operator string `json:"operator"` + PassengerPickupLat float64 `json:"passengerPickupLat"` + PassengerPickupLng float64 `json:"passengerPickupLng"` + PassengerDropLat float64 `json:"passengerDropLat"` + PassengerDropLng float64 `json:"passengerDropLng"` + Duration time.Duration `json:"duration"` + PassengerPickupAddress *string `json:"passengerPickupAddress,omitempty"` + PassengerDropAddress *string `json:"passengerDropAddress,omitempty"` + Distance *int64 `json:"distance,omitempty"` + DriverDepartureLat *float64 `json:"driverDepartureLat,omitempty"` + DriverDepartureLng *float64 `json:"driverDepartureLng,omitempty"` + DriverArrivalLat *float64 `json:"driverArrivalLat,omitempty"` + DriverArrivalLng *float64 `json:"driverArrivalLng,omitempty"` + DriverDepartureAddress *string `json:"driverDepartureAddress,omitempty"` + DriverArrivalAddress *string `json:"driverArrivalAddress,omitempty"` + JourneyPolyline *string `json:"journeyPolyline,omitempty"` + //WebUrl *string `json:"webUrl,omitempty"` + Preferences *Preferences `json:"preferences,omitempty"` +} + +type DriverTrip struct { + Driver User `json:"driver"` + DepartureToPickupWalkingDistance *int64 `json:"departureToPickupWalkingDistance,omitempty"` + DepartureToPickupWalkingDuration *time.Duration `json:"departureToPickupWalkingDuration,omitempty"` + DepartureToPickupWalkingPolyline *string `json:"departureToPickupWalkingPolyline,omitempty"` + DropoffToArrivalWalkingDistance *int64 `json:"dropoffToArrivalWalkingDistance,omitempty"` + DropoffToArrivalWalkingDuration *time.Duration `json:"dropoffToArrivalWalkingDuration,omitempty"` + DropoffToArrivalWalkingPolyline *string `json:"dropoffToArrivalWalkingPolyline,omitempty"` + Car *Car `json:"car,omitempty"` + + Trip +} + +type PassengerTrip struct { + Passenger User `json:"passenger"` + + Trip +} diff --git a/users.go b/users.go new file mode 100644 index 0000000..cfeb6cd --- /dev/null +++ b/users.go @@ -0,0 +1,21 @@ +package standardcovoiturage + +type Gender int64 + +const ( + Female Gender = iota + Male + Other +) + +type User struct { + ID string `json:"id"` + Operator string `json:"operator"` + Alias string `json:"alias"` + FirstName *string `json:"firstName,omitempty"` + LastName *string `json:"lastName,omitempty"` + Grade *int64 `json:"grade,omitempty"` + Picture *string `json:"picture,omitempty"` + Gender *Gender `json:"gender,omitempty"` + VerifiedIdentity *bool `json:"verifiedIdentity,omitempty"` +}