Initial commit
This commit is contained in:
		
						commit
						8bb8d90a88
					
				|  | @ -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. | ||||||
|  | 
 | ||||||
|  | @ -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"` | ||||||
|  | } | ||||||
|  | @ -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"` | ||||||
|  | } | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | package standardcovoiturage | ||||||
|  | 
 | ||||||
|  | type Car struct { | ||||||
|  | 	Model *string `json:"model,omitempty"` | ||||||
|  | 	Brand *string `json:"brand,omitempty"` | ||||||
|  | } | ||||||
|  | @ -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. | ||||||
|  | @ -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 | ||||||
|  | ) | ||||||
|  | @ -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= | ||||||
|  | @ -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
 | ||||||
|  | // }
 | ||||||
|  | @ -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 | ||||||
|  | ) | ||||||
|  | @ -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= | ||||||
|  | @ -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"` | ||||||
|  | } | ||||||
|  | @ -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"` | ||||||
|  | } | ||||||
|  | @ -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"` | ||||||
|  | } | ||||||
|  | @ -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"` | ||||||
|  | } | ||||||
|  | @ -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) | ||||||
|  | } | ||||||
|  | @ -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 | ||||||
|  | } | ||||||
|  | @ -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"` | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue