package externalroute import ( "fmt" "strings" "sync" "time" "bitbucket.org/nemt/nemt-portal-api/application/applicationservice" "bitbucket.org/nemt/nemt-portal-api/application/notificationservice" "bitbucket.org/nemt/nemt-portal-api/application/tncservice" "bitbucket.org/nemt/nemt-portal-api/application/viewmodel" "bitbucket.org/nemt/nemt-portal-api/infra/config" "bitbucket.org/nemt/nemt-portal-api/server/router/routeutils" "github.com/labstack/echo" ) var ( instance *controller once sync.Once ) type controller struct { cfg *config.Config svc *applicationservice.Service tnc *tncservice.Service notification *notificationservice.Service } func controllerInstance(cfg *config.Config, svc *applicationservice.Service, tnc *tncservice.Service, notification *notificationservice.Service) *controller { once.Do(func() { instance = &controller{ cfg: cfg, svc: svc, tnc: tnc, notification: notification, } }) return instance } func (c *controller) getDriverNotification(ride viewmodel.Ride, notificationType string, subject string, message string, to string, from string) viewmodel.Notification { retVal := viewmodel.Notification{ Type: notificationType, Message: message, Subject: subject, Ride: ride, User: ride.User, CreatedUser: ride.CreatedUser, To: to, From: from, } return retVal } func (c *controller) handleCancel(ctx echo.Context) error { var rideUUID = ctx.Param("ride_uuid") var userUUID = ctx.Param("user_uuid") ride, err := c.svc.Rides.GetByUUIDAndUserUUID(rideUUID, userUUID) if err != nil { return routeutils.HandleAPIError(ctx, err) } lyftRide := viewmodel.RideRequest{RideID: ride.InternalID} if ride.Status.Key == "scheduled" && !strings.Contains(ride.InternalID, "s_") { lyftRide.RideID = "s_" + ride.InternalID } if ride.CreatedUser.ID != c.cfg.LyftProd.UserUUID { if err = c.tnc.Lyft.CancelRide(lyftRide); err != nil { if err.Error() != "ride_not_found" { fmt.Println("Error to cancel with Lyft: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } } } else { fmt.Println("In Production") if err = c.tnc.LyftProd.CancelRide(lyftRide); err != nil { fmt.Println("Error to cancel with Lyft: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } } err = c.svc.Rides.UpdateStatus(rideUUID, "canceled") if err != nil { fmt.Println("Error: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } // ride.Status.Key = "canceled" // err = c.svc.Notification.SendNotification(ride.Status.Key, ride, viewmodel.RideRequest{}) // if err != nil { // fmt.Println("Error to notify: ", err.Error()) // } ctx.Response().Header().Set("Content-Type", "application/json") return routeutils.ResponseNoContent(ctx, nil) } func (c *controller) handleMessage(ctx echo.Context) error { var rideUUID = ctx.Param("ride_uuid") var userUUID = ctx.Param("user_uuid") ride, err := c.svc.Rides.GetByUUIDAndUserUUID(rideUUID, userUUID) if err != nil { return routeutils.HandleAPIError(ctx, err) } message := make(map[string]string) err = ctx.Bind(&message) if err != nil || message["message"] == "" { return routeutils.ResponseAPIValidationError(ctx, "message body param is mandatory") } if err != nil || message["to"] == "" { return routeutils.ResponseAPIValidationError(ctx, "to param is mandatory") } notifications := make([]viewmodel.Notification, 0) if message["to"] == "driver" { notifications = append(notifications, c.getDriverNotification(ride, "sms", "A message to driver", message["message"], ride.Driver.PhoneNumber, *ride.User.PhoneNumber)) } else { notifications = append(notifications, c.getDriverNotification(ride, "sms", "A message to dispatcher", message["message"], *ride.CreatedUser.PhoneNumber, *ride.User.PhoneNumber)) notifications = append(notifications, c.getDriverNotification(ride, "email", "A message to dispatcher", message["message"], *ride.CreatedUser.Email, *ride.User.Email)) } notifications, err = c.svc.Notification.SendNotifications(notifications) if err != nil { return routeutils.HandleAPIError(ctx, err) } return routeutils.ResponseAPIOK(ctx, notifications) } func (c *controller) handle(ctx echo.Context) error { var rideUUID = ctx.Param("ride_uuid") var userUUID = ctx.Param("user_uuid") ride, err := c.svc.Rides.GetByUUIDAndUserUUID(rideUUID, userUUID) if err != nil { fmt.Println("Error: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } if ride.Status.Key == "accepted" || ride.Status.Key == "pickedUp" || ride.Status.Key == "arrived" { var lyftRide viewmodel.RideRequest var err error if ride.CreatedUser.ID != c.cfg.LyftProd.UserUUID { lyftRide, err = c.tnc.Lyft.GetRideDetails(viewmodel.RideRequest{RideID: ride.InternalID}) } else { fmt.Println("In Production") lyftRide, err = c.tnc.LyftProd.GetRideDetails(viewmodel.RideRequest{RideID: ride.InternalID}) } if err != nil { fmt.Println("Error: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } ride.Route.Location = ride.Route.Origin ride.Route.Location.Address = "" ride.Route.Location.Name = "" switch ride.Status.Key { case "accepted": if lyftRide.Origin.ETASeconds != nil { ride.Route.ETA = *lyftRide.Origin.ETASeconds } else { ride.Route.ETA = 0 if c.cfg.App.Debug { ride.Route.ETA = 350 } } case "pickedUp": case "arrived": if lyftRide.Destination.ETASeconds != nil { ride.Route.ETA = *lyftRide.Destination.ETASeconds } else { ride.Route.ETA = 0 if c.cfg.App.Debug { ride.Route.ETA = 350 } } } if lyftRide.Location.Latitude != 0 && lyftRide.Location.Longitude != 0 { ride.Route.Location.Latitude = lyftRide.Location.Latitude ride.Route.Location.Longitude = lyftRide.Location.Longitude ride.Route.Location.Bearing = lyftRide.Location.Bearing } } ride.InternalID = "" ride.User.Gender = nil ride.User.Email = nil ride.User.PhoneNumber = nil ride.Passenger = viewmodel.UserLyft{} // ride.Visit = viewmodel.Visit{ // ExternalID: ride.Visit.ExternalID, // } ride.CreatedUser = viewmodel.User{} return routeutils.ResponseAPIOK(ctx, ride) } func (c *controller) handleReady(ctx echo.Context) error { var rideUUID = ctx.Param("ride_uuid") var userUUID = ctx.Param("user_uuid") ride, err := c.svc.Rides.GetByUUIDAndUserUUID(rideUUID, userUUID) if err != nil { fmt.Println("Error: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } authUser, err := c.svc.Users.GetByUUID(ride.CreatedUser.ID, "") if err != nil { fmt.Println("Error: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } var nextRide viewmodel.Ride if ride.TripType.Key == "from_visit_call" && ride.Status.Key == "willCall" { nextRide = ride } else if ride.Visit.TripType.Key == "roundtrip_call" && ride.TripType.Key == "to_visit" { roundTripRide, err := c.svc.Rides.GetByVisitUUIDAndTripType(ride.Visit.UUID, "from_visit_call", authUser) if err != nil { fmt.Println("Error to get next ride: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } nextRide = roundTripRide } else { fmt.Println("Error on get next ride ") return routeutils.ResponseAPINotFoundError(ctx) } var lyftRide viewmodel.RideRequest if ride.CreatedUser.ID != c.cfg.LyftProd.UserUUID { lyftRide, err = c.tnc.Lyft.GetRideDetails(viewmodel.RideRequest{RideID: ride.InternalID}) } else { fmt.Println("In Production") lyftRide, err = c.tnc.LyftProd.GetRideDetails(viewmodel.RideRequest{RideID: ride.InternalID}) } if err != nil { fmt.Println("Error: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } lyftRide.RideID = "" lyftRide.Destination = ride.Route.Destination lyftRide.Origin = ride.Route.Origin name := nextRide.User.Name names := strings.Split(name, " ") lyftRide.Passenger.FirstName = names[0] lyftRide.Passenger.LastName = " " lyftRide.Passenger.PhoneNumber = *nextRide.User.PhoneNumber lyftRide.RideType = "lyft" if c.cfg.LyftProd.UserUUID != nextRide.CreatedUser.ID { lyftRide, err = c.tnc.Lyft.RequestRide(lyftRide) } else { fmt.Println("In Production") lyftRide, err = c.tnc.LyftProd.RequestRide(lyftRide) } if err != nil { return routeutils.HandleAPIError(ctx, err) } currentTime := time.Now() lyftRide.PickupTime = ¤tTime lyftRide.ReturnTime = ¤tTime nextRide.PickupTime = ¤tTime nextRide, err = c.svc.Rides.UpdateNewRide(nextRide, lyftRide, authUser) if err != nil { fmt.Println("Error: ", err.Error()) return routeutils.HandleAPIError(ctx, err) } go func() { err = c.svc.Notification.SendNotification(lyftRide.Status, nextRide, lyftRide) if err != nil { fmt.Println("Error to notify user: ", err.Error()) } }() return routeutils.ResponseAPIOK(ctx, nextRide) }