This commit is contained in:
Arnaud Delcasse 2023-03-30 08:44:58 +02:00
parent bf6453b963
commit 0ae5730e7f
17 changed files with 305 additions and 44 deletions

4
go.mod
View File

@ -2,7 +2,7 @@ module git.coopgo.io/coopgo-platform/carpool-service
go 1.18
replace git.coopgo.io/coopgo-platform/routing-service => ../../coopgo-platform/routing-service/
// replace git.coopgo.io/coopgo-platform/routing-service => ../../coopgo-platform/routing-service/
replace git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss => ./interoperability/ocss/
@ -17,7 +17,7 @@ require (
)
require (
git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss v0.0.0-20230329105025-bbc682386a58 // indirect
git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss v0.0.0-20230329224518-bf6453b9639a // indirect
git.coopgo.io/coopgo-platform/routing-service v0.0.0-20230329165521-1442647132b9 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect

2
go.sum
View File

@ -38,6 +38,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss v0.0.0-20230329105025-bbc682386a58 h1:BgNJLsOZc71pGH87GqFqVhxWXEUB04Vv39EcxhzjD+8=
git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss v0.0.0-20230329105025-bbc682386a58/go.mod h1:sT9fl92Nb4K7rWsEeddGRbJKVi+84dnorDunIbnDYWk=
git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss v0.0.0-20230329224518-bf6453b9639a h1:4n7WKFSAdI9fOnF5MowJq6pY2zSwDwnAoId5xUt0m9U=
git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss v0.0.0-20230329224518-bf6453b9639a/go.mod h1:sT9fl92Nb4K7rWsEeddGRbJKVi+84dnorDunIbnDYWk=
git.coopgo.io/coopgo-platform/routing-service v0.0.0-20230329105109-a2dc346ed5b5 h1:7lhbgBk4oXTIK6T109IymgpoC2J4tHaU2O/rj/Y8M4s=
git.coopgo.io/coopgo-platform/routing-service v0.0.0-20230329105109-a2dc346ed5b5/go.mod h1:qKf4kan3/vJXVywIBHa4omSlxIOMYyR11xZrrE5v9D0=
git.coopgo.io/coopgo-platform/routing-service v0.0.0-20230329161053-d4ad6d1f4e33 h1:zm7lc0m0po6Tq/mjkJv7udnUEXZ+Z0swVO/anirbKmY=

64
handler/booking.go Normal file
View File

@ -0,0 +1,64 @@
package handler
import (
"errors"
"git.coopgo.io/coopgo-platform/carpool-service/internal"
"git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss"
"github.com/google/uuid"
"github.com/rs/zerolog/log"
)
func (h *CarpoolServiceHandler) Book(booking ocss.Booking) (*internal.Booking, error) {
futureBooking := internal.Booking{}
futureBooking.Roles = []string{}
if booking.Driver.Operator == "ridygo.fr" {
futureBooking.Roles = append(futureBooking.Roles, "driver")
previous_search_result, err := h.Storage.GetSearchResult("driver", booking.DriverJourneyID)
if err == nil {
futureBooking.DriverJourney = &internal.PlannedJourney{
Route: internal.RegularRoute(*previous_search_result.Route),
DepartureDate: previous_search_result.DepartureDate,
}
}
}
if booking.Passenger.Operator == "ridygo.fr" {
futureBooking.Roles = append(futureBooking.Roles, "passenger")
previous_search_result, err := h.Storage.GetSearchResult("passenger", booking.PassengerJourneyID)
if err == nil {
futureBooking.PassengerJourney = &internal.PlannedJourney{
Route: internal.RegularRoute(*previous_search_result.Route),
DepartureDate: previous_search_result.DepartureDate,
}
}
}
if len(futureBooking.Roles) == 0 {
return nil, errors.New("couldn't find the right operator id : \"ridygo.fr\" should be set for driver or passenger")
}
if _, err := uuid.Parse(booking.ID); err != nil {
return nil, errors.New("bookingid is not a valid uuid")
}
futureBooking.ID = booking.ID
futureBooking.BookingDefinition = booking
err := h.Storage.CreateBooking(futureBooking)
if err != nil {
log.Error().Err(err).Msg("issue creating booking in database")
return nil, err
}
return &futureBooking, nil
}
func (h *CarpoolServiceHandler) GetBooking(id string) (*internal.Booking, error) {
booking, err := h.Storage.GetBooking(id)
if err != nil {
log.Error().Err(err).Msg("issue retrieving booking in storage")
return nil, errors.New("booking id not found")
}
return booking, nil
}

View File

@ -4,7 +4,7 @@ import (
"errors"
"time"
"git.coopgo.io/coopgo-platform/carpool-service/helpers"
"git.coopgo.io/coopgo-platform/carpool-service/internal"
"git.coopgo.io/coopgo-platform/carpool-service/tiles"
"git.coopgo.io/coopgo-platform/routing-service/encoding/polylines"
"github.com/google/uuid"
@ -57,18 +57,18 @@ func (h *CarpoolServiceHandler) CreateRegularRoutes(routes []*geojson.FeatureCol
return nil
}
func (h *CarpoolServiceHandler) GetUserPlanning(userid string, minDepartureDate time.Time, maxDepartureDate time.Time) (map[string][]helpers.PlannedRouteSchedule, error) {
func (h *CarpoolServiceHandler) GetUserPlanning(userid string, minDepartureDate time.Time, maxDepartureDate time.Time) (map[string][]internal.PlannedRouteSchedule, error) {
log.Debug().
Str("user_id", userid).
Time("min_departure_date", minDepartureDate).
Time("max_departure_date", maxDepartureDate).
Msg("carpool service handler - GetUserPlanning")
results := map[string][]helpers.PlannedRouteSchedule{}
results := map[string][]internal.PlannedRouteSchedule{}
current_date := minDepartureDate
for current_date.Before(maxDepartureDate) {
results[current_date.Format("2006-01-02")] = []helpers.PlannedRouteSchedule{}
results[current_date.Format("2006-01-02")] = []internal.PlannedRouteSchedule{}
current_date = current_date.Add(24 * time.Hour)
}
@ -79,7 +79,7 @@ func (h *CarpoolServiceHandler) GetUserPlanning(userid string, minDepartureDate
}
for _, r := range routes {
rr := helpers.RegularRoute(*r)
rr := internal.RegularRoute(*r)
schedules, err := rr.PlannedJourneySchedules(minDepartureDate, maxDepartureDate)
if err != nil {
log.Error().Err(err)

View File

@ -4,21 +4,13 @@ import (
"time"
"git.coopgo.io/coopgo-platform/carpool-service/geoutils"
"git.coopgo.io/coopgo-platform/routing-service"
"git.coopgo.io/coopgo-platform/carpool-service/internal"
"git.coopgo.io/coopgo-platform/routing-service/encoding/polylines"
"github.com/paulmach/orb"
"github.com/paulmach/orb/geojson"
"github.com/rs/zerolog/log"
)
type SearchResult struct {
ID string
Route *geojson.FeatureCollection
DepartureDate time.Time
Itinerary *routing.Route
}
func (h *CarpoolServiceHandler) GetDriverJourneys(departure orb.Point, arrival orb.Point, departureRadius *float64, arrivalRadius *float64, minDate time.Time, maxDate time.Time, count *int64) ([]SearchResult, error) {
func (h *CarpoolServiceHandler) GetDriverJourneys(departure orb.Point, arrival orb.Point, departureRadius *float64, arrivalRadius *float64, minDate time.Time, maxDate time.Time, count *int64) ([]internal.SearchResult, error) {
log.Debug().
Any("departure", departure).
@ -61,7 +53,7 @@ func (h *CarpoolServiceHandler) GetDriverJourneys(departure orb.Point, arrival o
candidate_routes := tileset.GetTiledRoutes()
journeys := []SearchResult{}
journeys := []internal.SearchResult{}
counted := int64(0)
for _, r := range candidate_routes {
@ -81,7 +73,7 @@ func (h *CarpoolServiceHandler) GetDriverJourneys(departure orb.Point, arrival o
log.Error().Err(err).Msg("error getting route with viapoints")
continue
}
journeys = append(journeys, SearchResult{
journeys = append(journeys, internal.SearchResult{
ID: r.ID,
Route: r.Route,
DepartureDate: r.DepartureDate,
@ -94,10 +86,16 @@ func (h *CarpoolServiceHandler) GetDriverJourneys(departure orb.Point, arrival o
}
}
err = h.Storage.StoreSearchResults("driver", journeys)
if err != nil {
log.Error().Err(err).Msg("Error saving search results")
return nil, err
}
return journeys, nil
}
func (h *CarpoolServiceHandler) GetPassengerJourneys(departure orb.Point, arrival orb.Point, departureRadius *float64, arrivalRadius *float64, minDate time.Time, maxDate time.Time, count *int64) ([]SearchResult, error) {
func (h *CarpoolServiceHandler) GetPassengerJourneys(departure orb.Point, arrival orb.Point, departureRadius *float64, arrivalRadius *float64, minDate time.Time, maxDate time.Time, count *int64) ([]internal.SearchResult, error) {
log.Debug().
Any("departure", departure).
@ -155,7 +153,7 @@ func (h *CarpoolServiceHandler) GetPassengerJourneys(departure orb.Point, arriva
candidate_routes := tileset.GetTiledRoutes()
journeys := []SearchResult{}
journeys := []internal.SearchResult{}
counted := int64(0)
for _, r := range candidate_routes {
@ -173,7 +171,7 @@ func (h *CarpoolServiceHandler) GetPassengerJourneys(departure orb.Point, arriva
log.Error().Err(err).Msg("error getting route with viapoints")
continue
}
journeys = append(journeys, SearchResult{
journeys = append(journeys, internal.SearchResult{
ID: r.ID,
Route: r.Route,
DepartureDate: r.DepartureDate,
@ -186,6 +184,12 @@ func (h *CarpoolServiceHandler) GetPassengerJourneys(departure orb.Point, arriva
}
}
err = h.Storage.StoreSearchResults("passenger", journeys)
if err != nil {
log.Error().Err(err).Msg("Error saving search results")
return nil, err
}
return journeys, nil
}

11
internal/booking.go Normal file
View File

@ -0,0 +1,11 @@
package internal
import "git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss"
type Booking struct {
ID string `bson:"_id"`
Roles []string // At least one of ["driver", "passenger"]
BookingDefinition ocss.Booking
DriverJourney *PlannedJourney
PassengerJourney *PlannedJourney
}

View File

@ -1,4 +1,4 @@
package helpers
package internal
import "time"

View File

@ -1,4 +1,4 @@
package helpers
package internal
import (
"errors"

View File

@ -0,0 +1,15 @@
package internal
import (
"time"
"git.coopgo.io/coopgo-platform/routing-service"
"github.com/paulmach/orb/geojson"
)
type SearchResult struct {
ID string `bson:"_id"`
Route *geojson.FeatureCollection
DepartureDate time.Time
Itinerary *routing.Route
}

View File

@ -1,6 +1,10 @@
package ocss
import "time"
import (
"bytes"
"encoding/json"
"time"
)
type BookingStatus int64
@ -12,11 +16,45 @@ const (
BookingValidated
)
var bookingStatustoID = map[string]BookingStatus{
"WAITING_CONFIRMATION": BookingWaitingConfirmation,
"CONFIRMED": BookingConfirmed,
"CANCELLED": BookingCancelled,
"COMPLETED_PENDING_VALIDATION": BookingCompletedPendingValidation,
"VALIDATED": BookingValidated,
}
var bookingStatustoString = map[BookingStatus]string{
BookingWaitingConfirmation: "WAITING_CONFIRMATION",
BookingConfirmed: "CONFIRMED",
BookingCancelled: "CANCELLED",
BookingCompletedPendingValidation: "COMPLETED_PENDING_VALIDATION",
BookingValidated: "VALIDATED",
}
func (s BookingStatus) MarshalJSON() ([]byte, error) {
buffer := bytes.NewBufferString(`"`)
buffer.WriteString(bookingStatustoString[s])
buffer.WriteString(`"`)
return buffer.Bytes(), nil
}
func (bs *BookingStatus) UnmarshalJSON(b []byte) error {
var j string
err := json.Unmarshal(b, &j)
if err != nil {
return err
}
// Note that if the string cannot be found then it will be set to the zero value, 'Created' in this case.
*bs = bookingStatustoID[j]
return nil
}
type Booking struct {
ID string `json:"id"` // TODO check uuidv4
Driver User `json:"driver"`
ID string `json:"id",bson:"_id"` // TODO check uuidv4
Driver User `json:"driver"`
Passenger User `json:"passenger"`
PassengerPickupDate time.Time `json:"passengerPickupDate"`
PassengerPickupDate JSONTime `json:"passengerPickupDate"`
PassengerPickupLat float64 `json:"passengerPickupLat"`
PassengerPickupLng float64 `json:"passengerPickupLng"`
PassengerDropLat float64 `json:"passengerDropLat"`
@ -28,7 +66,7 @@ type Booking struct {
Duration *time.Duration `json:"duration,omitempty"`
WebUrl *string `json:"webUrl,omitempty"`
Price Price `json:"price"`
Car *Car `json:"car"`
Car *Car `json:"car,omitempty"`
DriverJourneyID string `json:"driverJourneyId"`
PassengerJourneyID string `json:"passengerJourneyId"`
}

View File

@ -1,6 +1,7 @@
package ocss
import (
"encoding/json"
"fmt"
"time"
)
@ -31,6 +32,22 @@ func (t JSONTime) MarshalJSON() ([]byte, error) {
return []byte(stamp), nil
}
func (t *JSONTime) UnmarshalJSON(b []byte) error {
var timestamp int64
err := json.Unmarshal(b, &timestamp)
if err != nil {
return err
}
parsed := time.Unix(timestamp, 0)
if err != nil {
return err
}
jsontime := JSONTime(parsed)
*t = jsontime
return nil
}
type JourneySchedule struct {
ID *string `json:"id,omitempty"`
PassengerPickupDate JSONTime `json:"passengerPickupDate"`

View File

@ -1,5 +1,10 @@
package ocss
import (
"bytes"
"encoding/json"
)
type PriceType int64
const (
@ -8,6 +13,36 @@ const (
Unknown
)
var priceTypeToID = map[string]PriceType{
"FREE": Free,
"PAYING": Paying,
"UNKNOWN": Unknown,
}
var priceTypeToString = map[PriceType]string{
Free: "FREE",
Paying: "PAYING",
Unknown: "UNKNOWN",
}
func (s PriceType) MarshalJSON() ([]byte, error) {
buffer := bytes.NewBufferString(`"`)
buffer.WriteString(priceTypeToString[s])
buffer.WriteString(`"`)
return buffer.Bytes(), nil
}
func (bs *PriceType) UnmarshalJSON(b []byte) error {
var j string
err := json.Unmarshal(b, &j)
if err != nil {
return err
}
// Note that if the string cannot be found then it will be set to the zero value, 'Created' in this case.
*bs = priceTypeToID[j]
return nil
}
type Price struct {
Type *PriceType `json:"type,omitempty"`
Amount *float64 `json:"amount,omitempty"`

View File

@ -418,13 +418,15 @@ func (s *Server) patchBookings(w http.ResponseWriter, bookingId string, r *http.
func (s *Server) getBookings(w http.ResponseWriter, bookingId string, r *http.Request) {
log.Debug().Str("booking id", bookingId).Msg("GetBooking request")
booking, err := s.Handler.GetBookings(
r.Context(),
bookingId,
)
if err != nil {
log.Error().Err(err).Msg("error in PatchBookings")
log.Error().Err(err).Msg("error in GetBookings")
jsonError(w, err, http.StatusInternalServerError)
return
}

View File

@ -5,14 +5,27 @@ import (
"errors"
"git.coopgo.io/coopgo-platform/carpool-service/interoperability/ocss"
"github.com/rs/zerolog/log"
)
func (s *OCSSApiService) PostBookings(ctx context.Context, booking ocss.Booking) (*ocss.Booking, error) {
return nil, errors.New("method not implmeented - PostBookings")
result, err := s.Handler.Book(booking)
if err != nil {
log.Error().Err(err).Msg("issue in booking")
return nil, err
}
return &result.BookingDefinition, nil
}
func (s *OCSSApiService) PatchBookings(ctx context.Context, bookingId string, status ocss.BookingStatus, message *string) error {
return errors.New("method not implmeented - PatchBooking")
return errors.New("booking not found")
}
func (s *OCSSApiService) GetBookings(ctx context.Context, bookingId string) (*ocss.Booking, error) {
return nil, errors.New("method not implmeented - GetBooking")
result, err := s.Handler.GetBooking(bookingId)
if err != nil {
log.Error().Err(err).Msg("issue retrieving booking in handler")
return nil, err
}
return &result.BookingDefinition, nil
}

View File

@ -3,7 +3,9 @@ package storage
import (
"context"
"encoding/json"
"fmt"
"git.coopgo.io/coopgo-platform/carpool-service/internal"
"github.com/paulmach/orb/geojson"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
@ -21,12 +23,14 @@ type MongoDBStorage struct {
func NewMongoDBStorage(cfg *viper.Viper) (MongoDBStorage, error) {
var (
mongodb_host = cfg.GetString("storage.db.mongodb.host")
mongodb_port = cfg.GetString("storage.db.mongodb.port")
mongodb_dbname = cfg.GetString("storage.db.mongodb.db_name")
mongodb_regular_routes = cfg.GetString("storage.db.mongodb.collections.regular_routes")
mongodb_punctual_routes = cfg.GetString("storage.db.mongodb.collections.punctual_routes")
mongodb_bookings = cfg.GetString("storage.db.mongodb.collections.bookings")
mongodb_host = cfg.GetString("storage.db.mongodb.host")
mongodb_port = cfg.GetString("storage.db.mongodb.port")
mongodb_dbname = cfg.GetString("storage.db.mongodb.db_name")
mongodb_regular_routes = cfg.GetString("storage.db.mongodb.collections.regular_routes")
mongodb_punctual_routes = cfg.GetString("storage.db.mongodb.collections.punctual_routes")
mongodb_bookings = cfg.GetString("storage.db.mongodb.collections.bookings")
mongodb_driver_candidate_journeys = cfg.GetString("storage.db.mongodb.collections.driver_candidate_journeys")
mongodb_passenger_candidate_journeys = cfg.GetString("storage.db.mongodb.collections.passenger_candidate_journeys")
)
client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://" + mongodb_host + ":" + mongodb_port))
@ -44,9 +48,11 @@ func NewMongoDBStorage(cfg *viper.Viper) (MongoDBStorage, error) {
Client: client,
DbName: mongodb_dbname,
Collections: map[string]string{
"regular_routes": mongodb_regular_routes,
"punctual_routes": mongodb_punctual_routes,
"bookings": mongodb_bookings,
"regular_routes": mongodb_regular_routes,
"punctual_routes": mongodb_punctual_routes,
"bookings": mongodb_bookings,
"driver_candidate_journeys": mongodb_driver_candidate_journeys,
"passenger_candidate_journeys": mongodb_passenger_candidate_journeys,
},
}
@ -209,6 +215,53 @@ func (s MongoDBStorage) GetPassengerRegularRoutesForTile(day string, gridId int6
return results, nil
}
func (s MongoDBStorage) StoreSearchResults(driverOrPassenger string, searchresults []internal.SearchResult) error {
log.Debug().Msg("Storage - CreateRegularRoutes")
documents := []any{}
for _, sr := range searchresults {
documents = append(documents, sr)
}
collection := s.Client.Database(s.DbName).Collection(s.Collections[fmt.Sprintf("%s_candidate_journeys", driverOrPassenger)])
if _, err := collection.InsertMany(context.TODO(), documents); err != nil {
return err
}
return nil
}
func (s MongoDBStorage) GetSearchResult(driverOrPassenger, id string) (searchResult *internal.SearchResult, err error) {
collection := s.Client.Database(s.DbName).Collection(s.Collections[fmt.Sprintf("%s_candidate_journeys", driverOrPassenger)])
err = collection.FindOne(context.TODO(), bson.M{"_id": id}).Decode(searchResult)
return
}
func (s MongoDBStorage) CreateBooking(booking internal.Booking) error {
collection := s.Client.Database(s.DbName).Collection(s.Collections["bookings"])
_, err := collection.InsertOne(context.TODO(), booking)
if err != nil {
return err
}
return nil
}
func (s MongoDBStorage) GetBooking(id string) (booking *internal.Booking, err error) {
var b internal.Booking
log.Debug().Str("booking id", id).Msg("get booking in DB")
collection := s.Client.Database(s.DbName).Collection(s.Collections["bookings"])
err = collection.FindOne(context.TODO(), bson.M{"_id": id}).Decode(&b)
if err != nil {
log.Error().Err(err).Msg("error")
return nil, err
}
return &b, nil
}
// func (s MongoDBStorage) CreatePassengerRegularTrips(trips []*geojson.FeatureCollection) error {
// log.Debug().Msg("Storage - CreatePassengerRegularTrips")

View File

@ -3,6 +3,7 @@ package storage
import (
"fmt"
"git.coopgo.io/coopgo-platform/carpool-service/internal"
"github.com/paulmach/orb/geojson"
"github.com/spf13/viper"
)
@ -12,6 +13,12 @@ type Storage interface {
GetUserRegularRoutes(userid string) ([]*geojson.FeatureCollection, error)
GetDriverRegularRoutesForTile(day string, gridId int64) ([]*geojson.FeatureCollection, error)
GetPassengerRegularRoutesForTile(day string, gridId int64) ([]*geojson.FeatureCollection, error)
StoreSearchResults(string, []internal.SearchResult) error
GetSearchResult(driverOrPassenger, id string) (*internal.SearchResult, error)
CreateBooking(internal.Booking) error
GetBooking(id string) (*internal.Booking, error)
}
func NewStorage(cfg *viper.Viper) (Storage, error) {

View File

@ -5,7 +5,7 @@ import (
"strings"
"time"
"git.coopgo.io/coopgo-platform/carpool-service/helpers"
"git.coopgo.io/coopgo-platform/carpool-service/internal"
"github.com/google/uuid"
"github.com/paulmach/orb/geojson"
"github.com/rs/zerolog/log"
@ -62,7 +62,7 @@ func (h *TilesHandler) GetTile(driverOrPassenger string, date time.Time, gridid
for _, r := range routes {
rr := helpers.RegularRoute(*r)
rr := internal.RegularRoute(*r)
schedules, err := rr.PlannedJourneySchedules(date0h, date24h)
if err != nil {
log.Error().Err(err)