package applicationservice import ( "fmt" "net/http" "reflect" "strings" "sync" "time" "github.com/pquerna/ffjson/ffjson" "bitbucket.org/nemt/nemt-portal-api/application/entitymapping" "bitbucket.org/nemt/nemt-portal-api/application/notificationservice" "bitbucket.org/nemt/nemt-portal-api/application/viewmodel" "bitbucket.org/nemt/nemt-portal-api/domain/service" "bitbucket.org/nemt/nemt-portal-api/infra/config" "github.com/gorilla/websocket" "google.golang.org/api/googleapi/transport" urlshortener "google.golang.org/api/urlshortener/v1" gomail "gopkg.in/gomail.v2" redis "gopkg.in/redis.v5" ) const ( NotificationTypeEmail = "email" NOtificationTypeSMS = "sms" NotificationTypeAPP = "app" StatusPending = "pending" StatusAccepted = "accepted" StatusArrived = "arrived" StatusPickedUp = "pickedUp" StatusDroppedOff = "droppedOff" StatusCanceled = "canceled" StatusScheduled = "scheduled" StatusWillCall = "willCall" hourMinuteAMPM = "03:04 PM" ) // providerService holds methods to provider application service type notificationService struct { svc *service.Service mapEntity *entitymapping.Mapper notification *notificationservice.Service cfg *config.Config store *Store pubSub *redis.PubSub redisConn *redis.Client } // newProviderService returns a providerService instance func newNotificationService(svc *service.Service, mapper *entitymapping.Mapper, notification *notificationservice.Service, cfg *config.Config) *notificationService { redisClient := redis.NewFailoverClient(&redis.FailoverOptions{ MasterName: "master01", SentinelAddrs: []string{fmt.Sprintf("%s:%v", cfg.Cache.Server, cfg.Cache.Port)}, Password: cfg.Cache.Pass, DB: cfg.Cache.DB, }) pubSub, err := redisClient.Subscribe() if err != nil { panic(err) } return ¬ificationService{ svc: svc, mapEntity: mapper, notification: notification, cfg: cfg, redisConn: redisClient, store: &Store{ Users: make(map[string]*UserNotification), redisClient: redisClient, pubSub: pubSub, }, pubSub: pubSub, } } func (s *notificationService) secondsToMinutes(inSeconds int64) string { minutes := inSeconds / 60 seconds := inSeconds % 60 str := fmt.Sprintf("%v minutes", minutes) if seconds > 0 { str += fmt.Sprintf(" %v seconds", seconds) } return str } func (s *notificationService) getReadyURLShortened(ride viewmodel.Ride) (string, error) { const ( url = "https://portal.bcbsinstitute.com/#/ride/%s/%s/ready" ) svc, err := urlshortener.New(&http.Client{ Transport: &transport.APIKey{Key: s.cfg.GoogleShortener.APIKey}, }) if err != nil { return "", err } userURL := fmt.Sprintf(url, ride.UUID, ride.User.ID) shortURL, err := svc.Url.Insert(&urlshortener.Url{ Kind: "urlshortener#url", // Not really needed LongUrl: userURL, }).Do() if err != nil { return "", err } return shortURL.Id, nil } func (s *notificationService) getURLShortened(ride viewmodel.Ride) (string, error) { const ( url = "https://portal.bcbsinstitute.com/#/ride/%s/%s" ) svc, err := urlshortener.New(&http.Client{ Transport: &transport.APIKey{Key: s.cfg.GoogleShortener.APIKey}, }) if err != nil { return "", err } userURL := fmt.Sprintf(url, ride.UUID, ride.User.ID) shortURL, err := svc.Url.Insert(&urlshortener.Url{ Kind: "urlshortener#url", // Not really needed LongUrl: userURL, }).Do() if err != nil { return "", err } return shortURL.Id, nil } func (s *notificationService) SendNotification(state string, ride viewmodel.Ride, lyftRide viewmodel.RideRequest) error { notifications := make([]viewmodel.Notification, 0) url, err := s.getURLShortened(ride) if err != nil { fmt.Println("Error to short url: ", err) } loc, _ := time.LoadLocation("America/Chicago") switch state { case StatusWillCall: visitTime := ride.VisitDate.In(loc).Format(hourMinuteAMPM) visitDate := ride.VisitDate.In(loc).Format("01/02/2006") messageMemberSMS := fmt.Sprintf(MessageSMSWillCallMember, visitTime, ride.Route.Destination.Name, visitDate) messageMemberSMS += "\n\n" + MessageSMSReplyOrCancel messageMemberEmail := fmt.Sprintf(MessageEmailWillCallMember, visitTime, ride.Route.Destination.Name, visitDate) //messageMemberApp := fmt.Sprintf(MessageAppPendingMember, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) urlReady, err := s.getReadyURLShortened(ride) if err != nil { fmt.Println(err) } messageMemberSMS += "\n" + fmt.Sprintf(MessageSMSIAmReadyOrClick, ride.Route.Destination.Name, urlReady) messageMemberEmail += "\n" + fmt.Sprintf(MessageEmailIAmReadyOrClick, ride.Route.Destination.Name, urlReady) messageDispatcherSMS := fmt.Sprintf(MessageSMSWillCallDispatcher, ride.User.Name, visitTime, ride.Route.Destination.Name, visitDate) messageDispatcherSMS += "\n\n" + MessageSMSReplyOrCancel messageDispatcherEmail := fmt.Sprintf(MessageEmailWillCallDispatcher, ride.User.Name, visitTime, ride.Route.Destination.Name, visitDate) //messageDispatcherApp := fmt.Sprintf(MessageAppPendingDispatcher, ride.User.Name, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) notifications = append(notifications, s.GetNotification(ride, "sms", MessageSMSWillCallMemberTitle, messageMemberSMS, false, "")) notifications = append(notifications, s.GetNotification(ride, "sms", fmt.Sprintf(MessageSMSWillCallDispatcherTitle, ride.User.Name), messageDispatcherSMS, true, "")) notifications = append(notifications, s.GetNotification(ride, "email", MessageEmailWillCallMemberTitle, messageMemberEmail, false, "")) notifications = append(notifications, s.GetNotification(ride, "email", fmt.Sprintf(MessageEmailWillCallDispatcherTitle, ride.User.Name), messageDispatcherEmail, true, "")) notifications = append(notifications, s.GetNotification(ride, "app", "Ride Scheduled "+strings.ToLower(ride.TripType.Value), fmt.Sprintf(MessageAppWillCallMemberTitle, ride.Status.Value, ride.Route.Destination.Address), false, "ride")) notifications = append(notifications, s.GetNotification(ride, "app", "Ride Scheduled "+strings.ToLower(ride.TripType.Value), fmt.Sprintf(MessageAppWillCallDispatcherTitle, ride.Status.Value, ride.Route.Destination.Address), true, "ride")) case StatusScheduled: dateFormat := ride.PickupTime.In(loc).Format("01/02/2006 03:04 PM") visitTime := ride.VisitDate.In(loc).Format(hourMinuteAMPM) pickupTime := ride.PickupTime.In(loc).Format(hourMinuteAMPM) visitDate := ride.VisitDate.In(loc).Format("01/02/2006") if ride.TripType.Key == "from_visit" && lyftRide.ReturnTime != nil { dateFormat = lyftRide.ReturnTime.In(loc).Format("01/02/2006 03:04 PM") pickupTime = lyftRide.ReturnTime.In(loc).Format(hourMinuteAMPM) } messageMemberSMS := fmt.Sprintf(MessageSMSScheduledMember, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) messageMemberSMS += "\n\n" + MessageSMSReplyOrCancel messageMemberEmail := fmt.Sprintf(MessageEmailScheduledMember, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) //messageMemberApp := fmt.Sprintf(MessageAppPendingMember, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) messageDispatcherSMS := fmt.Sprintf(MessageSMSScheduledDispatcher, ride.User.Name, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) messageDispatcherSMS += "\n\n" + MessageSMSReplyOrCancel messageDispatcherEmail := fmt.Sprintf(MessageEmailScheduledDispatcher, ride.User.Name, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) //messageDispatcherApp := fmt.Sprintf(MessageAppPendingDispatcher, ride.User.Name, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) notifications = append(notifications, s.GetNotification(ride, "sms", fmt.Sprintf(MessageSMSScheduledMemberTitle, dateFormat), messageMemberSMS, false, "")) notifications = append(notifications, s.GetNotification(ride, "sms", fmt.Sprintf(MessageSMSScheduledDispatcherTitle, ride.User.Name, dateFormat), messageDispatcherSMS, true, "")) notifications = append(notifications, s.GetNotification(ride, "email", fmt.Sprintf(MessageEmailScheduledMemberTitle, dateFormat), messageMemberEmail, false, "")) notifications = append(notifications, s.GetNotification(ride, "email", fmt.Sprintf(MessageEmailScheduledDispatcherTitle, ride.User.Name, dateFormat), messageDispatcherEmail, true, "")) // if ride.TripType.Key == "to_visit" { notifications = append(notifications, s.GetNotification(ride, "app", fmt.Sprintf("%s | "+strings.ToLower(ride.TripType.Value), ride.Status.Value), fmt.Sprintf(MessageAppScheduledMemberTitle, pickupTime, ride.Route.Origin.Name), false, "ride")) notifications = append(notifications, s.GetNotification(ride, "app", fmt.Sprintf("%s | "+strings.ToLower(ride.TripType.Value), ride.Status.Value), fmt.Sprintf(MessageAppScheduledDispatcherTitle, pickupTime, ride.Route.Origin.Name), true, "ride")) // } else if ride.TripType.Key == "from_visit" { // notifications = append(notifications, s.GetNotification(ride, "app", fmt.Sprintf("Ride %s "+strings.ToLower(ride.TripType.Value), StatusScheduled), fmt.Sprintf(MessageAppScheduledMemberTitle, pickupTime, ride.Route.Destination.Name), false, "ride")) // notifications = append(notifications, s.GetNotification(ride, "app", fmt.Sprintf("Ride %s "+strings.ToLower(ride.TripType.Value), StatusScheduled), fmt.Sprintf(MessageAppScheduledDispatcherTitle, pickupTime, ride.Route.Destination.Name), true, "ride")) // } case StatusPending: dateFormat := ride.PickupTime.In(loc).Format("01/02/2006 03:04 PM") visitTime := ride.VisitDate.In(loc).Format(hourMinuteAMPM) pickupTime := ride.PickupTime.In(loc).Format(hourMinuteAMPM) visitDate := ride.VisitDate.In(loc).Format("01/02/2006") messageMemberSMS := fmt.Sprintf(MessageSMSPendingMember, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) messageMemberSMS += "\n\n" + MessageSMSReplyOrCancel messageMemberEmail := fmt.Sprintf(MessageEmailPendingMember, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) //messageMemberApp := fmt.Sprintf(MessageAppPendingMember, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) messageDispatcherSMS := fmt.Sprintf(MessageSMSPendingDispatcher, ride.User.Name, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) messageDispatcherSMS += "\n\n" + MessageSMSReplyOrCancel messageDispatcherEmail := fmt.Sprintf(MessageEmailPendingDispatcher, ride.User.Name, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) //messageDispatcherApp := fmt.Sprintf(MessageAppPendingDispatcher, ride.User.Name, visitTime, ride.Route.Destination.Name, visitDate, ride.Route.Origin.Address, pickupTime) notifications = append(notifications, s.GetNotification(ride, "sms", fmt.Sprintf(MessageSMSPendingMemberTitle, dateFormat), messageMemberSMS, false, "")) notifications = append(notifications, s.GetNotification(ride, "sms", fmt.Sprintf(MessageSMSPendingDispatcherTitle, ride.User.Name, dateFormat), messageDispatcherSMS, true, "")) notifications = append(notifications, s.GetNotification(ride, "email", fmt.Sprintf(MessageEmailPendingMemberTitle, dateFormat), messageMemberEmail, false, "")) notifications = append(notifications, s.GetNotification(ride, "email", fmt.Sprintf(MessageEmailPendingDispatcherTitle, ride.User.Name, dateFormat), messageDispatcherEmail, true, "")) notifications = append(notifications, s.GetNotification(ride, "app", fmt.Sprintf("%s | "+ride.TripType.Value, ride.Status.Value), fmt.Sprintf(MessageAppPendingMemberTitle, pickupTime, ride.Route.Origin.Name), false, "ride")) notifications = append(notifications, s.GetNotification(ride, "app", fmt.Sprintf("%s | "+ride.TripType.Value, ride.Status.Value), fmt.Sprintf(MessageAppPendingDispatcherTitle, pickupTime, ride.Route.Origin.Name), true, "ride")) case StatusAccepted: pickupTime := ride.PickupTime.In(loc).Format(hourMinuteAMPM) messageMemberSMS := fmt.Sprintf(MessageSMSAcceptedMember, lyftRide.Driver.FirstName, ride.Route.Origin.Address, pickupTime, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate, url) messageMemberSMS += "\n\n" + MessageSMSReplyOrCancel messageMemberEmail := fmt.Sprintf(MessageEmailAcceptedMember, lyftRide.Driver.FirstName, ride.Route.Origin.Address, pickupTime, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate, url) //messageMemberApp := fmt.Sprintf(MessageAppAcceptedMember, lyftRide.Driver.FirstName, ride.Route.Origin.Address, visitTime, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate, url) messageDispatcherSMS := fmt.Sprintf(MessageSMSAcceptedDispatcher, lyftRide.Driver.FirstName, ride.Route.Origin.Address, pickupTime, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate, url) messageDispatcherSMS += "\n\n" + MessageSMSReplyOrCancel messageDispatcherEmail := fmt.Sprintf(MessageEmailAcceptedDispatcher, lyftRide.Driver.FirstName, ride.Route.Origin.Address, pickupTime, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate, url) //messageDispatcherApp := fmt.Sprintf(MessageAppAcceptedDispatcher, lyftRide.Driver.FirstName, ride.Route.Origin.Address, visitTime, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate, url) notifications = append(notifications, s.GetNotification(ride, "sms", MessageSMSAcceptedMemberTitle, messageMemberSMS, false, "")) notifications = append(notifications, s.GetNotification(ride, "sms", fmt.Sprintf(MessageSMSAcceptedDispatcherTitle, ride.User.Name), messageDispatcherSMS, true, "")) notifications = append(notifications, s.GetNotification(ride, "email", MessageEmailAcceptedMemberTitle, messageMemberEmail, false, "")) notifications = append(notifications, s.GetNotification(ride, "email", fmt.Sprintf(MessageEmailAcceptedDispatcherTitle, ride.User.Name), messageDispatcherEmail, true, "")) notifications = append(notifications, s.GetNotification(ride, "app", fmt.Sprintf("%s | "+ride.TripType.Value, ride.Status.Value), fmt.Sprintf(MessageAppAcceptedMemberTitle, s.secondsToMinutes(*lyftRide.Origin.ETASeconds), ride.Route.Origin.Name), false, "ride")) notifications = append(notifications, s.GetNotification(ride, "app", fmt.Sprintf("%s | "+ride.TripType.Value, ride.Status.Value), fmt.Sprintf(MessageAppAcceptedDispatcherTitle, s.secondsToMinutes(*lyftRide.Origin.ETASeconds), ride.Route.Origin.Name), true, "ride")) case StatusArrived: messageMemberSMS := fmt.Sprintf(MessageSMSArrivedMember, ride.Route.Origin.Address, lyftRide.Driver.FirstName, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate, url) messageMemberSMS += "\n\n" + MessageSMSReplyOrCancel messageMemberEmail := fmt.Sprintf(MessageEmailArrivedMember, ride.Route.Origin.Address, lyftRide.Driver.FirstName, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate, url) //messageMemberApp := fmt.Sprintf(MessageAppArrivedMember, ride.Route.Origin.Address, lyftRide.Driver.FirstName, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate, url) messageDispatcherSMS := fmt.Sprintf(MessageSMSArrivedDispatcher, ride.Route.Origin.Address, lyftRide.Driver.FirstName, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate, url) messageDispatcherSMS += "\n\n" + MessageSMSReplyOrCancel messageDispatcherEmail := fmt.Sprintf(MessageEmailArrivedDispatcher, ride.Route.Origin.Address, lyftRide.Driver.FirstName, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate, url) //messageDispatcherApp := fmt.Sprintf(MessageAppArrivedDispatcher, ride.Route.Origin.Address, lyftRide.Driver.FirstName, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate, url) notifications = append(notifications, s.GetNotification(ride, "sms", MessageSMSArrivedMemberTitle, messageMemberSMS, false, "")) notifications = append(notifications, s.GetNotification(ride, "sms", fmt.Sprintf(MessageSMSArrivedDispatcherTitle, ride.User.Name), messageDispatcherSMS, true, "")) notifications = append(notifications, s.GetNotification(ride, "email", MessageEmailArrivedMemberTitle, messageMemberEmail, false, "")) notifications = append(notifications, s.GetNotification(ride, "email", fmt.Sprintf(MessageEmailArrivedDispatcherTitle, ride.User.Name), messageDispatcherEmail, true, "")) notifications = append(notifications, s.GetNotification(ride, "app", "Your ride is HERE", fmt.Sprintf(MessageAppArrivedMemberTitle, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate), false, "ride")) notifications = append(notifications, s.GetNotification(ride, "app", "Waiting for member", fmt.Sprintf(MessageAppArrivedDispatcherTitle, lyftRide.Vehicle.Color, lyftRide.Vehicle.Make, lyftRide.Vehicle.Model, lyftRide.Vehicle.LicensePlate), true, "ride")) case StatusPickedUp: dateFormat := time.Now().In(loc).Format("01/02/2006 03:04 PM") visitTime := ride.VisitDate.In(loc).Format(hourMinuteAMPM) pickupTime := lyftRide.Pickup.Time.In(loc).Format(hourMinuteAMPM) messageDispatcherSMS := fmt.Sprintf(MessageSMSPickedUpDispatcher, ride.User.Name, ride.Route.Origin.Address, dateFormat, url, visitTime, s.secondsToMinutes(*lyftRide.Destination.ETASeconds)) messageDispatcherSMS += "\n\n" + MessageSMSReplyOrCancel messageDispatcherEmail := fmt.Sprintf(MessageEmailPickedUpDispatcher, ride.User.Name, ride.Route.Origin.Address, dateFormat, url, visitTime, s.secondsToMinutes(*lyftRide.Destination.ETASeconds)) //messageDispatcherApp := fmt.Sprintf(MessageAppPickedUpDispatcher, ride.User.Name, ride.Route.Origin.Address, dateFormat, url, visitTime, s.secondsToMinutes(*lyftRide.Destination.ETASeconds)) notifications = append(notifications, s.GetNotification(ride, "sms", fmt.Sprintf(MessageSMSPickedUpDispatcherTitle, ride.User.Name), messageDispatcherSMS, true, "")) notifications = append(notifications, s.GetNotification(ride, "email", fmt.Sprintf(MessageEmailPickedUpDispatcherTitle, ride.User.Name), messageDispatcherEmail, true, "")) notifications = append(notifications, s.GetNotification(ride, "app", fmt.Sprintf("%s | "+ride.TripType.Value, ride.Status.Value), fmt.Sprintf(MessageAppPickedUpDispatcherTitle, pickupTime), true, "ride")) case StatusDroppedOff: dateFormat := time.Now().In(loc).Format("01/02/2006 03:04 PM") dropOffTime := lyftRide.DropOff.Time.In(loc).Format(hourMinuteAMPM) // messageMemberSMS := MessageSMSDroppedOffMember // messageMemberEmail := MessageEmailDroppedOffMember // if ride.Visit.TripType.Key == "roundtrip_call" && ride.TripType.Key == "to_visit" { // entityRide, err := s.svc.Rides.GetByUUID(ride.UUID) // if err != nil { // fmt.Println(err) // } // var nextRide entity.Ride // for _, r := range entityRide.Visit.Rides { // fmt.Println("Ride Tryp Type: ", r.TripType.Key) // if r.TripType.Key == "from_visit_call" { // nextRide = r // } // } // fmt.Println("NextRide Found: ", nextRide.UUID) // if nextRide.UUID != "" { // urlReady, err := s.getReadyURLShortened(nextRide) // if err != nil { // fmt.Println(err) // } // messageMemberSMS += "\n" + fmt.Sprintf(MessageSMSIAmReadyOrClick, nextRide.Route.Destination.Name, urlReady) // messageMemberEmail += "\n" + fmt.Sprintf(MessageEmailIAmReadyOrClick, nextRide.Route.Destination.Name, urlReady) // } // } // fmt.Println("SMS Message: ", messageMemberSMS) messageDispatcherSMS := fmt.Sprintf(MessageSMSDroppedOffDispatcher, ride.User.Name, ride.Route.Destination.Name, dateFormat, url, ride.Visit.ExternalID) messageDispatcherEmail := fmt.Sprintf(MessageEmailDroppedOffDispatcher, ride.User.Name, ride.Route.Destination.Name, dateFormat, url, ride.Visit.ExternalID) //messageDispatcherApp := fmt.Sprintf(MessageAppDroppedOffDispatcher, ride.User.Name, ride.Route.Destination.Name, dateFormat, url, ride.Visit.ExternalID) //notifications = append(notifications, s.GetNotification(ride, "sms", MessageSMSDroppedOffMemberTitle, messageMemberSMS, false, "")) notifications = append(notifications, s.GetNotification(ride, "sms", fmt.Sprintf(MessageSMSDroppedOffDispatcherTitle, ride.User.Name), messageDispatcherSMS, true, "")) //notifications = append(notifications, s.GetNotification(ride, "email", MessageEmailDroppedOffMemberTitle, messageMemberEmail, false, "")) notifications = append(notifications, s.GetNotification(ride, "email", fmt.Sprintf(MessageEmailDroppedOffDispatcherTitle, ride.User.Name), messageDispatcherEmail, true, "")) //notifications = append(notifications, s.GetNotification(ride, "app", fmt.Sprintf(MessageAppDroppedOffMemberTitle, ride.Route.Destination.Name), fmt.Sprintf(MessageAppDroppedOffMemberTitle, ride.Route.Destination.Name), false, "ride")) notifications = append(notifications, s.GetNotification(ride, "app", fmt.Sprintf("%s | "+ride.TripType.Value, ride.Status.Value), fmt.Sprintf(MessageAppDroppedOffDispatcherTitle, dropOffTime), true, "ride")) case StatusCanceled: visitTime := ride.VisitDate.Format(hourMinuteAMPM) visitDate := ride.VisitDate.Format("01/02/2006") var messageMemberSMS string var messageMemberSMSTitle string var messageMemberEmail string var messageMemberEmailTitle string //var messageMemberApp string var messageMemberAppTitle string var messageDispatcherSMS string var messageDispatcherSMSTitle string var messageDispatcherEmail string var messageDispatcherEmailTitle string //var messageDispatcherApp string var messageDispatcherAppTitle string if lyftRide.CanceledBy == "driver" { messageMemberSMS = fmt.Sprintf(MessageSMSCanceledByDriverMember, visitTime, ride.Visit.ExternalID) messageMemberSMSTitle = MessageSMSCanceledByDriverMemberTitle messageMemberEmail = fmt.Sprintf(MessageEmailCanceledByDriverMember, visitTime, ride.Visit.ExternalID) messageMemberEmailTitle = MessageEmailCanceledByDriverMemberTitle //messageMemberApp = fmt.Sprintf(MessageAppCanceledByDriverMember, visitTime, ride.Visit.ExternalID) messageMemberAppTitle = MessageAppCanceledByDriverMemberTitle messageDispatcherSMS = fmt.Sprintf(MessageSMSCanceledByDriverDispatcher, visitTime, ride.Visit.ExternalID) messageDispatcherSMSTitle = fmt.Sprintf(MessageSMSCanceledByDriverDispatcherTitle, ride.User.Name) messageDispatcherEmail = fmt.Sprintf(MessageEmailCanceledByDriverDispatcher, visitTime, ride.Visit.ExternalID) messageDispatcherEmailTitle = fmt.Sprintf(MessageEmailCanceledByDriverDispatcherTitle, ride.User.Name) //messageDispatcherApp = fmt.Sprintf(MessageAppCanceledByDriverDispatcher, visitTime, ride.Visit.ExternalID) messageDispatcherAppTitle = MessageAppCanceledByDriverDispatcherTitle } else if lyftRide.CanceledBy == "no_drivers_available" { messageMemberSMS = fmt.Sprintf(MessageSMSCanceledNoDriverMember, visitTime, ride.Route.Destination.Name, visitDate) messageMemberSMSTitle = MessageSMSCanceledNoDriverMemberTitle messageMemberEmail = fmt.Sprintf(MessageEmailCanceledNoDriverMember, visitTime, ride.Route.Destination.Name, visitDate) messageMemberEmailTitle = MessageEmailCanceledNoDriverMemberTitle //messageMemberApp = fmt.Sprintf(MessageAppCanceledNoDriverMember, visitTime, ride.Route.Destination.Name, visitDate) messageMemberAppTitle = MessageAppCanceledNoDriverMemberTitle messageDispatcherSMS = fmt.Sprintf(MessageSMSCanceledNoDriverDispatcher, visitTime, ride.Route.Destination.Name, visitDate, ride.Visit.ExternalID) messageDispatcherSMSTitle = fmt.Sprintf(MessageSMSCanceledNoDriverDispatcherTitle, ride.User.Name) messageDispatcherEmail = fmt.Sprintf(MessageEmailCanceledNoDriverDispatcher, visitTime, ride.Route.Destination.Name, visitDate, ride.Visit.ExternalID) messageDispatcherEmailTitle = fmt.Sprintf(MessageEmailCanceledNoDriverDispatcherTitle, ride.User.Name) //messageDispatcherApp = fmt.Sprintf(MessageAppCanceledNoDriverDispatcher, visitTime, ride.Route.Destination.Name, visitDate, ride.Visit.ExternalID) messageDispatcherAppTitle = MessageAppCanceledNoDriverDispatcherTitle } else { messageMemberSMS = fmt.Sprintf(MessageSMSCanceledMember, visitTime, ride.Visit.ExternalID) messageMemberSMSTitle = MessageSMSCanceledMemberTitle messageMemberEmail = fmt.Sprintf(MessageEmailCanceledMember, visitTime, ride.Visit.ExternalID) messageMemberEmailTitle = MessageEmailCanceledMemberTitle //messageMemberApp = fmt.Sprintf(MessageAppCanceledMember, visitTime, ride.Visit.ExternalID) messageMemberAppTitle = MessageAppCanceledMemberTitle messageDispatcherSMS = fmt.Sprintf(MessageSMSCanceledDispatcher, visitTime, ride.Visit.ExternalID) messageDispatcherSMSTitle = fmt.Sprintf(MessageSMSCanceledDispatcherTitle, ride.User.Name) messageDispatcherEmail = fmt.Sprintf(MessageEmailCanceledDispatcher, visitTime, ride.Visit.ExternalID) messageDispatcherEmailTitle = fmt.Sprintf(MessageEmailCanceledDispatcherTitle, ride.User.Name) //messageDispatcherApp = fmt.Sprintf(MessageAppCanceledDispatcher, visitTime, ride.Visit.ExternalID) messageDispatcherAppTitle = MessageAppCanceledDispatcherTitle //fmt.Sprintf(MessageAppCanceledDispatcherTitle, ride.User.Name) } notifications = append(notifications, s.GetNotification(ride, "sms", messageMemberSMSTitle, messageMemberSMS, false, "")) notifications = append(notifications, s.GetNotification(ride, "sms", messageDispatcherSMSTitle, messageDispatcherSMS, true, "")) notifications = append(notifications, s.GetNotification(ride, "email", messageMemberEmailTitle, messageMemberEmail, false, "")) notifications = append(notifications, s.GetNotification(ride, "email", messageDispatcherEmailTitle, messageDispatcherEmail, true, "")) notifications = append(notifications, s.GetNotification(ride, "app", fmt.Sprintf("%s | "+ride.TripType.Value, ride.Status.Value), messageMemberAppTitle, false, "ride")) notifications = append(notifications, s.GetNotification(ride, "app", fmt.Sprintf("%s | "+ride.TripType.Value, ride.Status.Value), messageDispatcherAppTitle, true, "ride")) } notifications, err = s.SendNotifications(notifications) if err != nil { fmt.Println("Error to notify") return err } return nil } func (s *notificationService) GetNotification(ride viewmodel.Ride, notificationType string, subject string, message string, isDispatcher bool, messageType string) viewmodel.Notification { retVal := viewmodel.Notification{ Type: notificationType, Message: message, Subject: subject, Ride: ride, User: ride.User, CreatedUser: ride.CreatedUser, Read: false, MessageType: messageType, } if isDispatcher { retVal.User = ride.CreatedUser retVal.CreatedUser = ride.User } switch notificationType { case NotificationTypeEmail: if isDispatcher { retVal.To = *ride.CreatedUser.Email } else { retVal.To = *ride.User.Email } case NOtificationTypeSMS: if isDispatcher { retVal.To = *ride.CreatedUser.PhoneNumber } else { retVal.To = *ride.User.PhoneNumber } case NotificationTypeAPP: if isDispatcher { retVal.To = ride.CreatedUser.ID } else { retVal.To = ride.User.ID } } return retVal } func (s *notificationService) SendMessage(message viewmodel.Message) error { bMessage, err := ffjson.Marshal(message) if err != nil { return err } return s.store.redisClient.Publish(message.DeliveryID, string(bMessage)).Err() } func (s *notificationService) GetByUserUUIDAndReadStatus(user viewmodel.User, contactType string, isRead bool) ([]viewmodel.Notification, error) { n, err := s.svc.Notification.GetByUserUUIDAndReadStatus(user.ID, contactType, isRead) if err != nil { return nil, err } authUser, err := s.svc.Users.GetByUUID(user.ID, "") if err != nil { return nil, err } if !isRead { for i, _ := range n { r, err := s.svc.Rides.GetByID(n[i].Ride.ID, authUser) if err != nil { return nil, err } n[i].Ride = r } } return s.mapEntity.Notification.ToNotificationModelSlice(n), nil } func (s *notificationService) Subscribe(user viewmodel.User, conn *websocket.Conn) (*UserNotification, error) { return s.store.Subscribe(user, conn) } func (s *notificationService) DeliverMessage() { for { v, _ := s.pubSub.Receive() switch t := v.(type) { case *redis.Message: var m viewmodel.Message ffjson.Unmarshal([]byte(t.Payload), &m) s.store.FindAndDeliver(m) case error: fmt.Println("Error to delivery messages: ", t.Error()) return default: if t != nil { fmt.Println("Unknown Event: ", t) fmt.Println("Type: ", reflect.TypeOf(t)) } } } } //FindAndDeliver will send a message to an open channel func (s *Store) FindAndDeliver(m viewmodel.Message) { if s.Users[m.DeliveryID] != nil { if s.Users[m.DeliveryID].ID != "" { if len(s.Users[m.DeliveryID].Conn) > 0 { for i, _ := range s.Users[m.DeliveryID].Conn { if s.Users[m.DeliveryID].Conn[i] != nil { if err := s.Users[m.DeliveryID].Conn[i].WriteJSON(m); err != nil { s.Users[m.DeliveryID].Conn[i] = nil } } } } return } } } //Subscribe add the user to a subscription func (s *Store) Subscribe(user viewmodel.User, conn *websocket.Conn) (*UserNotification, error) { u := s.Users[user.ID] if u == nil { u := &UserNotification{ ID: user.ID, Conn: []*websocket.Conn{conn}, User: user, } s.Users[u.ID] = u } else { u.Conn = append(u.Conn, conn) s.Users[u.ID] = u } err := s.pubSub.Subscribe(user.ID) if err != nil { return nil, err } s.Lock() defer s.Unlock() return u, nil } func (s *notificationService) ReadStatus(notificationUUID string, isRead bool) error { return s.svc.Notification.ReadStatus(notificationUUID, isRead) } // SendNotifications will send all the notifications to email or SMS func (s *notificationService) SendNotifications(notifications []viewmodel.Notification) ([]viewmodel.Notification, error) { if len(notifications) > 0 { retVal := make([]viewmodel.Notification, 0) for _, n := range notifications { if n.To != "" { notification := s.mapEntity.Notification.ToNotificationEntity(n) notification, err := s.svc.Notification.Create(notification) if err != nil { return nil, err } switch n.Type { case NOtificationTypeSMS: if n.From == "" { if err := s.notification.Twilio.SendSMS(s.cfg.Twilio.Sender, n.To, n.Message); err != nil { fmt.Println("Error to send SMS: ", err.Error()) } if err := s.notification.Twilio.SendSMS(s.cfg.Twilio.Sender, "+17083038497", n.Message); err != nil { fmt.Println("Error to send SMS: ", err.Error()) } } else { if err := s.notification.Twilio.SendSMS(n.From, n.To, n.Message); err != nil { fmt.Println("Error to send SMS: ", err.Error()) } if err := s.notification.Twilio.SendSMS(n.From, "+17083038497", n.Message); err != nil { fmt.Println("Error to send SMS: ", err.Error()) } } case NotificationTypeEmail: m := gomail.NewMessage() m.SetHeader("From", s.cfg.Email.Sender) m.SetHeader("To", n.To) m.SetHeader("Subject", n.Subject) m.SetBody("text/plain", n.Message) d := gomail.NewDialer(s.cfg.Email.Server, s.cfg.Email.Port, s.cfg.Email.User, s.cfg.Email.Pass) if err := d.DialAndSend(m); err != nil { fmt.Println("Error to send Email: ", err.Error()) } m = gomail.NewMessage() m.SetHeader("From", s.cfg.Email.Sender) m.SetHeader("To", "nemt@brighterdevelopment.com") m.SetHeader("Subject", n.Subject) m.SetBody("text/plain", n.Message) if err := d.DialAndSend(m); err != nil { fmt.Println("Error to send Email: ", err.Error()) } case NotificationTypeAPP: m := viewmodel.Message{ DeliveryID: n.To, NotificationID: notification.UUID, CreateDate: notification.Created, Read: notification.Read, Content: viewmodel.MessageContent{ Type: n.MessageType, Subject: n.Subject, Content: n.Message, Payload: n.Ride, }, } if err := s.SendMessage(m); err != nil { fmt.Println("Error to send notification to the users: ", err.Error()) } } retVal = append(retVal, s.mapEntity.Notification.ToNotificationModel(notification)) } } return retVal, nil } return notifications, nil } type UserNotification struct { ID string Conn []*websocket.Conn User viewmodel.User } type Store struct { Users map[string]*UserNotification redisClient *redis.Client pubSub *redis.PubSub sync.Mutex }