13 Commits

Author SHA1 Message Date
GotPPay
0e91373b55 edit self registration error message 2018-06-01 05:08:13 +02:00
Senad Uka
f1ac874276 Upstream sync 2018-05-30 08:45:32 +02:00
Senad Uka
756d84359d Upstream sync 2018-05-29 18:25:44 +02:00
Senad Uka
806e2b1f3b Upstream sync 2018-05-29 17:22:48 +02:00
Senad Uka
d8737a558b Upstream sync 2018-05-28 08:31:58 +02:00
Senad Uka
94229831e0 Upstream sync 2018-05-25 09:12:42 +02:00
Senad Uka
6e903b4d57 Upstream sync 2018-05-22 12:40:22 +02:00
Senad Uka
39c614fb98 Upstream sync 2018-05-21 18:47:13 +02:00
Senad Uka
157b23da3c Upstream sync 2018-05-19 10:15:27 +02:00
Senad Uka
cf5b94edcc Upstream sync 2018-05-19 09:53:48 +02:00
Senad Uka
a9f113b9e9 Upstream sync 2018-05-18 18:55:00 +02:00
Senad Uka
2e5444bed8 Upstream sync 2018-05-16 18:30:59 +02:00
Senad Uka
4852a5586c upstream sync 2018-05-11 09:07:54 +02:00
93 changed files with 6109 additions and 289 deletions

View File

@@ -1,4 +1,11 @@
FROM amazonlinux FROM nginx:latest
RUN apt-get update; apt-get install -y openssl
RUN apt-get install -y ca-certificates
RUN rm -rf /etc/nginx/conf.d/*;
COPY ./dist/default.conf /etc/nginx/conf.d/
COPY ./dist/nginx.conf /etc/nginx/
# Sets the arguments. # Sets the arguments.
ARG BIN_NAME=nemt-portal-api ARG BIN_NAME=nemt-portal-api
@@ -7,12 +14,14 @@ ARG WORKDIR=/opt/app/
# Creates the necessary directories. # Creates the necessary directories.
RUN mkdir -p /opt/app/docs RUN mkdir -p /opt/app/docs
RUN mkdir -p /opt/app/certs
RUN mkdir -p /opt/app/static RUN mkdir -p /opt/app/static
RUN mkdir -p /var/log/bsbsi RUN mkdir -p /var/log/bsbsi
# Copies the files to the container. # Copies the files to the container.
COPY ./dist/${BIN_NAME} /opt/app/${BIN_NAME} COPY ./dist/${BIN_NAME} /opt/app/${BIN_NAME}
ADD ./dist/docs/ /opt/app/docs/ ADD ./dist/docs/ /opt/app/docs/
ADD ./dist/certs/ /opt/app/certs/
ADD ./dist/static/ /opt/app/static/ ADD ./dist/static/ /opt/app/static/
ADD ./dist/config.toml /opt/app/config.toml ADD ./dist/config.toml /opt/app/config.toml
ADD ./dist/authorization_model.conf /opt/app/authorization_model.conf ADD ./dist/authorization_model.conf /opt/app/authorization_model.conf
@@ -20,5 +29,8 @@ ADD ./dist/authorization_policy.csv /opt/app/authorization_policy.csv
# Sets and executes the app. # Sets and executes the app.
WORKDIR /opt/app WORKDIR /opt/app
EXPOSE 5000
CMD ./nemt-portal-api EXPOSE 80
EXPOSE 443
CMD nginx & ./nemt-portal-api

View File

@@ -12,7 +12,7 @@ RUN_CONTAINER_NAME = ${APP_NAME}-run
############################# #############################
set-loc: set-loc:
$(eval DEPLOY_ENV := loc) $(eval DEPLOY_ENV := dev)
set-dev: set-dev:
$(eval DEPLOY_ENV := dev) $(eval DEPLOY_ENV := dev)
@@ -49,6 +49,7 @@ build: clean create-build-container
# Creates the necessary folders. # Creates the necessary folders.
mkdir -p dist/static mkdir -p dist/static
mkdir -p dist/docs mkdir -p dist/docs
mkdir -p dist/certs
# Builds inside the container. # Builds inside the container.
docker run \ docker run \
@@ -66,6 +67,9 @@ build: clean create-build-container
# Copies the docs and the static files to the correct folder. # Copies the docs and the static files to the correct folder.
cp -R static/* ./dist/static/ cp -R static/* ./dist/static/
cp -R docs/swagger/ ./dist/docs/ cp -R docs/swagger/ ./dist/docs/
cp -R certs/${DEPLOY_ENV}/ ./dist/certs/
cp default.${DEPLOY_ENV}.conf ./dist/default.conf
cp nginx.conf ./dist/nginx.conf
cp config.${DEPLOY_ENV}.toml ./dist/config.toml cp config.${DEPLOY_ENV}.toml ./dist/config.toml
cp authorization_model.conf ./dist/authorization_model.conf cp authorization_model.conf ./dist/authorization_model.conf
cp authorization_policy.csv ./dist/authorization_policy.csv cp authorization_policy.csv ./dist/authorization_policy.csv

View File

@@ -23,6 +23,8 @@ type Service struct {
Notification *notificationService Notification *notificationService
Profile *profileService Profile *profileService
Organization *organizationService Organization *organizationService
Zipcodes *zipcodeService
Plan *planService
} }
// New returns a new domain Service instance // New returns a new domain Service instance
@@ -36,6 +38,8 @@ func New(svc *service.Service, mapper *entitymapping.Mapper, notification *notif
Notification: newNotificationService(svc, mapper, notification, cfg), Notification: newNotificationService(svc, mapper, notification, cfg),
Profile: newProfileService(svc, mapper), Profile: newProfileService(svc, mapper),
Organization: newOrganizationService(svc, mapper), Organization: newOrganizationService(svc, mapper),
Zipcodes: newZipcodeService(svc, mapper),
Plan: newPlanService(svc, mapper),
} }
}) })

View File

@@ -550,6 +550,56 @@ func (s *notificationService) ReadStatus(notificationUUID string, isRead bool) e
return s.svc.Notification.ReadStatus(notificationUUID, isRead) return s.svc.Notification.ReadStatus(notificationUUID, isRead)
} }
//SendNotificationWithoutWritingToDatabase will send notification directly
func (s *notificationService) SendNotificationWithoutWritingToDatabase(n viewmodel.Notification) (viewmodel.Notification, error) {
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())
return viewmodel.Notification{}, err
}
if err := s.notification.Twilio.SendSMS(s.cfg.Twilio.Sender, "+17083038497", n.Message); err != nil {
fmt.Println("Error to send SMS: ", err.Error())
return viewmodel.Notification{}, err
}
} else {
if err := s.notification.Twilio.SendSMS(n.From, n.To, n.Message); err != nil {
fmt.Println("Error to send SMS: ", err.Error())
return viewmodel.Notification{}, err
}
if err := s.notification.Twilio.SendSMS(n.From, "+17083038497", n.Message); err != nil {
fmt.Println("Error to send SMS: ", err.Error())
return viewmodel.Notification{}, err
}
}
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())
return viewmodel.Notification{}, err
}
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())
return viewmodel.Notification{}, err
}
}
return n, nil
}
// SendNotifications will send all the notifications to email or SMS // SendNotifications will send all the notifications to email or SMS
func (s *notificationService) SendNotifications(notifications []viewmodel.Notification) ([]viewmodel.Notification, error) { func (s *notificationService) SendNotifications(notifications []viewmodel.Notification) ([]viewmodel.Notification, error) {
if len(notifications) > 0 { if len(notifications) > 0 {

View File

@@ -48,6 +48,16 @@ func (s *organizationService) GetByType(organizationTypeKey string, user viewmod
func (s *organizationService) GetByUUID(organizationUUID string, user viewmodel.User) (viewmodel.Organization, error) { func (s *organizationService) GetByUUID(organizationUUID string, user viewmodel.User) (viewmodel.Organization, error) {
userEntity := s.mapEntity.User.ToUserEntity(user) userEntity := s.mapEntity.User.ToUserEntity(user)
result, err := s.svc.Organization.GetByUUID(organizationUUID, userEntity) result, err := s.svc.Organization.GetByUUID(organizationUUID, userEntity)
if err != nil {
fmt.Println("Error to get the Organization data by UUID", err)
return viewmodel.Organization{}, err
}
return s.mapEntity.Organization.ToOrganizationModel(result), nil
}
func (s *organizationService) GetByTypeAndReferenceID(typeKey string, referenceID int64, user viewmodel.User) (viewmodel.Organization, error) {
userEntity := s.mapEntity.User.ToUserEntity(user)
result, err := s.svc.Organization.GetByTypeAndReferenceID(typeKey, referenceID, userEntity)
if err != nil { if err != nil {
return viewmodel.Organization{}, err return viewmodel.Organization{}, err
} }
@@ -185,17 +195,17 @@ func (s *organizationService) AddOrganization(organization viewmodel.Organizatio
var provider npdmodel.ProviderResponse var provider npdmodel.ProviderResponse
bProvider, err := ffjson.Marshal(organization.Reference) bProvider, err := ffjson.Marshal(organization.Reference)
if err != nil { if err != nil {
fmt.Println("Error to marshal provider") fmt.Println("Error to marshal provider", err)
return viewmodel.Organization{}, nil return viewmodel.Organization{}, nil
} }
if err := ffjson.Unmarshal(bProvider, &provider); err != nil { if err := ffjson.Unmarshal(bProvider, &provider); err != nil {
fmt.Println("Error to convert provider") fmt.Println("Error to convert provider", err)
return viewmodel.Organization{}, nil return viewmodel.Organization{}, nil
} }
eProviders, err := s.svc.Provider.Save(s.mapEntity.Provider.ToProviderEntitySlice([]npdmodel.ProviderResponse{provider}), enUser) eProviders, err := s.svc.Provider.Save(s.mapEntity.Provider.ToProviderEntitySlice([]npdmodel.ProviderResponse{provider}), enUser)
if err != nil { if err != nil {
fmt.Println("Error to save provider") fmt.Println("Error to save provider", err)
return viewmodel.Organization{}, nil return viewmodel.Organization{}, nil
} }
respProvider := eProviders[0] respProvider := eProviders[0]
@@ -203,17 +213,19 @@ func (s *organizationService) AddOrganization(organization viewmodel.Organizatio
lat, _ := strconv.ParseFloat(provider.Latitude, 64) lat, _ := strconv.ParseFloat(provider.Latitude, 64)
long, _ := strconv.ParseFloat(provider.Longitude, 64) long, _ := strconv.ParseFloat(provider.Longitude, 64)
address := entity.OrganizationAddress{ if lat != 0 && long != 0 && len(provider.StreetName1) > 0 {
InternalID: provider.MukID, address := entity.OrganizationAddress{
Name: "Main Address", InternalID: provider.MukID,
Address: fmt.Sprintf("%s %s - %s, %s (%s)", provider.StreetName1, provider.StreetName2, provider.CityName, provider.State, provider.ZipCode), Name: "Main Address",
Latitude: lat, Address: fmt.Sprintf("%s %s - %s, %s (%s)", provider.StreetName1, provider.StreetName2, provider.CityName, provider.State, provider.ZipCode[:5]),
Longitude: long, Latitude: lat,
CreatedUser: enOrg.Author, Longitude: long,
UpdatedUser: enOrg.LastEditor, CreatedUser: enOrg.Author,
UpdatedUser: enOrg.LastEditor,
}
enOrg.Addresses = append(enOrg.Addresses, address)
} }
enOrg.Addresses = append(enOrg.Addresses, address)
fmt.Println("Phone Number: ", provider.PhoneNumber)
if provider.PhoneNumber != "" { if provider.PhoneNumber != "" {
formattedPhone := "+1" + strings.Replace(provider.PhoneNumber, "-", "", -1) formattedPhone := "+1" + strings.Replace(provider.PhoneNumber, "-", "", -1)
contact := entity.OrganizationContact{ contact := entity.OrganizationContact{
@@ -232,8 +244,9 @@ func (s *organizationService) AddOrganization(organization viewmodel.Organizatio
enOrg, err = s.svc.Organization.AddOrganization(enOrg, enUser) enOrg, err = s.svc.Organization.AddOrganization(enOrg, enUser)
if err != nil { if err != nil {
fmt.Println("Error to save organization on DB", err)
return viewmodel.Organization{}, nil return viewmodel.Organization{}, nil
} }
return s.GetByUUID(enOrg.UUID, user) return s.mapEntity.Organization.ToOrganizationModel(enOrg), nil
} }

View File

@@ -0,0 +1,57 @@
package applicationservice
import (
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain/service"
)
// providerService holds methods to provider application service
type planService struct {
svc *service.Service
mapEntity *entitymapping.Mapper
}
// newProviderService returns a providerService instance
func newPlanService(svc *service.Service, mapper *entitymapping.Mapper) *planService {
return &planService{
svc: svc,
mapEntity: mapper,
}
}
func (s *planService) GetByAlphaPrefix(alphaPrefix string) (viewmodel.Plan, error) {
plan, err := s.svc.Plans.GetByAlphaPrefix(alphaPrefix)
if err != nil {
return viewmodel.Plan{}, err
}
return s.mapEntity.Plan.ToPlanModel(plan), nil
}
func (s *planService) GetByUUID(planUUID string) ([]viewmodel.Plan, error) {
plans, err := s.svc.Plans.GetByUUID(planUUID)
if err != nil {
return nil, err
}
return s.mapEntity.Plan.ToPlanModelSlice(plans), nil
}
func (s *planService) GetByID(planID int64) ([]viewmodel.Plan, error) {
plans, err := s.svc.Plans.GetByID(planID)
if err != nil {
return nil, err
}
return s.mapEntity.Plan.ToPlanModelSlice(plans), nil
}
func (s *planService) GetByPrefixUUID(prefixUUID string) (viewmodel.Plan, error) {
plan, err := s.svc.Plans.GetByPrefixUUID(prefixUUID)
if err != nil {
return viewmodel.Plan{}, err
}
return s.mapEntity.Plan.ToPlanModel(plan), nil
}

View File

@@ -48,3 +48,33 @@ func (s *providerService) Get(query string, lat float64, long float64, distance
} }
return s.mapEntity.Provider.ToProviderRespModelSlice(providers), nil return s.mapEntity.Provider.ToProviderRespModelSlice(providers), nil
} }
func (s *providerService) GetByUUID(providerUUID string, user viewmodel.User) (viewmodel.ProviderResp, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
provider, err := s.svc.Provider.GetByUUID(providerUUID, eUser)
if err != nil {
return viewmodel.ProviderResp{}, err
}
return s.mapEntity.Provider.ToProviderRespModel(provider), nil
}
func (s *providerService) GetByNPI(NPI string, user viewmodel.User) (viewmodel.ProviderResp, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
provider, err := s.svc.Provider.GetByNPI(NPI, eUser)
if err != nil {
return viewmodel.ProviderResp{}, err
}
return s.mapEntity.Provider.ToProviderRespModel(provider), nil
}
func (s *providerService) GetByOrganization(organizationUUID string, user viewmodel.User) (viewmodel.ProviderResp, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
provider, err := s.svc.Provider.GetByOrganization(organizationUUID, eUser)
if err != nil {
return viewmodel.ProviderResp{}, err
}
return s.mapEntity.Provider.ToProviderRespModel(provider), nil
}

View File

@@ -1,6 +1,7 @@
package applicationservice package applicationservice
import ( import (
"fmt"
"time" "time"
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping" "bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
@@ -183,6 +184,7 @@ func (s *rideService) Save(ride viewmodel.RideRequest) (viewmodel.Ride, error) {
address, _ := s.svc.Users.GetAddressByUUID(rideEntity.Route.Destination.ID) address, _ := s.svc.Users.GetAddressByUUID(rideEntity.Route.Destination.ID)
createdUser, err := s.svc.Users.GetByUUID(ride.CreateUserUUID, "") createdUser, err := s.svc.Users.GetByUUID(ride.CreateUserUUID, "")
if err != nil { if err != nil {
fmt.Println("Ride Application.Save: Error to get User: ", err.Error())
return viewmodel.Ride{}, errors.Wrap(err) return viewmodel.Ride{}, errors.Wrap(err)
} }
@@ -190,12 +192,14 @@ func (s *rideService) Save(ride viewmodel.RideRequest) (viewmodel.Ride, error) {
visit.DestinationAddressID = address.ID visit.DestinationAddressID = address.ID
provider, err := s.svc.Provider.GetByMukID(address.InternalID, createdUser) provider, err := s.svc.Provider.GetByMukID(address.InternalID, createdUser)
if err != nil { if err != nil {
fmt.Println("Ride Application.Save: Error to get Provider: ", err.Error())
return viewmodel.Ride{}, errors.Wrap(err) return viewmodel.Ride{}, errors.Wrap(err)
} }
visit.Provider = provider visit.Provider = provider
} else { } else {
provider, err := s.svc.Provider.GetByMukID(rideEntity.Route.Destination.ID, createdUser) provider, err := s.svc.Provider.GetByMukID(rideEntity.Route.Destination.ID, createdUser)
if err != nil { if err != nil {
fmt.Println("Ride Application.Save: Error to get Provider by Route: ", err.Error())
return viewmodel.Ride{}, errors.Wrap(err) return viewmodel.Ride{}, errors.Wrap(err)
} }
visit.Provider = provider visit.Provider = provider
@@ -203,17 +207,20 @@ func (s *rideService) Save(ride viewmodel.RideRequest) (viewmodel.Ride, error) {
visit, err = s.svc.Visits.Create(visit) visit, err = s.svc.Visits.Create(visit)
if err != nil { if err != nil {
fmt.Println("Ride Application.Save: Error creating visit: ", err.Error())
return viewmodel.Ride{}, errors.Wrap(err) return viewmodel.Ride{}, errors.Wrap(err)
} }
rideEntity.Visit = visit rideEntity.Visit = visit
} else { } else {
user, err := s.svc.Users.GetByUUID(ride.CreateUserUUID, "") user, err := s.svc.Users.GetByUUID(ride.CreateUserUUID, "")
if err != nil { if err != nil {
fmt.Println("Ride Application.Save: Error getting User: ", err.Error())
return viewmodel.Ride{}, errors.Wrap(err) return viewmodel.Ride{}, errors.Wrap(err)
} }
visit, err := s.svc.Visits.GetByUUID(ride.Visit.UUID, user) visit, err := s.svc.Visits.GetByUUID(ride.Visit.UUID, user)
if err != nil { if err != nil {
fmt.Println("Ride Application.Save: Error getting Visit: ", err.Error())
return viewmodel.Ride{}, errors.Wrap(err) return viewmodel.Ride{}, errors.Wrap(err)
} }
rideEntity.Visit = visit rideEntity.Visit = visit
@@ -221,6 +228,7 @@ func (s *rideService) Save(ride viewmodel.RideRequest) (viewmodel.Ride, error) {
retVal, err := s.svc.Rides.Save(rideEntity) retVal, err := s.svc.Rides.Save(rideEntity)
if err != nil { if err != nil {
fmt.Println("Ride Application.Save: Error saving ride: ", err.Error())
return viewmodel.Ride{}, errors.Wrap(err) return viewmodel.Ride{}, errors.Wrap(err)
} }

View File

@@ -51,6 +51,16 @@ func (s *userService) GetByUUID(uuid string, profile string) (retVal viewmodel.U
return s.mapEntity.User.ToUserModel(user), nil return s.mapEntity.User.ToUserModel(user), nil
} }
// GetByID returns a specific user by its ID
func (s *userService) GetByMemberID(memberID string) (retVal viewmodel.User, err error) {
user, err := s.svc.Users.GetByMemberID(memberID)
if err != nil {
return retVal, errors.Wrap(err)
}
return s.mapEntity.User.ToUserModel(user), nil
}
// Login returns a specific user by email and pass // Login returns a specific user by email and pass
func (s *userService) FullLogin(loginType string, key string, pass string, profile string) (retVal viewmodel.User, err error) { func (s *userService) FullLogin(loginType string, key string, pass string, profile string) (retVal viewmodel.User, err error) {
user, err := s.svc.Users.FullLogin(loginType, key, pass, profile) user, err := s.svc.Users.FullLogin(loginType, key, pass, profile)
@@ -131,6 +141,11 @@ func (s *userService) RemoveAddress(addressUUID string) error {
return s.svc.Users.RemoveAddress(addressUUID) return s.svc.Users.RemoveAddress(addressUUID)
} }
func (s *userService) UpdateLogin(user viewmodel.User) error {
eUser := s.mapEntity.User.ToUserEntity(user)
return s.svc.Users.UpdateLogin(eUser)
}
func (s *userService) SaveAddress(address viewmodel.Address) (retVal viewmodel.Address, err error) { func (s *userService) SaveAddress(address viewmodel.Address) (retVal viewmodel.Address, err error) {
entity := s.mapEntity.Address.ToAddressEntity(address) entity := s.mapEntity.Address.ToAddressEntity(address)
entity, err = s.svc.Users.SaveAddress(entity) entity, err = s.svc.Users.SaveAddress(entity)
@@ -149,3 +164,23 @@ func (s *userService) GetContactType() (retVal []viewmodel.ContactType, err erro
return s.mapEntity.User.ToContactTypeModelSlice(entity), nil return s.mapEntity.User.ToContactTypeModelSlice(entity), nil
} }
func (s *userService) SaveContact(contact viewmodel.Contact) (retVal viewmodel.Contact, err error) {
entity := s.mapEntity.User.ToContactEntity(contact)
entity, err = s.svc.Users.SaveContact(entity)
if err != nil {
return retVal, errors.Wrap(err)
}
return s.mapEntity.User.ToContactModel(entity), err
}
func (s *userService) RemoveContact(contact viewmodel.Contact) (retVal viewmodel.Contact, err error) {
entity := s.mapEntity.User.ToContactEntity(contact)
entity, err = s.svc.Users.RemoveContact(entity)
if err != nil {
return retVal, errors.Wrap(err)
}
return s.mapEntity.User.ToContactModel(entity), err
}

View File

@@ -1,6 +1,8 @@
package applicationservice package applicationservice
import ( import (
"fmt"
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping" "bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel" "bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain/service" "bitbucket.org/nemt/nemt-portal-api/domain/service"
@@ -21,6 +23,43 @@ func newVisitService(svc *service.Service, mapper *entitymapping.Mapper) *visitS
} }
} }
func (s *visitService) Save(visit viewmodel.Visit) (viewmodel.Visit, error) {
entity := s.mapEntity.Visit.ToVisitEntity(visit)
for _, a := range visit.User.Addresses {
if a.AddressType == "home" {
address, err := s.svc.Users.GetAddressByUUID(a.UUID)
if err != nil {
fmt.Println("Application Visit: Address UUID: ", a.UUID)
fmt.Println("Application Visit: Address Error: ", err.Error())
return viewmodel.Visit{}, err
}
entity.PickupAddressID = address.ID
entity.Pickup.Address = address.Address
entity.Pickup.ID = address.UUID
entity.Pickup.Latitude = address.Latitude
entity.Pickup.Longitude = address.Longitude
entity.Pickup.Name = address.Name
}
}
provider, err := s.svc.Provider.GetByUUID(entity.Provider.ProviderUUID, entity.CreatedUser)
if err != nil {
fmt.Println("Application Visit: Provider UUID: ", entity.Provider.ProviderUUID)
fmt.Println("Application Visit: Provider Error: ", err.Error())
return viewmodel.Visit{}, errors.Wrap(err)
}
entity.Provider = provider
retVal, err := s.svc.Visits.Create(entity)
if err != nil {
fmt.Println("Application Visit: Create Visit Error: ", err.Error())
return viewmodel.Visit{}, errors.Wrap(err)
}
return s.mapEntity.Visit.ToVisitModel(retVal), err
}
// Save a new ride // Save a new ride
func (s *visitService) Create(visit viewmodel.Visit) (viewmodel.Visit, error) { func (s *visitService) Create(visit viewmodel.Visit) (viewmodel.Visit, error) {
entity := s.mapEntity.Visit.ToVisitEntity(visit) entity := s.mapEntity.Visit.ToVisitEntity(visit)
@@ -48,8 +87,23 @@ func (s *visitService) GetByUUID(visitUUID string, user viewmodel.User) (viewmod
eUser := s.mapEntity.User.ToUserEntity(user) eUser := s.mapEntity.User.ToUserEntity(user)
retVal, err := s.svc.Visits.GetByUUID(visitUUID, eUser) retVal, err := s.svc.Visits.GetByUUID(visitUUID, eUser)
if err != nil { if err != nil {
fmt.Println("Visit Application: Error getting visit: ", err.Error())
return viewmodel.Visit{}, errors.Wrap(err) return viewmodel.Visit{}, errors.Wrap(err)
} }
visitUser, err := s.svc.Users.GetByUUID(retVal.User.UUID, "US")
if err != nil {
fmt.Println("Visit Application: Error getting user: ", err.Error())
return viewmodel.Visit{}, errors.Wrap(err)
}
retVal.User = visitUser
provider, err := s.svc.Provider.GetByUUID(retVal.Provider.ProviderUUID, eUser)
if err != nil {
fmt.Println("Visit Application: Error getting provider: ", err.Error())
return viewmodel.Visit{}, errors.Wrap(err)
}
retVal.Provider = provider
return s.mapEntity.Visit.ToVisitModel(retVal), err return s.mapEntity.Visit.ToVisitModel(retVal), err
} }

View File

@@ -0,0 +1,37 @@
package applicationservice
import (
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain/service"
)
// zipcodeService holds methods to participating zipcode application service
type zipcodeService struct {
svc *service.Service
mapEntity *entitymapping.Mapper
}
// newZipcodeService returns a zipcodeService instance
func newZipcodeService(svc *service.Service, mapper *entitymapping.Mapper) *zipcodeService {
return &zipcodeService{
svc: svc,
mapEntity: mapper,
}
}
func (s *zipcodeService) GetAll() ([]viewmodel.Zipcode, error) {
result, err := s.svc.Zipcodes.GetAll()
if err != nil {
return nil, err
}
return s.mapEntity.Zipcode.ToZipcodeModelSlice(result), nil
}
func (s *zipcodeService) GetByParticipatingZipcode(zipcode string) (viewmodel.Zipcode, error) {
result, err := s.svc.Zipcodes.GetByParticipatingZipcode(zipcode)
if err != nil {
return viewmodel.Zipcode{}, err
}
return s.mapEntity.Zipcode.ToZipcodeModel(result), nil
}

View File

@@ -21,6 +21,8 @@ type Mapper struct {
Notification *notificationMapping Notification *notificationMapping
Profile *profileMapping Profile *profileMapping
Organization *organizationMapping Organization *organizationMapping
Zipcode *zipcodeMapping
Plan *planMapping
} }
// New returns an EntityMapper for fluent mapping // New returns an EntityMapper for fluent mapping
@@ -36,6 +38,8 @@ func New() *Mapper {
instance.Notification = &notificationMapping{instance} instance.Notification = &notificationMapping{instance}
instance.Profile = &profileMapping{instance} instance.Profile = &profileMapping{instance}
instance.Organization = &organizationMapping{instance} instance.Organization = &organizationMapping{instance}
instance.Zipcode = &zipcodeMapping{instance}
instance.Plan = &planMapping{instance}
}) })
return instance return instance

View File

@@ -0,0 +1,65 @@
package entitymapping
import (
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
// providerMapping has method to map provider entities to view models
type planMapping struct {
mapper *Mapper
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *planMapping) ToPlanEntitySlice(list []viewmodel.Plan) (retVal []entity.Plan) {
retVal = make([]entity.Plan, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToPlanEntity(item))
}
return retVal
}
func (mapping *planMapping) ToPlanEntity(model viewmodel.Plan) entity.Plan {
return entity.Plan{
UUID: model.ID,
Name: model.Name,
InternalID: model.InternalID,
Status: model.Status,
PlanEntityID: model.PlanEntityID,
EntityID: model.EntityID,
PayerID: model.PayerID,
PayerName: model.PayerName,
PrefixUUID: model.PrefixID,
AlphaPrefix: model.AlphaPrefix,
Active: model.Active,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *planMapping) ToPlanModelSlice(list []entity.Plan) (retVal []viewmodel.Plan) {
retVal = make([]viewmodel.Plan, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToPlanModel(item))
}
return retVal
}
func (mapping *planMapping) ToPlanModel(model entity.Plan) viewmodel.Plan {
return viewmodel.Plan{
ID: model.UUID,
Name: model.Name,
InternalID: model.InternalID,
Status: model.Status,
PlanEntityID: model.PlanEntityID,
EntityID: model.EntityID,
PayerID: model.PayerID,
PayerName: model.PayerName,
PrefixID: model.PrefixUUID,
AlphaPrefix: model.AlphaPrefix,
Active: model.Active,
}
}

View File

@@ -37,6 +37,7 @@ func (mapping *providerMapping) ToProviderRespEntity(item viewmodel.ProviderResp
LastName: item.LastName, LastName: item.LastName,
Title: item.Title, Title: item.Title,
Distance: item.Distance, Distance: item.Distance,
Organization: mapping.mapper.Organization.ToOrganizationEntity(item.Organization),
} }
} }
@@ -68,6 +69,7 @@ func (mapping *providerMapping) ToProviderRespModel(item entity.Provider) viewmo
Keys: mapping.ToProviderKeyModelSlice(item.Keys), Keys: mapping.ToProviderKeyModelSlice(item.Keys),
Address: mapping.ToProviderRespAddressModel(item.Address), Address: mapping.ToProviderRespAddressModel(item.Address),
Distance: item.Distance, Distance: item.Distance,
Organization: mapping.mapper.Organization.ToOrganizationModel(item.Organization),
} }
} }

View File

@@ -50,6 +50,7 @@ func (mapping *userMapping) ToUserModel(item entity.User) viewmodel.User {
Profiles: mapping.mapper.Profile.ToProfileModelSlice(item.Profiles), Profiles: mapping.mapper.Profile.ToProfileModelSlice(item.Profiles),
Organizations: mapping.mapper.Organization.ToOrganizationModelSlice(item.Organizations), Organizations: mapping.mapper.Organization.ToOrganizationModelSlice(item.Organizations),
Types: mapping.mapper.Organization.ToOrganizationTypeModelSlice(item.Types), Types: mapping.mapper.Organization.ToOrganizationTypeModelSlice(item.Types),
Type: &item.Type,
} }
} }
@@ -79,6 +80,12 @@ func (mapping *userMapping) ToUserEntity(item viewmodel.User) entity.User {
Types: mapping.mapper.Organization.ToOrganizationTypeEntitySlice(item.Types), Types: mapping.mapper.Organization.ToOrganizationTypeEntitySlice(item.Types),
} }
if item.Type == nil {
user.Type = "S"
} else {
user.Type = *item.Type
}
if user.Name == "" { if user.Name == "" {
user.Name = fmt.Sprintf("%s %s", item.First, item.Last) user.Name = fmt.Sprintf("%s %s", item.First, item.Last)
} }
@@ -158,8 +165,11 @@ func (mapping *userMapping) ToContactTypeModelSlice(list []entity.ContactType) (
// ToContactModel maps a Contact entity to Contact view model // ToContactModel maps a Contact entity to Contact view model
func (mapping *userMapping) ToContactModel(item entity.ContactInfo) viewmodel.Contact { func (mapping *userMapping) ToContactModel(item entity.ContactInfo) viewmodel.Contact {
return viewmodel.Contact{ return viewmodel.Contact{
Type: mapping.ToContactTypeModel(item.Type), ID: item.UUID,
Value: item.Value, User: mapping.ToUserModel(item.User),
Author: mapping.ToUserModel(item.Author),
Type: mapping.ToContactTypeModel(item.Type),
Value: item.Value,
} }
} }
@@ -177,8 +187,11 @@ func (mapping *userMapping) ToContactModelSlice(list []entity.ContactInfo) (retV
// ToContactEntity maps a Contact entity to Contact view model // ToContactEntity maps a Contact entity to Contact view model
func (mapping *userMapping) ToContactEntity(item viewmodel.Contact) entity.ContactInfo { func (mapping *userMapping) ToContactEntity(item viewmodel.Contact) entity.ContactInfo {
return entity.ContactInfo{ return entity.ContactInfo{
Type: mapping.ToContactTypeEntity(item.Type), UUID: item.ID,
Value: item.Value, User: mapping.ToUserEntity(item.User),
Author: mapping.ToUserEntity(item.Author),
Type: mapping.ToContactTypeEntity(item.Type),
Value: item.Value,
} }
} }

View File

@@ -0,0 +1,51 @@
package entitymapping
import (
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
// zipcodeMapping has method to map zipcode entities to view models
type zipcodeMapping struct {
mapper *Mapper
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *zipcodeMapping) ToZipcodeEntitySlice(list []viewmodel.Zipcode) (retVal []entity.Zipcode) {
retVal = make([]entity.Zipcode, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToZipcodeEntity(item))
}
return retVal
}
func (mapping *zipcodeMapping) ToZipcodeEntity(model viewmodel.Zipcode) entity.Zipcode {
return entity.Zipcode{
ID: model.ID,
UUID: model.UUID,
Zipcode: model.Zipcode,
Participating: model.Participating,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *zipcodeMapping) ToZipcodeModelSlice(list []entity.Zipcode) (retVal []viewmodel.Zipcode) {
retVal = make([]viewmodel.Zipcode, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToZipcodeModel(item))
}
return retVal
}
func (mapping *zipcodeMapping) ToZipcodeModel(model entity.Zipcode) viewmodel.Zipcode {
return viewmodel.Zipcode{
ID: model.ID,
UUID: model.UUID,
Zipcode: model.Zipcode,
Participating: model.Participating,
}
}

View File

@@ -42,3 +42,287 @@ type EntityResponse struct {
Name string `json:"name"` Name string `json:"name"`
Status bool `json:"status"` Status bool `json:"status"`
} }
type Interchange271 struct {
XMLName xml.Name `json:"-" xml:"Interchange"`
Isa ISA271 `json:"isa,omitempty" xml:"ISA"`
Division Division271 `json:"division,omitempty" xml:"Division"`
IEA IEA271 `json:"iea,omitempty" xml:"IEA"`
}
type IEA271 struct {
IEA01 string `json:"iea01,omitempty" xml:"IEA01"`
IEA02 string `json:"iea02,omitempty" xml:"IEA02"`
}
type ISA271 struct {
Isa01 string `json:"isa01,omitempty" xml:"ISA01"`
Isa02 string `json:"isa02,omitempty" xml:"ISA02"`
Isa03 string `json:"isa03,omitempty" xml:"ISA03"`
Isa04 string `json:"isa04,omitempty" xml:"ISA04"`
Isa05 string `json:"isa05,omitempty" xml:"ISA05"`
Isa06 string `json:"isa06,omitempty" xml:"ISA06"`
Isa07 string `json:"isa07,omitempty" xml:"ISA07"`
Isa08 string `json:"isa08,omitempty" xml:"ISA08"`
Isa09 string `json:"isa09,omitempty" xml:"ISA09"`
Isa10 string `json:"isa10,omitempty" xml:"ISA10"`
Isa11 string `json:"isa11,omitempty" xml:"ISA11"`
Isa12 string `json:"isa12,omitempty" xml:"ISA12"`
Isa13 string `json:"isa13,omitempty" xml:"ISA13"`
Isa14 string `json:"isa14,omitempty" xml:"ISA14"`
Isa15 string `json:"isa15,omitempty" xml:"ISA15"`
Isa16 string `json:"isa16,omitempty" xml:"ISA16"`
}
type Division271 struct {
GS GS271 `json:"gs,omitempty" xml:"GS"`
HealthCareEligibilityResponse HealthCareEligibilityBenefitResponse271 `json:"eligibility_response,omitempty" xml:"Health_Care_Eligibility_Benefit_Response"`
GE GE271 `json:"ge,omitempty" xml:"GE"`
}
type GS271 struct {
GS01 string `json:"gs01,omitempty" xml:"GS01"`
GS02 string `json:"gs02,omitempty" xml:"GS02"`
GS03 string `json:"gs03,omitempty" xml:"GS03"`
GS04 string `json:"gs04,omitempty" xml:"GS04"`
GS05 string `json:"gs05,omitempty" xml:"GS05"`
GS06 string `json:"gs06,omitempty" xml:"GS06"`
GS07 string `json:"gs07,omitempty" xml:"GS07"`
GS08 string `json:"gs08,omitempty" xml:"GS08"`
}
type GE271 struct {
GE01 string `json:"ge01,omitempty" xml:"GE01"`
GE02 string `json:"ge02,omitempty" xml:"GE02"`
}
type HealthCareEligibilityBenefitResponse271 struct {
ST0010 ST `json:"st0010,omitempty" xml:"ST_0010"`
BHT0020 BHT `json:"bht0020,omitempty" xml:"BHT_0020"`
LoopHL0030 []LoopHL0030271 `json:"hl0030,omitempty" xml:"Loop_HL_0030"`
}
type ST struct {
ST01 string `json:"st01,omitempty" xml:"ST01"`
ST02 string `json:"st02,omitempty" xml:"ST02"`
ST03 string `json:"st03,omitempty" xml:"ST03"`
ST04 string `json:"st04,omitempty" xml:"ST04"`
ST05 string `json:"st05,omitempty" xml:"ST05"`
ST06 string `json:"st06,omitempty" xml:"ST06"`
ST07 string `json:"st07,omitempty" xml:"ST07"`
ST08 string `json:"st08,omitempty" xml:"ST08"`
ST09 string `json:"st09,omitempty" xml:"ST09"`
ST10 string `json:"st10,omitempty" xml:"ST10"`
ST11 string `json:"st11,omitempty" xml:"ST11"`
ST12 string `json:"st12,omitempty" xml:"ST12"`
ST13 string `json:"st13,omitempty" xml:"ST13"`
ST14 string `json:"st14,omitempty" xml:"ST14"`
ST15 string `json:"st15,omitempty" xml:"ST15"`
ST16 string `json:"st16,omitempty" xml:"ST16"`
}
type BHT struct {
BHT01 string `json:"bht01,omitempty" xml:"BHT01"`
BHT02 string `json:"bht02,omitempty" xml:"BHT02"`
BHT03 string `json:"bht03,omitempty" xml:"BHT03"`
BHT04 string `json:"bht04,omitempty" xml:"BHT04"`
BHT05 string `json:"bht05,omitempty" xml:"BHT05"`
BHT06 string `json:"bht06,omitempty" xml:"BHT06"`
BHT07 string `json:"bht07,omitempty" xml:"BHT07"`
BHT08 string `json:"bht08,omitempty" xml:"BHT08"`
BHT09 string `json:"bht09,omitempty" xml:"BHT09"`
BHT10 string `json:"bht10,omitempty" xml:"BHT10"`
BHT11 string `json:"bht11,omitempty" xml:"BHT11"`
BHT12 string `json:"bht12,omitempty" xml:"BHT12"`
BHT13 string `json:"bht13,omitempty" xml:"BHT13"`
BHT14 string `json:"bht14,omitempty" xml:"BHT14"`
BHT15 string `json:"bht15,omitempty" xml:"BHT15"`
BHT16 string `json:"bht16,omitempty" xml:"BHT16"`
}
type LoopHL0030271 struct {
HL_0030 HL `json:"hl_0030,omitempty" xml:"HL_0030"`
NM1_0060 []LoopNM10060 `json:"nm1_0060,omitempty" xml:"Loop_NM1_0060"`
HL_0460 []LoopHL0460 `json:"hl_0460,omitempty" xml:"Loop_HL_0460"`
}
type LoopHL0460 struct {
HL_0460 HL `json:"hl_0460,omitempty" xml:"HL_0460"`
NM1_0490 []LoopNM10490 `json:"nm1_0490,omitempty" xml:"Loop_NM1_0490"`
HL_0890 []LoopHL0890 `json:"hl_0890,omitempty" xml:"Loop_HL_0890"`
}
type LoopNM10490 struct {
NM1_0490 NM1 `json:"nm1_0490,omitempty" xml:"NM1_0490"`
}
type LoopHL0890 struct {
HL_0890 HL `json:"hl_0890,omitempty" xml:"HL_0890"`
TRN_0900 TRN `json:"trn_0900,omitempty" xml:"TRN_0900"`
NM1_0920 []LoopNM10920 `json:"nm1_0920,omitempty" xml:"Loop_NM1_0920"`
}
type REF struct {
REF01 string `json:"ref01,omitempty" xml:"REF01"`
REF02 string `json:"ref02,omitempty" xml:"REF02"`
REF03 string `json:"ref03,omitempty" xml:"REF03"`
REF04 string `json:"ref04,omitempty" xml:"REF04"`
REF05 string `json:"ref05,omitempty" xml:"REF05"`
REF06 string `json:"ref06,omitempty" xml:"REF06"`
REF07 string `json:"ref07,omitempty" xml:"REF07"`
REF08 string `json:"ref08,omitempty" xml:"REF08"`
REF09 string `json:"ref09,omitempty" xml:"REF09"`
REF10 string `json:"ref10,omitempty" xml:"REF10"`
REF11 string `json:"ref11,omitempty" xml:"REF11"`
REF12 string `json:"ref12,omitempty" xml:"REF12"`
REF13 string `json:"ref13,omitempty" xml:"REF13"`
REF14 string `json:"ref14,omitempty" xml:"REF14"`
REF15 string `json:"ref15,omitempty" xml:"REF15"`
REF16 string `json:"ref16,omitempty" xml:"REF16"`
}
type N3 struct {
N301 string `json:"n301,omitempty" xml:"N301"`
N302 string `json:"n302,omitempty" xml:"N302"`
N303 string `json:"n303,omitempty" xml:"N303"`
N304 string `json:"n304,omitempty" xml:"N304"`
N305 string `json:"n305,omitempty" xml:"N305"`
N306 string `json:"n306,omitempty" xml:"N306"`
N307 string `json:"n307,omitempty" xml:"N307"`
N308 string `json:"n308,omitempty" xml:"N308"`
N309 string `json:"n309,omitempty" xml:"N309"`
N310 string `json:"n310,omitempty" xml:"N310"`
N311 string `json:"n311,omitempty" xml:"N311"`
N312 string `json:"n312,omitempty" xml:"N312"`
N313 string `json:"n313,omitempty" xml:"N313"`
N314 string `json:"n314,omitempty" xml:"N314"`
N315 string `json:"n315,omitempty" xml:"N315"`
N316 string `json:"n316,omitempty" xml:"N316"`
}
type N4 struct {
N401 string `json:"n401,omitempty" xml:"N401"`
N402 string `json:"n402,omitempty" xml:"N402"`
N403 string `json:"n403,omitempty" xml:"N403"`
N404 string `json:"n404,omitempty" xml:"N404"`
N405 string `json:"n405,omitempty" xml:"N405"`
N406 string `json:"n406,omitempty" xml:"N406"`
N407 string `json:"n407,omitempty" xml:"N407"`
N408 string `json:"n408,omitempty" xml:"N408"`
N409 string `json:"n409,omitempty" xml:"N409"`
N410 string `json:"n410,omitempty" xml:"N410"`
N411 string `json:"n411,omitempty" xml:"N411"`
N412 string `json:"n412,omitempty" xml:"N412"`
N413 string `json:"n413,omitempty" xml:"N413"`
N414 string `json:"n414,omitempty" xml:"N414"`
N415 string `json:"n415,omitempty" xml:"N415"`
N416 string `json:"n416,omitempty" xml:"N416"`
}
type LoopNM10920 struct {
NM1_0920 NM1 `json:"nm1_0920,omitempty" xml:"NM1_0920"`
REF_0930 []REF `json:"ref_0930,omitempty" xml:"REF_0930"`
N3_0950 N3 `json:"n3_0950,omitempty" xml:"N3_0950"`
N4_0960 N4 `json:"n4_0960,omitempty" xml:"N4_0960"`
DMG_1000 DMG `json:"dmg_1000,omitempty" xml:"DMG_1000"`
INS_1010 INS `json:"ins_1010,omitempty" xml:"INS_1010"`
}
type DMG struct {
DMG01 string `json:"dmg01,omitempty" xml:"DMG01"`
DMG02 string `json:"dmg02,omitempty" xml:"DMG02"`
DMG03 string `json:"dmg03,omitempty" xml:"DMG03"`
DMG04 string `json:"dmg04,omitempty" xml:"DMG04"`
DMG05 string `json:"dmg05,omitempty" xml:"DMG05"`
DMG06 string `json:"dmg06,omitempty" xml:"DMG06"`
DMG07 string `json:"dmg07,omitempty" xml:"DMG07"`
DMG08 string `json:"dmg08,omitempty" xml:"DMG08"`
DMG09 string `json:"dmg09,omitempty" xml:"DMG09"`
DMG10 string `json:"dmg10,omitempty" xml:"DMG10"`
DMG11 string `json:"dmg11,omitempty" xml:"DMG11"`
DMG12 string `json:"dmg12,omitempty" xml:"DMG12"`
DMG13 string `json:"dmg13,omitempty" xml:"DMG13"`
DMG14 string `json:"dmg14,omitempty" xml:"DMG14"`
DMG15 string `json:"dmg15,omitempty" xml:"DMG15"`
DMG16 string `json:"dmg16,omitempty" xml:"DMG16"`
}
type INS struct {
INS01 string `json:"ins01,omitempty" xml:"INS01"`
INS02 string `json:"ins02,omitempty" xml:"INS02"`
INS03 string `json:"ins03,omitempty" xml:"INS03"`
INS04 string `json:"ins04,omitempty" xml:"INS04"`
INS05 string `json:"ins05,omitempty" xml:"INS05"`
INS06 string `json:"ins06,omitempty" xml:"INS06"`
INS07 string `json:"ins07,omitempty" xml:"INS07"`
INS08 string `json:"ins08,omitempty" xml:"INS08"`
INS09 string `json:"ins09,omitempty" xml:"INS09"`
INS10 string `json:"ins10,omitempty" xml:"INS10"`
INS11 string `json:"ins11,omitempty" xml:"INS11"`
INS12 string `json:"ins12,omitempty" xml:"INS12"`
INS13 string `json:"ins13,omitempty" xml:"INS13"`
INS14 string `json:"ins14,omitempty" xml:"INS14"`
INS15 string `json:"ins15,omitempty" xml:"INS15"`
INS16 string `json:"ins16,omitempty" xml:"INS16"`
}
type TRN struct {
TRN01 string `json:"trn01,omitempty" xml:"TRN01"`
TRN02 string `json:"trn02,omitempty" xml:"TRN02"`
TRN03 string `json:"trn03,omitempty" xml:"TRN03"`
TRN04 string `json:"trn04,omitempty" xml:"TRN04"`
TRN05 string `json:"trn05,omitempty" xml:"TRN05"`
TRN06 string `json:"trn06,omitempty" xml:"TRN06"`
TRN07 string `json:"trn07,omitempty" xml:"TRN07"`
TRN08 string `json:"trn08,omitempty" xml:"TRN08"`
TRN09 string `json:"trn09,omitempty" xml:"TRN09"`
TRN10 string `json:"trn10,omitempty" xml:"TRN10"`
TRN11 string `json:"trn11,omitempty" xml:"TRN11"`
TRN12 string `json:"trn12,omitempty" xml:"TRN12"`
TRN13 string `json:"trn13,omitempty" xml:"TRN13"`
TRN14 string `json:"trn14,omitempty" xml:"TRN14"`
TRN15 string `json:"trn15,omitempty" xml:"TRN15"`
TRN16 string `json:"trn16,omitempty" xml:"TRN16"`
}
type HL struct {
HL01 string `json:"hl01,omitempty" xml:"HL01"`
HL02 string `json:"hl02,omitempty" xml:"HL02"`
HL03 string `json:"hl03,omitempty" xml:"HL03"`
HL04 string `json:"hl04,omitempty" xml:"HL04"`
HL05 string `json:"hl05,omitempty" xml:"HL05"`
HL06 string `json:"hl06,omitempty" xml:"HL06"`
HL07 string `json:"hl07,omitempty" xml:"HL07"`
HL08 string `json:"hl08,omitempty" xml:"HL08"`
HL09 string `json:"hl09,omitempty" xml:"HL09"`
HL10 string `json:"hl10,omitempty" xml:"HL10"`
HL11 string `json:"hl11,omitempty" xml:"HL11"`
HL12 string `json:"hl12,omitempty" xml:"HL12"`
HL13 string `json:"hl13,omitempty" xml:"HL13"`
HL14 string `json:"hl14,omitempty" xml:"HL14"`
HL15 string `json:"hl15,omitempty" xml:"HL15"`
HL16 string `json:"hl16,omitempty" xml:"HL16"`
}
type LoopNM10060 struct {
NM10060 NM1 `json:"nm1_0060,omitempty" xml:"NM1_0060"`
}
type NM1 struct {
NM101 string `json:"nm101,omitempty" xml:"NM101"`
NM102 string `json:"nm102,omitempty" xml:"NM102"`
NM103 string `json:"nm103,omitempty" xml:"NM103"`
NM104 string `json:"nm104,omitempty" xml:"NM104"`
NM105 string `json:"nm105,omitempty" xml:"NM105"`
NM106 string `json:"nm106,omitempty" xml:"NM106"`
NM107 string `json:"nm107,omitempty" xml:"NM107"`
NM108 string `json:"nm108,omitempty" xml:"NM108"`
NM109 string `json:"nm109,omitempty" xml:"NM109"`
NM110 string `json:"nm110,omitempty" xml:"NM110"`
NM111 string `json:"nm111,omitempty" xml:"NM111"`
NM112 string `json:"nm112,omitempty" xml:"NM112"`
NM113 string `json:"nm113,omitempty" xml:"NM113"`
NM114 string `json:"nm114,omitempty" xml:"NM114"`
NM115 string `json:"nm115,omitempty" xml:"NM115"`
NM116 string `json:"nm116,omitempty" xml:"NM116"`
}

View File

@@ -5,7 +5,9 @@ import (
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"encoding/xml" "encoding/xml"
"errors"
"fmt" "fmt"
"html"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strings" "strings"
@@ -72,14 +74,34 @@ func (s bxeService) GetPayerDetails(subscriberID string) ([]bcbsimodel.EntityRes
return response, nil return response, nil
} }
func (s bxeService) CheckEligibility(eligibility viewmodel.Eligibility) (bcbsimodel.MemberEligibilityResponse, error) { func (s bxeService) Get271(eligibility viewmodel.Eligibility) (bcbsimodel.Interchange271, error) {
payer, err := s.GetPayerDetails(eligibility.Subscriber.SubscriberID) resp, err := s.CheckEligibility(eligibility)
if err != nil { if err != nil {
return bcbsimodel.MemberEligibilityResponse{}, err return bcbsimodel.Interchange271{}, err
} }
eligibility.Payer.PayerID = payer[0].ID if resp.QueryResult.HIPPA271.T271 != "" {
eligibility.Payer.PayerName = payer[0].Name xmlString := html.UnescapeString(resp.QueryResult.HIPPA271.T271)
xmlReader := strings.NewReader(xmlString)
var f bcbsimodel.Interchange271
err = xml.NewDecoder(xmlReader).Decode(&f)
if err != nil {
fmt.Println("Error to unmarshal: ", err.Error())
return bcbsimodel.Interchange271{}, err
}
return f, nil
} else {
return bcbsimodel.Interchange271{}, errors.New("No 271 response")
}
}
func (s bxeService) CheckEligibility(eligibility viewmodel.Eligibility) (bcbsimodel.MemberEligibilityResponse, error) {
if eligibility.Payer.PayerID == "" || eligibility.Payer.PayerName == "" {
eligibility.Payer.PayerID = "621"
eligibility.Payer.PayerName = "blue_cross_blue_shield_il"
}
envelope := bcbsimodel.GetEnvelope(eligibility) envelope := bcbsimodel.GetEnvelope(eligibility)
apiKey := s.cfg.BXE.APIKey apiKey := s.cfg.BXE.APIKey
@@ -97,16 +119,19 @@ func (s bxeService) CheckEligibility(eligibility viewmodel.Eligibility) (bcbsimo
req.Header.Add("X-Api-Key", apiKey) req.Header.Add("X-Api-Key", apiKey)
req.Header.Add("X-Signature", s.getSignature(apiKey, secretKey)) req.Header.Add("X-Signature", s.getSignature(apiKey, secretKey))
eligibilityCall := time.Now()
fmt.Println(fmt.Sprintf("Start eligibility call %s at %s", eligibility.TrackingID, eligibilityCall.Format("2006-01-02 15:04:05 PM")))
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
fmt.Println("Error WebService: ", err) fmt.Println("Error WebService Request: ", err)
return bcbsimodel.MemberEligibilityResponse{}, err return bcbsimodel.MemberEligibilityResponse{}, err
} }
fmt.Println(fmt.Sprintf("Getting Response from eligibility call %s at %s, duration %f seconds", eligibility.TrackingID, time.Now().Format("2006-01-02 15:04:05 PM"), time.Since(eligibilityCall).Seconds()))
defer resp.Body.Close() defer resp.Body.Close()
bReturn, err := ioutil.ReadAll(resp.Body) bReturn, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
fmt.Println("Error WebService: ", err) fmt.Println("Error WebService getting byte: ", err)
return bcbsimodel.MemberEligibilityResponse{}, err return bcbsimodel.MemberEligibilityResponse{}, err
} }
@@ -118,7 +143,7 @@ func (s bxeService) CheckEligibility(eligibility viewmodel.Eligibility) (bcbsimo
var result bcbsimodel.EnvelopeResponse var result bcbsimodel.EnvelopeResponse
err = xml.Unmarshal([]byte(sResponse), &result) err = xml.Unmarshal([]byte(sResponse), &result)
if err != nil { if err != nil {
fmt.Println("Error WebService: ", err) fmt.Println("Error WebService getting object: ", err)
return bcbsimodel.MemberEligibilityResponse{}, err return bcbsimodel.MemberEligibilityResponse{}, err
} }

View File

@@ -262,6 +262,7 @@ func (s *lyftService) RequestRide(rideRequest viewmodel.RideRequest) (viewmodel.
if raw.Error != "" { if raw.Error != "" {
fmt.Println("Error to call Lyft: ", raw.Error+" - "+raw.ErrorDescription) fmt.Println("Error to call Lyft: ", raw.Error+" - "+raw.ErrorDescription)
fmt.Println("Full body error: ", string(body))
return viewmodel.RideRequest{}, errors.New("Lyft Error: " + raw.Error + " - " + raw.ErrorDescription) return viewmodel.RideRequest{}, errors.New("Lyft Error: " + raw.Error + " - " + raw.ErrorDescription)
} }

View File

@@ -1,6 +1,7 @@
package viewmodel package viewmodel
import ( import (
"encoding/xml"
"time" "time"
) )
@@ -10,6 +11,7 @@ type Eligibility struct {
Provider Provider `json:"provider,omitempty"` Provider Provider `json:"provider,omitempty"`
Subscriber Subscriber `json:"subscriber,omitempty"` Subscriber Subscriber `json:"subscriber,omitempty"`
ServiceInfo ServiceInfo `json:"service_info,omitempty"` ServiceInfo ServiceInfo `json:"service_info,omitempty"`
User User `json:"user,omitempty"`
} }
type Payer struct { type Payer struct {
@@ -53,3 +55,287 @@ type ServiceInfo struct {
DateOfService time.Time `json:"date_of_service,omitempty"` DateOfService time.Time `json:"date_of_service,omitempty"`
ServiceTypeCodes []string `json:"service_type_codes,omitempty"` ServiceTypeCodes []string `json:"service_type_codes,omitempty"`
} }
type Interchange271 struct {
XMLName xml.Name `json:"-" xml:"Interchange"`
Isa ISA271 `json:"isa,omitempty" xml:"ISA"`
Division Division271 `json:"division,omitempty" xml:"Division"`
IEA IEA271 `json:"iea,omitempty" xml:"IEA"`
}
type IEA271 struct {
IEA01 string `json:"iea01,omitempty" xml:"IEA01"`
IEA02 string `json:"iea02,omitempty" xml:"IEA02"`
}
type ISA271 struct {
Isa01 string `json:"isa01,omitempty" xml:"ISA01"`
Isa02 string `json:"isa02,omitempty" xml:"ISA02"`
Isa03 string `json:"isa03,omitempty" xml:"ISA03"`
Isa04 string `json:"isa04,omitempty" xml:"ISA04"`
Isa05 string `json:"isa05,omitempty" xml:"ISA05"`
Isa06 string `json:"isa06,omitempty" xml:"ISA06"`
Isa07 string `json:"isa07,omitempty" xml:"ISA07"`
Isa08 string `json:"isa08,omitempty" xml:"ISA08"`
Isa09 string `json:"isa09,omitempty" xml:"ISA09"`
Isa10 string `json:"isa10,omitempty" xml:"ISA10"`
Isa11 string `json:"isa11,omitempty" xml:"ISA11"`
Isa12 string `json:"isa12,omitempty" xml:"ISA12"`
Isa13 string `json:"isa13,omitempty" xml:"ISA13"`
Isa14 string `json:"isa14,omitempty" xml:"ISA14"`
Isa15 string `json:"isa15,omitempty" xml:"ISA15"`
Isa16 string `json:"isa16,omitempty" xml:"ISA16"`
}
type Division271 struct {
GS GS271 `json:"gs,omitempty" xml:"GS"`
HealthCareEligibilityResponse HealthCareEligibilityBenefitResponse271 `json:"eligibility_response,omitempty" xml:"Health_Care_Eligibility_Benefit_Response"`
GE GE271 `json:"ge,omitempty" xml:"GE"`
}
type GS271 struct {
GS01 string `json:"gs01,omitempty" xml:"GS01"`
GS02 string `json:"gs02,omitempty" xml:"GS02"`
GS03 string `json:"gs03,omitempty" xml:"GS03"`
GS04 string `json:"gs04,omitempty" xml:"GS04"`
GS05 string `json:"gs05,omitempty" xml:"GS05"`
GS06 string `json:"gs06,omitempty" xml:"GS06"`
GS07 string `json:"gs07,omitempty" xml:"GS07"`
GS08 string `json:"gs08,omitempty" xml:"GS08"`
}
type GE271 struct {
GE01 string `json:"ge01,omitempty" xml:"GE01"`
GE02 string `json:"ge02,omitempty" xml:"GE02"`
}
type HealthCareEligibilityBenefitResponse271 struct {
ST0010 ST `json:"st0010,omitempty" xml:"ST_0010"`
BHT0020 BHT `json:"bht0020,omitempty" xml:"BHT_0020"`
LoopHL0030 []LoopHL0030271 `json:"hl0030,omitempty" xml:"Loop_HL_0030"`
}
type ST struct {
ST01 string `json:"st01,omitempty" xml:"ST01"`
ST02 string `json:"st02,omitempty" xml:"ST02"`
ST03 string `json:"st03,omitempty" xml:"ST03"`
ST04 string `json:"st04,omitempty" xml:"ST04"`
ST05 string `json:"st05,omitempty" xml:"ST05"`
ST06 string `json:"st06,omitempty" xml:"ST06"`
ST07 string `json:"st07,omitempty" xml:"ST07"`
ST08 string `json:"st08,omitempty" xml:"ST08"`
ST09 string `json:"st09,omitempty" xml:"ST09"`
ST10 string `json:"st10,omitempty" xml:"ST10"`
ST11 string `json:"st11,omitempty" xml:"ST11"`
ST12 string `json:"st12,omitempty" xml:"ST12"`
ST13 string `json:"st13,omitempty" xml:"ST13"`
ST14 string `json:"st14,omitempty" xml:"ST14"`
ST15 string `json:"st15,omitempty" xml:"ST15"`
ST16 string `json:"st16,omitempty" xml:"ST16"`
}
type BHT struct {
BHT01 string `json:"bht01,omitempty" xml:"BHT01"`
BHT02 string `json:"bht02,omitempty" xml:"BHT02"`
BHT03 string `json:"bht03,omitempty" xml:"BHT03"`
BHT04 string `json:"bht04,omitempty" xml:"BHT04"`
BHT05 string `json:"bht05,omitempty" xml:"BHT05"`
BHT06 string `json:"bht06,omitempty" xml:"BHT06"`
BHT07 string `json:"bht07,omitempty" xml:"BHT07"`
BHT08 string `json:"bht08,omitempty" xml:"BHT08"`
BHT09 string `json:"bht09,omitempty" xml:"BHT09"`
BHT10 string `json:"bht10,omitempty" xml:"BHT10"`
BHT11 string `json:"bht11,omitempty" xml:"BHT11"`
BHT12 string `json:"bht12,omitempty" xml:"BHT12"`
BHT13 string `json:"bht13,omitempty" xml:"BHT13"`
BHT14 string `json:"bht14,omitempty" xml:"BHT14"`
BHT15 string `json:"bht15,omitempty" xml:"BHT15"`
BHT16 string `json:"bht16,omitempty" xml:"BHT16"`
}
type LoopHL0030271 struct {
HL_0030 HL `json:"hl_0030,omitempty" xml:"HL_0030"`
NM1_0060 []LoopNM10060 `json:"nm1_0060,omitempty" xml:"Loop_NM1_0060"`
HL_0460 []LoopHL0460 `json:"hl_0460,omitempty" xml:"Loop_HL_0460"`
}
type LoopHL0460 struct {
HL_0460 HL `json:"hl_0460,omitempty" xml:"HL_0460"`
NM1_0490 []LoopNM10490 `json:"nm1_0490,omitempty" xml:"Loop_NM1_0490"`
HL_0890 []LoopHL0890 `json:"hl_0890,omitempty" xml:"Loop_HL_0890"`
}
type LoopNM10490 struct {
NM1_0490 NM1 `json:"nm1_0490,omitempty" xml:"NM1_0490"`
}
type LoopHL0890 struct {
HL_0890 HL `json:"hl_0890,omitempty" xml:"HL_0890"`
TRN_0900 TRN `json:"trn_0900,omitempty" xml:"TRN_0900"`
NM1_0920 []LoopNM10920 `json:"nm1_0920,omitempty" xml:"Loop_NM1_0920"`
}
type REF struct {
REF01 string `json:"ref01,omitempty" xml:"REF01"`
REF02 string `json:"ref02,omitempty" xml:"REF02"`
REF03 string `json:"ref03,omitempty" xml:"REF03"`
REF04 string `json:"ref04,omitempty" xml:"REF04"`
REF05 string `json:"ref05,omitempty" xml:"REF05"`
REF06 string `json:"ref06,omitempty" xml:"REF06"`
REF07 string `json:"ref07,omitempty" xml:"REF07"`
REF08 string `json:"ref08,omitempty" xml:"REF08"`
REF09 string `json:"ref09,omitempty" xml:"REF09"`
REF10 string `json:"ref10,omitempty" xml:"REF10"`
REF11 string `json:"ref11,omitempty" xml:"REF11"`
REF12 string `json:"ref12,omitempty" xml:"REF12"`
REF13 string `json:"ref13,omitempty" xml:"REF13"`
REF14 string `json:"ref14,omitempty" xml:"REF14"`
REF15 string `json:"ref15,omitempty" xml:"REF15"`
REF16 string `json:"ref16,omitempty" xml:"REF16"`
}
type N3 struct {
N301 string `json:"n301,omitempty" xml:"N301"`
N302 string `json:"n302,omitempty" xml:"N302"`
N303 string `json:"n303,omitempty" xml:"N303"`
N304 string `json:"n304,omitempty" xml:"N304"`
N305 string `json:"n305,omitempty" xml:"N305"`
N306 string `json:"n306,omitempty" xml:"N306"`
N307 string `json:"n307,omitempty" xml:"N307"`
N308 string `json:"n308,omitempty" xml:"N308"`
N309 string `json:"n309,omitempty" xml:"N309"`
N310 string `json:"n310,omitempty" xml:"N310"`
N311 string `json:"n311,omitempty" xml:"N311"`
N312 string `json:"n312,omitempty" xml:"N312"`
N313 string `json:"n313,omitempty" xml:"N313"`
N314 string `json:"n314,omitempty" xml:"N314"`
N315 string `json:"n315,omitempty" xml:"N315"`
N316 string `json:"n316,omitempty" xml:"N316"`
}
type N4 struct {
N401 string `json:"n401,omitempty" xml:"N401"`
N402 string `json:"n402,omitempty" xml:"N402"`
N403 string `json:"n403,omitempty" xml:"N403"`
N404 string `json:"n404,omitempty" xml:"N404"`
N405 string `json:"n405,omitempty" xml:"N405"`
N406 string `json:"n406,omitempty" xml:"N406"`
N407 string `json:"n407,omitempty" xml:"N407"`
N408 string `json:"n408,omitempty" xml:"N408"`
N409 string `json:"n409,omitempty" xml:"N409"`
N410 string `json:"n410,omitempty" xml:"N410"`
N411 string `json:"n411,omitempty" xml:"N411"`
N412 string `json:"n412,omitempty" xml:"N412"`
N413 string `json:"n413,omitempty" xml:"N413"`
N414 string `json:"n414,omitempty" xml:"N414"`
N415 string `json:"n415,omitempty" xml:"N415"`
N416 string `json:"n416,omitempty" xml:"N416"`
}
type LoopNM10920 struct {
NM1_0920 NM1 `json:"nm1_0920,omitempty" xml:"NM1_0920"`
REF_0930 []REF `json:"ref_0930,omitempty" xml:"REF_0930"`
N3_0950 N3 `json:"n3_0950,omitempty" xml:"N3_0950"`
N4_0960 N4 `json:"n4_0960,omitempty" xml:"N4_0960"`
DMG_1000 DMG `json:"dmg_1000,omitempty" xml:"DMG_1000"`
INS_1010 INS `json:"ins_1010,omitempty" xml:"INS_1010"`
}
type DMG struct {
DMG01 string `json:"dmg01,omitempty" xml:"DMG01"`
DMG02 string `json:"dmg02,omitempty" xml:"DMG02"`
DMG03 string `json:"dmg03,omitempty" xml:"DMG03"`
DMG04 string `json:"dmg04,omitempty" xml:"DMG04"`
DMG05 string `json:"dmg05,omitempty" xml:"DMG05"`
DMG06 string `json:"dmg06,omitempty" xml:"DMG06"`
DMG07 string `json:"dmg07,omitempty" xml:"DMG07"`
DMG08 string `json:"dmg08,omitempty" xml:"DMG08"`
DMG09 string `json:"dmg09,omitempty" xml:"DMG09"`
DMG10 string `json:"dmg10,omitempty" xml:"DMG10"`
DMG11 string `json:"dmg11,omitempty" xml:"DMG11"`
DMG12 string `json:"dmg12,omitempty" xml:"DMG12"`
DMG13 string `json:"dmg13,omitempty" xml:"DMG13"`
DMG14 string `json:"dmg14,omitempty" xml:"DMG14"`
DMG15 string `json:"dmg15,omitempty" xml:"DMG15"`
DMG16 string `json:"dmg16,omitempty" xml:"DMG16"`
}
type INS struct {
INS01 string `json:"ins01,omitempty" xml:"INS01"`
INS02 string `json:"ins02,omitempty" xml:"INS02"`
INS03 string `json:"ins03,omitempty" xml:"INS03"`
INS04 string `json:"ins04,omitempty" xml:"INS04"`
INS05 string `json:"ins05,omitempty" xml:"INS05"`
INS06 string `json:"ins06,omitempty" xml:"INS06"`
INS07 string `json:"ins07,omitempty" xml:"INS07"`
INS08 string `json:"ins08,omitempty" xml:"INS08"`
INS09 string `json:"ins09,omitempty" xml:"INS09"`
INS10 string `json:"ins10,omitempty" xml:"INS10"`
INS11 string `json:"ins11,omitempty" xml:"INS11"`
INS12 string `json:"ins12,omitempty" xml:"INS12"`
INS13 string `json:"ins13,omitempty" xml:"INS13"`
INS14 string `json:"ins14,omitempty" xml:"INS14"`
INS15 string `json:"ins15,omitempty" xml:"INS15"`
INS16 string `json:"ins16,omitempty" xml:"INS16"`
}
type TRN struct {
TRN01 string `json:"trn01,omitempty" xml:"TRN01"`
TRN02 string `json:"trn02,omitempty" xml:"TRN02"`
TRN03 string `json:"trn03,omitempty" xml:"TRN03"`
TRN04 string `json:"trn04,omitempty" xml:"TRN04"`
TRN05 string `json:"trn05,omitempty" xml:"TRN05"`
TRN06 string `json:"trn06,omitempty" xml:"TRN06"`
TRN07 string `json:"trn07,omitempty" xml:"TRN07"`
TRN08 string `json:"trn08,omitempty" xml:"TRN08"`
TRN09 string `json:"trn09,omitempty" xml:"TRN09"`
TRN10 string `json:"trn10,omitempty" xml:"TRN10"`
TRN11 string `json:"trn11,omitempty" xml:"TRN11"`
TRN12 string `json:"trn12,omitempty" xml:"TRN12"`
TRN13 string `json:"trn13,omitempty" xml:"TRN13"`
TRN14 string `json:"trn14,omitempty" xml:"TRN14"`
TRN15 string `json:"trn15,omitempty" xml:"TRN15"`
TRN16 string `json:"trn16,omitempty" xml:"TRN16"`
}
type HL struct {
HL01 string `json:"hl01,omitempty" xml:"HL01"`
HL02 string `json:"hl02,omitempty" xml:"HL02"`
HL03 string `json:"hl03,omitempty" xml:"HL03"`
HL04 string `json:"hl04,omitempty" xml:"HL04"`
HL05 string `json:"hl05,omitempty" xml:"HL05"`
HL06 string `json:"hl06,omitempty" xml:"HL06"`
HL07 string `json:"hl07,omitempty" xml:"HL07"`
HL08 string `json:"hl08,omitempty" xml:"HL08"`
HL09 string `json:"hl09,omitempty" xml:"HL09"`
HL10 string `json:"hl10,omitempty" xml:"HL10"`
HL11 string `json:"hl11,omitempty" xml:"HL11"`
HL12 string `json:"hl12,omitempty" xml:"HL12"`
HL13 string `json:"hl13,omitempty" xml:"HL13"`
HL14 string `json:"hl14,omitempty" xml:"HL14"`
HL15 string `json:"hl15,omitempty" xml:"HL15"`
HL16 string `json:"hl16,omitempty" xml:"HL16"`
}
type LoopNM10060 struct {
NM10060 NM1 `json:"nm1_0060,omitempty" xml:"NM1_0060"`
}
type NM1 struct {
NM101 string `json:"nm101,omitempty" xml:"NM101"`
NM102 string `json:"nm102,omitempty" xml:"NM102"`
NM103 string `json:"nm103,omitempty" xml:"NM103"`
NM104 string `json:"nm104,omitempty" xml:"NM104"`
NM105 string `json:"nm105,omitempty" xml:"NM105"`
NM106 string `json:"nm106,omitempty" xml:"NM106"`
NM107 string `json:"nm107,omitempty" xml:"NM107"`
NM108 string `json:"nm108,omitempty" xml:"NM108"`
NM109 string `json:"nm109,omitempty" xml:"NM109"`
NM110 string `json:"nm110,omitempty" xml:"NM110"`
NM111 string `json:"nm111,omitempty" xml:"NM111"`
NM112 string `json:"nm112,omitempty" xml:"NM112"`
NM113 string `json:"nm113,omitempty" xml:"NM113"`
NM114 string `json:"nm114,omitempty" xml:"NM114"`
NM115 string `json:"nm115,omitempty" xml:"NM115"`
NM116 string `json:"nm116,omitempty" xml:"NM116"`
}

View File

@@ -0,0 +1,15 @@
package viewmodel
type Plan struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
InternalID string `json:"key,omitempty"`
Status bool `json:"desc,omitempty"`
PlanEntityID int64 `json:"plan_entity_id,omitempty"`
EntityID int64 `json:"entity_id,omitempty"`
PayerID int64 `json:"payer_id,omitempty"`
PayerName string `json:"payer_name,omitempty"`
PrefixID string `json:"prefix_uuid,omitempty"`
AlphaPrefix string `json:"alpha_prefix,omitempty"`
Active bool `json:"active,omitempty"`
}

View File

@@ -16,6 +16,7 @@ type ProviderResp struct {
Keys []ProviderKey `json:"keys,omitempty"` Keys []ProviderKey `json:"keys,omitempty"`
Address ProviderAddress `json:"address,omitempty"` Address ProviderAddress `json:"address,omitempty"`
Distance float64 `json:"distance,omitempty"` Distance float64 `json:"distance,omitempty"`
Organization Organization `json:"organization,omitempty"`
} }
type ProviderKey struct { type ProviderKey struct {

View File

@@ -14,49 +14,53 @@ type WebhookResponse struct {
//RideRequest has the data to dispatch a ride //RideRequest has the data to dispatch a ride
type RideRequest struct { type RideRequest struct {
UserUUID string `json:"user_uuid,omitempty"` UserUUID string `json:"user_uuid,omitempty"`
Status string `json:"status,omitempty"` UserConsent bool `json:"user_consent,omitempty"`
RideID string `json:"ride_id,omitempty"` Status string `json:"status,omitempty"`
RideType string `json:"ride_type,omitempty"` RideID string `json:"ride_id,omitempty"`
Origin Location `json:"origin,omitempty"` RideType string `json:"ride_type,omitempty"`
Location Location `json:"location,omitempty"` Origin Location `json:"origin,omitempty"`
Destination Location `json:"destination,omitempty"` Location Location `json:"location,omitempty"`
Passenger UserLyft `json:"passenger,omitempty"` Destination Location `json:"destination,omitempty"`
Notes string `json:"external_note,omitempty"` Passenger UserLyft `json:"passenger,omitempty"`
RouteURL string `json:"route_url,omitempty"` Notes string `json:"external_note,omitempty"`
ScheduledPickupRange interface{} `json:"scheduled_pickup_range,omitempty"` RouteURL string `json:"route_url,omitempty"`
PrimetimePercentage string `json:"primetime_percentage,omitempty"` ScheduledPickupRange interface{} `json:"scheduled_pickup_range,omitempty"`
Pickup Location `json:"pickup,omitempty"` PrimetimePercentage string `json:"primetime_percentage,omitempty"`
DropOff Location `json:"dropoff,omitempty"` Pickup Location `json:"pickup,omitempty"`
Vehicle Vehicle `json:"vehicle,omitempty"` DropOff Location `json:"dropoff,omitempty"`
Price Price `json:"price,omitempty"` Vehicle Vehicle `json:"vehicle,omitempty"`
Driver UserLyft `json:"driver,omitempty"` Price Price `json:"price,omitempty"`
GeneratedAtMS *int64 `json:"generated_at_ms,omitempty"` Driver UserLyft `json:"driver,omitempty"`
GeneratedAt *time.Time `json:"generated_at,omitempty"` GeneratedAtMS *int64 `json:"generated_at_ms,omitempty"`
RequestAtMS *int64 `json:"requested_at_ms,omitempty"` GeneratedAt *time.Time `json:"generated_at,omitempty"`
RequestAt *time.Time `json:"requested_at,omitempty"` RequestAtMS *int64 `json:"requested_at_ms,omitempty"`
LineItems []Price `json:"line_items,omitempty"` RequestAt *time.Time `json:"requested_at,omitempty"`
BeaconColor string `json:"beacon_color,omitempty"` LineItems []Price `json:"line_items,omitempty"`
Charges []Charge `json:"charges,omitempty"` BeaconColor string `json:"beacon_color,omitempty"`
VisitDate *time.Time `json:"visit_date,omitempty"` Charges []Charge `json:"charges,omitempty"`
VisitTime *time.Time `json:"visit_time,omitempty"` VisitDate *time.Time `json:"visit_date,omitempty"`
PickupTime *time.Time `json:"pickup_time,omitempty"` VisitTime *time.Time `json:"visit_time,omitempty"`
ReturnTime *time.Time `json:"return_time,omitempty"` PickupTime *time.Time `json:"pickup_time,omitempty"`
Distance float64 `json:"distance,omitempty"` ReturnTime *time.Time `json:"return_time,omitempty"`
ETA int64 `json:"eta,omitempty"` Distance float64 `json:"distance,omitempty"`
Duration int64 `json:"duration,omitempty"` ETA int64 `json:"eta,omitempty"`
Visit Visit `json:"visit,omitempty"` Duration int64 `json:"duration,omitempty"`
CreateUserUUID string `json:"created_user_uuid,omitempty"` Visit Visit `json:"visit,omitempty"`
VisitExternalID string `json:"visit_external_id,omitempty"` CreateUserUUID string `json:"created_user_uuid,omitempty"`
CanCancel []string `json:"can_cancel,omitempty"` VisitExternalID string `json:"visit_external_id,omitempty"`
PricingDetailsURL string `json:"pricing_details_url,omitempty"` CanCancel []string `json:"can_cancel,omitempty"`
RideProfile string `json:"ride_profile,omitempty"` PricingDetailsURL string `json:"pricing_details_url,omitempty"`
DistanceInMiles float64 `json:"distance_miles,omitempty"` RideProfile string `json:"ride_profile,omitempty"`
DurationInSeconds float64 `json:"duration_seconds,omitempty"` DistanceInMiles float64 `json:"distance_miles,omitempty"`
CanceledBy string `json:"canceled_by,omitempty"` DurationInSeconds float64 `json:"duration_seconds,omitempty"`
TripType TripType `json:"trip_type,omitempty"` CanceledBy string `json:"canceled_by,omitempty"`
Error string `json:"error,omitempty"` TripType TripType `json:"trip_type,omitempty"`
ErrorDescription string `json:"error_description,omitempty"` Error string `json:"error,omitempty"`
ErrorDescription string `json:"error_description,omitempty"`
User User `json:"user,omitempty"`
Provider ProviderResp `json:"provider,omitempty"`
RawProvider ProviderResponse `json:"raw_provider,omitempty"`
} }
//Charge information //Charge information

View File

@@ -13,6 +13,7 @@ type User struct {
BirthDate *time.Time `json:"birthdate,omitempty"` BirthDate *time.Time `json:"birthdate,omitempty"`
Email *string `json:"email,omitempty"` Email *string `json:"email,omitempty"`
PhoneNumber *string `json:"phonenumber,omitempty"` PhoneNumber *string `json:"phonenumber,omitempty"`
Type *string `json:"type,omitempty"`
Pass string `json:"pass,omitempty"` Pass string `json:"pass,omitempty"`
Active bool `json:"active,omitempty"` Active bool `json:"active,omitempty"`
Created time.Time `json:"created,omitempty"` Created time.Time `json:"created,omitempty"`
@@ -23,11 +24,16 @@ type User struct {
Profiles []Profile `json:"profiles,omitempty"` Profiles []Profile `json:"profiles,omitempty"`
Types []OrganizationType `json:"types,omitempty"` Types []OrganizationType `json:"types,omitempty"`
Organizations []Organization `json:"organizations,omitempty"` Organizations []Organization `json:"organizations,omitempty"`
Provider *ProviderResp `json:"provider,omitempty"`
Consent bool `json:"consent,omitempty"`
} }
type Contact struct { type Contact struct {
Type ContactType `json:"type,omitempty"` ID string `json:"id,omitempty"`
Value string `json:"contact,omitempty"` User User `json:"-"`
Type ContactType `json:"type,omitempty"`
Value string `json:"contact,omitempty"`
Author User `json:"-"`
} }
type ContactType struct { type ContactType struct {

View File

@@ -12,22 +12,23 @@ type VisitStatus struct {
// Visit entity data // Visit entity data
type Visit struct { type Visit struct {
UUID string `json:"visit_uuid,omitempty"` UUID string `json:"visit_uuid,omitempty"`
Status VisitStatus `json:"visit_status,omitempty"` Status VisitStatus `json:"visit_status,omitempty"`
User User `json:"user,omitempty"` User User `json:"user,omitempty"`
VisitDatetime time.Time `json:"visit_datetime,omitempty"` VisitDatetime time.Time `json:"visit_datetime,omitempty"`
VisitDuration int64 `json:"visit_duration,omitempty"` VisitDuration int64 `json:"visit_duration,omitempty"`
PickupDatetime time.Time `json:"pickup_datetime,omitempty"` PickupDatetime time.Time `json:"pickup_datetime,omitempty"`
Notes *string `json:"notes,omitempty"` Notes *string `json:"notes,omitempty"`
PickupAddressID int64 `json:"pickup_address_id,omitempty"` PickupAddressID int64 `json:"pickup_address_id,omitempty"`
DestinationAddressID int64 `json:"destination_address_id,omitempty"` DestinationAddressID int64 `json:"destination_address_id,omitempty"`
Pickup Location `json:"pickup,omitempty"` Pickup Location `json:"pickup,omitempty"`
Provider ProviderResp `json:"provider,omitempty"` Provider ProviderResp `json:"provider,omitempty"`
CreatedUser User `json:"created_user,omitempty"` CreatedUser User `json:"created_user,omitempty"`
CreatedDate time.Time `json:"created,omitempty"` CreatedDate time.Time `json:"created,omitempty"`
UpdatedDate time.Time `json:"updated,omitempty"` UpdatedDate time.Time `json:"updated,omitempty"`
ReturnDate *time.Time `json:"return_date,omitempty"` ReturnDate *time.Time `json:"return_date,omitempty"`
TripType TripType `json:"trip_type,omitempty"` TripType TripType `json:"trip_type,omitempty"`
ExternalID string `json:"visit_external_id,omitempty"` ExternalID string `json:"visit_external_id,omitempty"`
Rides []Ride `json:"rides,omitempty"` Rides []Ride `json:"rides,omitempty"`
RawProvider ProviderResponse `json:"raw_provider,omitempty"`
} }

View File

@@ -0,0 +1,8 @@
package viewmodel
type Zipcode struct {
ID int64 `json:"-"`
UUID string `json:"uuid"`
Zipcode string `json:"zipcode"`
Participating bool `json:"participating"`
}

View File

@@ -79,18 +79,23 @@ p, *, *, *, *, *, *, /v1/nemt/organization/type, GET
p, AD, *, *, *, *, *, /v1/nemt/organization/*, GET p, AD, *, *, *, *, *, /v1/nemt/organization/*, GET
p, AD, *, *, *, *, *, /v1/nemt/organization/*, POST p, AD, *, *, *, *, *, /v1/nemt/organization/*, POST
p, AD, *, *, *, *, *, /v1/nemt/organization/*, PUT p, AD, *, *, *, *, *, /v1/nemt/organization/*, PUT
p, AD, *, *, *, *, *, /v1/nemt/organization/*, DELETE
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, GET p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, GET
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, POST p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, POST
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, PUT p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, PUT
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, DELETE
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, GET p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, GET
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, POST p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, POST
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, PUT p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, PUT
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, DELETE
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, GET p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, GET
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, POST p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, POST
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, PUT p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, PUT
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, DELETE
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, GET p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, GET
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, POST p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, POST
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, PUT p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, PUT
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, DELETE
p, SPT, *, programsupport, *, *, *, /v1/nemt/organization/*, GET p, SPT, *, programsupport, *, *, *, /v1/nemt/organization/*, GET
p, SP, *, provider, *, *, *, /v1/nemt/organization, GET p, SP, *, provider, *, *, *, /v1/nemt/organization, GET
p, SP, *, plan, *, *, *, /v1/nemt/organization, GET p, SP, *, plan, *, *, *, /v1/nemt/organization, GET
@@ -108,4 +113,10 @@ p, BCBSIAD, *, bcbsi, *, *, *, /v1/nemt/eligibility, POST
p, BDCAD, *, techsupport, *, *, *, /v1/nemt/eligibility, POST p, BDCAD, *, techsupport, *, *, *, /v1/nemt/eligibility, POST
p, PLANAD, *, plan, *, *, *, /v1/nemt/eligibility, POST p, PLANAD, *, plan, *, *, *, /v1/nemt/eligibility, POST
p, AD, *, *, *, *, *, /v1/nemt/eligibility, POST p, AD, *, *, *, *, *, /v1/nemt/eligibility, POST
p, VIRPT, *, *, *, *, *, /v1/nemt/users/member, POST
p, VIRPT, *, *, *, *, *, /v1/nemt/users/member, GET
p, VIRPT, *, *, *, *, *, /v1/nemt/eligibility, POST
p, VIRPT, *, *, *, *, *, /v1/nemt/visits, POST
p, VIRPT, *, *, *, *, *, /v1/nemt/rides/eta, GET
p, VIRPT, *, *, *, *, *, /v1/nemt/provider, GET
p, VIRPT, *, *, *, *, *, /v1/selfregister, POST
1 p AD * * * * * * *
79 p AD * * * * * /v1/nemt/organization/* GET
80 p AD * * * * * /v1/nemt/organization/* POST
81 p AD * * * * * /v1/nemt/organization/* PUT
82 p AD * * * * * /v1/nemt/organization/* DELETE
83 p SCHDAD * * * [equal*] * /v1/nemt/organization/* GET
84 p SCHDAD * * * [equal*] * /v1/nemt/organization/* POST
85 p SCHDAD * * * [equal*] * /v1/nemt/organization/* PUT
86 p SCHDAD * * * [equal*] * /v1/nemt/organization/* DELETE
87 p PLANAD * * * [equal*] * /v1/nemt/organization/* GET
88 p PLANAD * * * [equal*] * /v1/nemt/organization/* POST
89 p PLANAD * * * [equal*] * /v1/nemt/organization/* PUT
90 p PLANAD * * * [equal*] * /v1/nemt/organization/* DELETE
91 p BDCAD * * * * * /v1/nemt/organization/* GET
92 p BDCAD * * * * * /v1/nemt/organization/* POST
93 p BDCAD * * * * * /v1/nemt/organization/* PUT
94 p BDCAD * * * * * /v1/nemt/organization/* DELETE
95 p BCBSIAD * * * * * /v1/nemt/organization/* GET
96 p BCBSIAD * * * * * /v1/nemt/organization/* POST
97 p BCBSIAD * * * * * /v1/nemt/organization/* PUT
98 p BCBSIAD * * * * * /v1/nemt/organization/* DELETE
99 p SPT * programsupport * * * /v1/nemt/organization/* GET
100 p SP * provider * * * /v1/nemt/organization GET
101 p SP * plan * * * /v1/nemt/organization GET
113 p BDCAD * techsupport * * * /v1/nemt/eligibility POST
114 p PLANAD * plan * * * /v1/nemt/eligibility POST
115 p AD * * * * * /v1/nemt/eligibility POST
116 p VIRPT * * * * * /v1/nemt/users/member POST
117 p VIRPT * * * * * /v1/nemt/users/member GET
118 p VIRPT * * * * * /v1/nemt/eligibility POST
119 p VIRPT * * * * * /v1/nemt/visits POST
120 p VIRPT * * * * * /v1/nemt/rides/eta GET
121 p VIRPT * * * * * /v1/nemt/provider GET
122 p VIRPT * * * * * /v1/selfregister POST

View File

@@ -4,7 +4,7 @@ pipelines:
master: master:
- step: - step:
script: script:
- curl https://glide.sh/get | sh - curl https://glide.sh/get -L -o - | sh
- mkdir -p /go/src/bitbucket.org/nemt/nemt-portal-api - mkdir -p /go/src/bitbucket.org/nemt/nemt-portal-api
- pwd - pwd
- ls -al - ls -al
@@ -14,11 +14,14 @@ pipelines:
- rm -rf vendor/ - rm -rf vendor/
- glide install -force - glide install -force
- go build -o nemt-portal-api - go build -o nemt-portal-api
- mkdir -p dist/{static,docs} - mkdir -p dist/{static,docs,certs}
- cp nemt-portal-api ./dist/ - cp nemt-portal-api ./dist/
- cp -R static/* ./dist/static/ - cp -R static/* ./dist/static/
- cp -R docs/swagger/ ./dist/docs/ - cp -R docs/swagger/ ./dist/docs/
- cp -R certs/prd/* ./dist/certs/
- cp config.prd.toml ./dist/config.toml - cp config.prd.toml ./dist/config.toml
- cp default.prd.conf ./dist/default.conf
- cp nginx.conf ./dist/nginx.conf
- cp authorization_model.conf ./dist/authorization_model.conf - cp authorization_model.conf ./dist/authorization_model.conf
- cp authorization_policy.csv ./dist/authorization_policy.csv - cp authorization_policy.csv ./dist/authorization_policy.csv
- docker build -f Dockerfile.run -t nemt-portal-api-run:prod --force-rm --build-arg BIN_NAME=nemt-portal-api --build-arg APP_NAME=nemt-portal-api . - docker build -f Dockerfile.run -t nemt-portal-api-run:prod --force-rm --build-arg BIN_NAME=nemt-portal-api --build-arg APP_NAME=nemt-portal-api .
@@ -33,7 +36,7 @@ pipelines:
development: development:
- step: - step:
script: script:
- curl https://glide.sh/get | sh - curl https://glide.sh/get -L -o - | sh
- mkdir -p /go/src/bitbucket.org/nemt/nemt-portal-api - mkdir -p /go/src/bitbucket.org/nemt/nemt-portal-api
- pwd - pwd
- ls -al - ls -al
@@ -43,11 +46,14 @@ pipelines:
- rm -rf vendor/ - rm -rf vendor/
- glide install -force - glide install -force
- go build -o nemt-portal-api - go build -o nemt-portal-api
- mkdir -p dist/{static,docs} - mkdir -p dist/{static,docs,certs}
- cp nemt-portal-api ./dist/ - cp nemt-portal-api ./dist/
- cp -R static/* ./dist/static/ - cp -R static/* ./dist/static/
- cp -R docs/swagger/ ./dist/docs/ - cp -R docs/swagger/ ./dist/docs/
- cp -R certs/stg/* ./dist/certs/
- cp config.stg.toml ./dist/config.toml - cp config.stg.toml ./dist/config.toml
- cp default.stg.conf ./dist/default.conf
- cp nginx.conf ./dist/nginx.conf
- cp authorization_model.conf ./dist/authorization_model.conf - cp authorization_model.conf ./dist/authorization_model.conf
- cp authorization_policy.csv ./dist/authorization_policy.csv - cp authorization_policy.csv ./dist/authorization_policy.csv
- docker build -f Dockerfile.run -t nemt-portal-api-run:dev --force-rm --build-arg BIN_NAME=nemt-portal-api --build-arg APP_NAME=nemt-portal-api . - docker build -f Dockerfile.run -t nemt-portal-api-run:dev --force-rm --build-arg BIN_NAME=nemt-portal-api --build-arg APP_NAME=nemt-portal-api .

28
certs/dev/private.key Normal file
View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC0VyKNSM/a/CzE
16vidZzip1p4B7+EhJVyENoofRDk7D7afDddWV33yHUvI5opsyKIEMuGFRNIROH/
ZX47vV3H2ST/5UmkXhghEVjA/xQFUqx2hUxAjI+EkHyf+D3cofcoqFBGA7DVQ9MK
qgbRmwV09IgfQmdlFlF/D3/ZROYNYhY7NC5W+9d+JdmkV45Kp2zIDEa990roDF2p
oN6Nk0WsDMNn5nhyFtGyeuFmYcWwKeCI/XlMu5roko7tJtY0oC0boKSZ8S7xiEPK
uBUxw9cWcHVbkLyeJXIr7lfIzg5xejX3A5/KA7UuKtPAc3HQh09TEOD40Rof5Mts
l5njh/MhAgMBAAECggEAHSE+CYhLWtoE+T7FGu1YjBvwNxc5TlSEN0qVkpixE+k9
Ndl+r+txjEaq9xRPIJE48LWVynC5DqFhx/lC7K9n6JIgsdz9ijlQuHau2W3adAmo
pfReHscVn5ofJ0/X3j2jSMP3Q3fxJmGwQza3pz/dH8kn+7SkMuXqABYm1peUeXCr
BOIl0/C9UpuIlDrK0TL4VVC3gR/sXSTJV7CV12o6mqWMc5eRjYdz5Tn3W6yC5Cir
GrI3zHEDnhUM8xMtLHTxJ41Sim8To1NSuSrUk9Zd/sEQfT1daqYM3jPnfCePgzOH
b6zDzKwIDqb8T0LOOnn9uDjgz3TkRzkfEhw4xJE36QKBgQDmeR7mkENRtU5+DErI
vKWv1+SfUklfzrhgr/MqmNzvBmgqV9shVWPPg4TtERL+kiPvTFVWmAvUcC81h0Bx
ztGg49067reZq0bEYSCNaCvDvNGf9i2wirWpdOxofLI7AONcWQMm7pIwA+/ph0tG
liW6Q4Ppl4/qQfiHQ/fyqOBzXwKBgQDIUIpbUFslaEhPwAPlPAgulzu0uZxG99TG
Qxl5JKQapv5WlJ1HzU6EtMrMS4p+8Hkq2x6SRQnteZTBCvgi61eHauw7MfswhNFi
elZW7AHzydoNM+mJV8pWIVhfNtnQkVsmu0Id/dXo7U/6qWMK1yEbICAqsBkZIdfM
6EQTWxupfwKBgDK168qna2iLEB5D7iCFAZ/TTQaRQHvILGF51XNF9zbQnhLTCfAn
rbJ3KcRPwXIqDaYVkaFgCxpPJNQOUmu4Kf/Qo1jYNaWmPgfvpw32IcsLvMQJkrwJ
iTcj9vB2n3DEHUKwgzUJwTi3ZQ5pKnL5jouRV3EKXCwbH+gDWIcYCWrZAoGBALs6
BEebEMYi9UuNFlcBSEh71DN0NOxkIfz5pGqFY9kBcsHsACGndJc3AEH47Ub+btIu
oiFm5AORWwcfwJOq0lHhD1G4wqYzzh00aVSvHJgHd4ZVmhdj9duRKS89blKyObc2
2XJ82Z3viYypG8h7ERdwbIBZveuupSyBf3dz9aPzAoGBAKSN9nskGkSMfPdPlohA
BAmZGciAbob0un6db34ahExKEfkjhPA/C1AIs6LZz9QNy/OTUlXzVSx4axHMeqxo
HAb5yVRkj2VDBnWl//BEAxXKj+r1KOqESdqaKeQcYzXzAMQ36DJia7DOiej7HNSx
Y3ydXe8hO8lutgiU5rsBNVLM
-----END PRIVATE KEY-----

88
certs/dev/ssl_certificate.cer Executable file
View File

@@ -0,0 +1,88 @@
-----BEGIN CERTIFICATE-----
MIIGvjCCBaagAwIBAgIQC3nVkJVbuOa1WFfJQc+IMDANBgkqhkiG9w0BAQsFADBN
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E
aWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgwNTIxMDAwMDAwWhcN
MjAwNTIwMTIwMDAwWjCBhTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lz
MRAwDgYDVQQHEwdDaGljYWdvMS8wLQYDVQQKEyZCbHVlIENyb3NzIGFuZCBCbHVl
IFNoaWVsZCBBc3NvY2lhdGlvbjEgMB4GA1UEAwwXKi5kZXYuYmNic2luc3RpdHV0
ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0VyKNSM/a/CzE
16vidZzip1p4B7+EhJVyENoofRDk7D7afDddWV33yHUvI5opsyKIEMuGFRNIROH/
ZX47vV3H2ST/5UmkXhghEVjA/xQFUqx2hUxAjI+EkHyf+D3cofcoqFBGA7DVQ9MK
qgbRmwV09IgfQmdlFlF/D3/ZROYNYhY7NC5W+9d+JdmkV45Kp2zIDEa990roDF2p
oN6Nk0WsDMNn5nhyFtGyeuFmYcWwKeCI/XlMu5roko7tJtY0oC0boKSZ8S7xiEPK
uBUxw9cWcHVbkLyeJXIr7lfIzg5xejX3A5/KA7UuKtPAc3HQh09TEOD40Rof5Mts
l5njh/MhAgMBAAGjggNfMIIDWzAfBgNVHSMEGDAWgBQPgGEcgjFh1S8o541GOLQs
4cbZ4jAdBgNVHQ4EFgQUOlOHeILArFmCfRgy4zob9YD7ZdMwIgYDVR0RBBswGYIX
Ki5kZXYuYmNic2luc3RpdHV0ZS5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC+gLaArhilodHRwOi8v
Y3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDAvoC2gK4YpaHR0cDov
L2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwTAYDVR0gBEUwQzA3
BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu
Y29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzABhhho
dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9jYWNl
cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5jcnQw
CQYDVR0TBAIwADCCAYAGCisGAQQB1nkCBAIEggFwBIIBbAFqAHYApLkJkLQYWBSH
uxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFjhC1vrQAABAMARzBFAiEAjDaMTkKz
JL1M7AloHKciZwIm9PhTpRJhtDedIoV2l5oCIEyT5kke4/OXoBE9guw1TPCKwuS5
klDOeG+rlHiTHZvbAHcAb1N2rDHwMRnYmQCkURX/dxUcEdkCwQApBo2yCJo32RMA
AAFjhC1xQwAABAMASDBGAiEAzo+0zJUoqV0X0IqzaZ+9boXzWvIzZCR/OqT1qcAe
a3QCIQCdMYaIEYnhnsaOXPMsyShv+ry41lQ9UvUZ3EAvhjgCeQB3ALvZ37wfinG1
k5Qjl6qSe0c4V5UKq1LoGpCWZDaOHtGFAAABY4QtcKQAAAQDAEgwRgIhAJ4XGViz
vfkGsR3/UWlVZhX9t5rLAlyhW/t1K17vkNjJAiEAhzQycmcTPIVb1Ul1Ug5UgWQ4
eD2rp/4raewQVACs26QwDQYJKoZIhvcNAQELBQADggEBADjGzhdcyCYxemKuWoP9
Umd0jnS6gHPivwgpy2Ra4SSsFCkucHX8dRMi63MRghiKi4FPj9LsFoLpdHacfi+6
Q1lX3fZ6Mv2ZpNjMtBe/g6SATLsFxUQl+UP5bMShEXHsQduinAvSW3m8UpQZ2UxG
7L/XmNfeW8x213Mi4G2DNUJKDMjO28bO/GbCNB85HGfhnaDxj7OsQYllbE5oEDXN
Wkx1QZFrvqE3/2zoOa1ga36xymRXt0Sn3OSFr/ukZh3MCWAL5fuT4zjnSjybHDqT
2qdmV08ECgXwVNUMtbTFq9kenBN0xTrfPFR0Y0IPzqXQP5kTPktgrrYiAf+S875J
IVo=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg
U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83
nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd
KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f
/ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX
kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0
/RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C
AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6
Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1
oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD
QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v
d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh
xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB
CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl
5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA
8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC
2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit
c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0
j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----

28
certs/prd/private.key Normal file
View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCs4SiZVk5EI7BQ
c43SAmeAriEKoxLb0d32fCXltF/hbFouMDVA3h5TacTTVCH9JrKIykV2hbJXd8DM
UUOO0gAJ6DOjvmHeDrUquT3+eXqX71QLGVKSVgcDBy+IjdSlNj1RDdxT1gBKdWYj
OHFHsFZgGZc1OysXiww9mUhx+JhFSq5EOo7jVM6/uOfA7dXazk6sCxiT+SuEN9Hh
uPZdlHUnf+S/BPDI1PK90AG6Wj8U+nroWZZ8ZMGyh10FBLnmdZ30iO7Ll73leqR4
7rF9Ox4w4DDwWYaaiNWX3CvneYUdmTCUPJC5G82AYlMVZ9dVloIOYPMz1XwH9gs1
vzwCAH2lAgMBAAECggEAYOUh2C+jVlWacL0Tc+2dDWaLZmbYHxSVj50tsH1UcAhG
0zR55I2Z+a6Cft/c3QJfdoPIQxHUT2nzSZESiG3zT5oxt0jxmYAs0nFY6dQ0fgvJ
0x6yRQqqi2vvnF3CHYc0/sUCBIshRppeUMdF1qRjBSHSuicbk+p/Rdcv35Ex50Nz
rskvhtmPU0b7B/tVyvp+pLD+5uC42epW4Eh7R2er7WWp6m8e6mh9gjn1TYLdbprV
p/SNTJnGp4dUNO851wgsqeJcokGA6wdOb3UxIcEbW7EvX5ybozVZfUk3vP5toTmS
bNCm0UlwELE7+zX21ka7Wrfc5vGLYsdRE0Pa3V3X0QKBgQDj0E/sQ8lApJzlKf8T
9GEcuf7NM1f9DHeUmj2N8v055uAqUcE3h7PdUWSrJCbotowrJQ3jGTJd1uFrQVI4
4FEgestZDYaJ/8Bq7xt8cuebfTHzYj/o3ace4uAUKKfpxJz8+WzIK42mrcMDC221
HMmV5A4IFaM6bsvCia/LXJ91iwKBgQDCROGH8bFeriXOk8QXoq6Vq1paxEtukWBH
dtKcsAqJsUtKsVWclei+XucBrN0lrzDBii/ewcq/EH2GEknGwg0ooTG0mUD9nbCu
L9a3NUxBLxdKLZaDVsl7sxkbL9HIn4yGvznqfo4rjA4X8jY5OB7X6oR8yWdKhFJf
dT8Yi1YfjwKBgQCtSLSiaGVa0FuvTKSDzy1XJnsUJuvUxXjoBfKwWJYZRu5YAlvQ
G17LB7BlJVibRs+Tudm4VmAjVOGeLc+XB7lt1Tl8AXfG3EzGih4EKXrWoQIvuRoX
zRHjwnrjmpEulak8G5WNJOPYVu+xDy5hxwXnB9NMfvjr538B+K1JKKj6RQKBgHmI
K+sm2YZYvdAhAvCiVkPNocXcvS/bhHbQr+tT+hOvtWFx1RQTeDn4Ft4mbWbQ1ViO
gWoCpDqpL027jSnpZeAAD59irJS8nLYruVB96ElzE0fVgy6BEaTwIwmt/bhbj8cQ
REQdjgVSJdL3NNLQ+AKtdNq4CIVGiF2tdJ5/NI6jAoGBAJnsp+bti4F+LrQVPMNb
Ptyxw1eOfNkjqyoAJQXJ6HBN3uDVes/peR+9k4ATsZRMUyo+P07ggAo397+i8PY2
FeAwbzACVIb0TVNki8dP/U30e7087DgyxzMK9/ggeCuzcHczEekkioTVQubfd5vJ
4N4yQGflInls/OMIodPBir1j
-----END PRIVATE KEY-----

88
certs/prd/ssl_certificate.cer Executable file
View File

@@ -0,0 +1,88 @@
-----BEGIN CERTIFICATE-----
MIIGxzCCBa+gAwIBAgIQDARDXxHDhGyEB0wVou2tYTANBgkqhkiG9w0BAQsFADBN
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E
aWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgwNTIxMDAwMDAwWhcN
MjAwNTIwMTIwMDAwWjCBgTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lz
MRAwDgYDVQQHEwdDaGljYWdvMS8wLQYDVQQKEyZCbHVlIENyb3NzIGFuZCBCbHVl
IFNoaWVsZCBBc3NvY2lhdGlvbjEcMBoGA1UEAwwTKi5iY2JzaW5zdGl0dXRlLmNv
bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKzhKJlWTkQjsFBzjdIC
Z4CuIQqjEtvR3fZ8JeW0X+FsWi4wNUDeHlNpxNNUIf0msojKRXaFsld3wMxRQ47S
AAnoM6O+Yd4OtSq5Pf55epfvVAsZUpJWBwMHL4iN1KU2PVEN3FPWAEp1ZiM4cUew
VmAZlzU7KxeLDD2ZSHH4mEVKrkQ6juNUzr+458Dt1drOTqwLGJP5K4Q30eG49l2U
dSd/5L8E8MjU8r3QAbpaPxT6euhZlnxkwbKHXQUEueZ1nfSI7suXveV6pHjusX07
HjDgMPBZhpqI1ZfcK+d5hR2ZMJQ8kLkbzYBiUxVn11WWgg5g8zPVfAf2CzW/PAIA
faUCAwEAAaOCA2wwggNoMB8GA1UdIwQYMBaAFA+AYRyCMWHVLyjnjUY4tCzhxtni
MB0GA1UdDgQWBBQLp7ndHlG3iCGf7P7Np16aWJn+fzAxBgNVHREEKjAoghMqLmJj
YnNpbnN0aXR1dGUuY29tghFiY2JzaW5zdGl0dXRlLmNvbTAOBgNVHQ8BAf8EBAMC
BaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMGsGA1UdHwRkMGIwL6At
oCuGKWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zc2NhLXNoYTItZzYuY3JsMC+g
LaArhilodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDBM
BgNVHSAERTBDMDcGCWCGSAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3
dy5kaWdpY2VydC5jb20vQ1BTMAgGBmeBDAECAjB8BggrBgEFBQcBAQRwMG4wJAYI
KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBGBggrBgEFBQcwAoY6
aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMlNlY3VyZVNl
cnZlckNBLmNydDAJBgNVHRMEAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgA
dgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWOELVu6AAAEAwBH
MEUCIAZMGHS0chj0XWT4ikeIjqg0dglEBDIavlnouMrAEiCnAiEAzFN2rUdA0N/l
+cJqOaEJHIop81RoAcrQ8ltrNkXdZD8AdgBvU3asMfAxGdiZAKRRFf93FRwR2QLB
ACkGjbIImjfZEwAAAWOELV3xAAAEAwBHMEUCIFojBHhsdHar7n0eJ35etIlqUtHR
WV9EQxu752OWrnmsAiEAod+vqZXLOUYR4DRzlA3h9BBkkm0hc4QAU2v2h9h46rQA
dgDuS723dc5guuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAWOELVwOAAAEAwBH
MEUCIEBiLv2mAcIhhIHNmCKFFxQM6UtbO4XmlNNm9PTQLtxEAiEAichicElMgsp9
wAXBuHQ5stQiDicsJ/04Ws2QzuxbpTQwDQYJKoZIhvcNAQELBQADggEBAB3kQbAX
/RaGmnyIduvFE66Nzd/goThIr4bpBnrW0YKvZj2oHq34KjaVkmWX4VXHmyHTd9TI
YJyHifiMrfZ/BCkS5FDg32J1Vocp89k5YDS+pHxlLLxqqMsrz80v5mtblhDhqenx
2dsdwYErlbrAvNp95BKdwqcVbqvg2IHBhJ8myB5kgGLgU6Sn96SfsF5wytW+qnQx
gIn3qfPkwXVou/mq8PbZSqsrNvggjOTKbkNj8k4u+/OAHd9nP4p/CBGN7hb5RxXs
e24Ql2MFqKXx2EIrsMs+ow2xnz6hNRAD39vsYp7HSFj7Ph32Wi8X1O+J68PiNbaW
ZblXGGMRXKXUfFA=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg
U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83
nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd
KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f
/ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX
kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0
/RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C
AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6
Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1
oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD
QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v
d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh
xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB
CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl
5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA
8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC
2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit
c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0
j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----

28
certs/stg/private.key Normal file
View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC0VyKNSM/a/CzE
16vidZzip1p4B7+EhJVyENoofRDk7D7afDddWV33yHUvI5opsyKIEMuGFRNIROH/
ZX47vV3H2ST/5UmkXhghEVjA/xQFUqx2hUxAjI+EkHyf+D3cofcoqFBGA7DVQ9MK
qgbRmwV09IgfQmdlFlF/D3/ZROYNYhY7NC5W+9d+JdmkV45Kp2zIDEa990roDF2p
oN6Nk0WsDMNn5nhyFtGyeuFmYcWwKeCI/XlMu5roko7tJtY0oC0boKSZ8S7xiEPK
uBUxw9cWcHVbkLyeJXIr7lfIzg5xejX3A5/KA7UuKtPAc3HQh09TEOD40Rof5Mts
l5njh/MhAgMBAAECggEAHSE+CYhLWtoE+T7FGu1YjBvwNxc5TlSEN0qVkpixE+k9
Ndl+r+txjEaq9xRPIJE48LWVynC5DqFhx/lC7K9n6JIgsdz9ijlQuHau2W3adAmo
pfReHscVn5ofJ0/X3j2jSMP3Q3fxJmGwQza3pz/dH8kn+7SkMuXqABYm1peUeXCr
BOIl0/C9UpuIlDrK0TL4VVC3gR/sXSTJV7CV12o6mqWMc5eRjYdz5Tn3W6yC5Cir
GrI3zHEDnhUM8xMtLHTxJ41Sim8To1NSuSrUk9Zd/sEQfT1daqYM3jPnfCePgzOH
b6zDzKwIDqb8T0LOOnn9uDjgz3TkRzkfEhw4xJE36QKBgQDmeR7mkENRtU5+DErI
vKWv1+SfUklfzrhgr/MqmNzvBmgqV9shVWPPg4TtERL+kiPvTFVWmAvUcC81h0Bx
ztGg49067reZq0bEYSCNaCvDvNGf9i2wirWpdOxofLI7AONcWQMm7pIwA+/ph0tG
liW6Q4Ppl4/qQfiHQ/fyqOBzXwKBgQDIUIpbUFslaEhPwAPlPAgulzu0uZxG99TG
Qxl5JKQapv5WlJ1HzU6EtMrMS4p+8Hkq2x6SRQnteZTBCvgi61eHauw7MfswhNFi
elZW7AHzydoNM+mJV8pWIVhfNtnQkVsmu0Id/dXo7U/6qWMK1yEbICAqsBkZIdfM
6EQTWxupfwKBgDK168qna2iLEB5D7iCFAZ/TTQaRQHvILGF51XNF9zbQnhLTCfAn
rbJ3KcRPwXIqDaYVkaFgCxpPJNQOUmu4Kf/Qo1jYNaWmPgfvpw32IcsLvMQJkrwJ
iTcj9vB2n3DEHUKwgzUJwTi3ZQ5pKnL5jouRV3EKXCwbH+gDWIcYCWrZAoGBALs6
BEebEMYi9UuNFlcBSEh71DN0NOxkIfz5pGqFY9kBcsHsACGndJc3AEH47Ub+btIu
oiFm5AORWwcfwJOq0lHhD1G4wqYzzh00aVSvHJgHd4ZVmhdj9duRKS89blKyObc2
2XJ82Z3viYypG8h7ERdwbIBZveuupSyBf3dz9aPzAoGBAKSN9nskGkSMfPdPlohA
BAmZGciAbob0un6db34ahExKEfkjhPA/C1AIs6LZz9QNy/OTUlXzVSx4axHMeqxo
HAb5yVRkj2VDBnWl//BEAxXKj+r1KOqESdqaKeQcYzXzAMQ36DJia7DOiej7HNSx
Y3ydXe8hO8lutgiU5rsBNVLM
-----END PRIVATE KEY-----

88
certs/stg/ssl_certificate.cer Executable file
View File

@@ -0,0 +1,88 @@
-----BEGIN CERTIFICATE-----
MIIGvjCCBaagAwIBAgIQC3nVkJVbuOa1WFfJQc+IMDANBgkqhkiG9w0BAQsFADBN
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E
aWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgwNTIxMDAwMDAwWhcN
MjAwNTIwMTIwMDAwWjCBhTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lz
MRAwDgYDVQQHEwdDaGljYWdvMS8wLQYDVQQKEyZCbHVlIENyb3NzIGFuZCBCbHVl
IFNoaWVsZCBBc3NvY2lhdGlvbjEgMB4GA1UEAwwXKi5kZXYuYmNic2luc3RpdHV0
ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0VyKNSM/a/CzE
16vidZzip1p4B7+EhJVyENoofRDk7D7afDddWV33yHUvI5opsyKIEMuGFRNIROH/
ZX47vV3H2ST/5UmkXhghEVjA/xQFUqx2hUxAjI+EkHyf+D3cofcoqFBGA7DVQ9MK
qgbRmwV09IgfQmdlFlF/D3/ZROYNYhY7NC5W+9d+JdmkV45Kp2zIDEa990roDF2p
oN6Nk0WsDMNn5nhyFtGyeuFmYcWwKeCI/XlMu5roko7tJtY0oC0boKSZ8S7xiEPK
uBUxw9cWcHVbkLyeJXIr7lfIzg5xejX3A5/KA7UuKtPAc3HQh09TEOD40Rof5Mts
l5njh/MhAgMBAAGjggNfMIIDWzAfBgNVHSMEGDAWgBQPgGEcgjFh1S8o541GOLQs
4cbZ4jAdBgNVHQ4EFgQUOlOHeILArFmCfRgy4zob9YD7ZdMwIgYDVR0RBBswGYIX
Ki5kZXYuYmNic2luc3RpdHV0ZS5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC+gLaArhilodHRwOi8v
Y3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDAvoC2gK4YpaHR0cDov
L2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwTAYDVR0gBEUwQzA3
BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu
Y29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzABhhho
dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9jYWNl
cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5jcnQw
CQYDVR0TBAIwADCCAYAGCisGAQQB1nkCBAIEggFwBIIBbAFqAHYApLkJkLQYWBSH
uxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFjhC1vrQAABAMARzBFAiEAjDaMTkKz
JL1M7AloHKciZwIm9PhTpRJhtDedIoV2l5oCIEyT5kke4/OXoBE9guw1TPCKwuS5
klDOeG+rlHiTHZvbAHcAb1N2rDHwMRnYmQCkURX/dxUcEdkCwQApBo2yCJo32RMA
AAFjhC1xQwAABAMASDBGAiEAzo+0zJUoqV0X0IqzaZ+9boXzWvIzZCR/OqT1qcAe
a3QCIQCdMYaIEYnhnsaOXPMsyShv+ry41lQ9UvUZ3EAvhjgCeQB3ALvZ37wfinG1
k5Qjl6qSe0c4V5UKq1LoGpCWZDaOHtGFAAABY4QtcKQAAAQDAEgwRgIhAJ4XGViz
vfkGsR3/UWlVZhX9t5rLAlyhW/t1K17vkNjJAiEAhzQycmcTPIVb1Ul1Ug5UgWQ4
eD2rp/4raewQVACs26QwDQYJKoZIhvcNAQELBQADggEBADjGzhdcyCYxemKuWoP9
Umd0jnS6gHPivwgpy2Ra4SSsFCkucHX8dRMi63MRghiKi4FPj9LsFoLpdHacfi+6
Q1lX3fZ6Mv2ZpNjMtBe/g6SATLsFxUQl+UP5bMShEXHsQduinAvSW3m8UpQZ2UxG
7L/XmNfeW8x213Mi4G2DNUJKDMjO28bO/GbCNB85HGfhnaDxj7OsQYllbE5oEDXN
Wkx1QZFrvqE3/2zoOa1ga36xymRXt0Sn3OSFr/ukZh3MCWAL5fuT4zjnSjybHDqT
2qdmV08ECgXwVNUMtbTFq9kenBN0xTrfPFR0Y0IPzqXQP5kTPktgrrYiAf+S875J
IVo=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg
U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83
nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd
KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f
/ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX
kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0
/RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C
AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6
Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1
oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD
QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v
d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh
xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB
CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl
5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA
8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC
2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit
c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0
j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----

View File

@@ -74,10 +74,13 @@ user-uuid = "11a49fa4-fbc7-4fe9-87fe-52a5bc3b71f8"
[bxe] [bxe]
url = "https://api-pve.bcbs.com/BXDirectConnect/V30" url = "https://api-pve.bcbs.com/BXDirectConnect/V30"
key = "dacg7jtsmb6ajr3z553jbczg" key = "c63z7gv9a5qz2zgx7zcm3253"
secret = "vFhNeWE8JdJpbDZQtcm6AHjX" secret = "hK4Yc9jtBrxaZTr4UU2VsfX9"
[blue365] [blue365]
url = "https://api-cloud.bcbs.com/blue365deals-stg/v1/validatePrefix/" url = "https://api-cloud.bcbs.com/blue365deals-stg/v1/validatePrefix/"
key = "jcn5xjxvarc96rtjxp25dctj" key = "jcn5xjxvarc96rtjxp25dctj"
secret = "6XdEusG2w2PWWXsfXVyweQnY" secret = "6XdEusG2w2PWWXsfXVyweQnY"
[eligibility]
url = "https://portal-api.dev.bcbsinstitute.com/v1/nemt/eligibility"

View File

@@ -81,3 +81,6 @@ secret = "vFhNeWE8JdJpbDZQtcm6AHjX"
url = "https://api-cloud.bcbs.com/blue365deals-stg/v1/validatePrefix/" url = "https://api-cloud.bcbs.com/blue365deals-stg/v1/validatePrefix/"
key = "jcn5xjxvarc96rtjxp25dctj" key = "jcn5xjxvarc96rtjxp25dctj"
secret = "6XdEusG2w2PWWXsfXVyweQnY" secret = "6XdEusG2w2PWWXsfXVyweQnY"
[eligibility]
url = "https://portal-api.bcbsinstitute.com/v1/nemt/eligibility"

View File

@@ -74,8 +74,8 @@ user-uuid = "11a49fa4-fbc7-4fe9-87fe-52a5bc3b71f8"
[bxe] [bxe]
url = "https://api-pve.bcbs.com/BXDirectConnect/V30" url = "https://api-pve.bcbs.com/BXDirectConnect/V30"
key = "dacg7jtsmb6ajr3z553jbczg" key = "c63z7gv9a5qz2zgx7zcm3253"
secret = "vFhNeWE8JdJpbDZQtcm6AHjX" secret = "hK4Yc9jtBrxaZTr4UU2VsfX9"
[blue365] [blue365]
url = "https://api-cloud.bcbs.com/blue365deals-stg/v1/validatePrefix/" url = "https://api-cloud.bcbs.com/blue365deals-stg/v1/validatePrefix/"

View File

@@ -28,6 +28,8 @@ type Conn struct {
notification *notificationRepo notification *notificationRepo
profile *profileRepo profile *profileRepo
organization *organizationRepo organization *organizationRepo
zipcodes *zipcodeRepo
plan *planRepo
} }
// Begin starts a transaction // Begin starts a transaction
@@ -80,6 +82,14 @@ func (c *Conn) Organization() contract.OrganizationRepo {
return c.organization return c.organization
} }
func (c *Conn) Zipcodes() contract.ZipcodeRepo {
return c.zipcodes
}
func (c *Conn) Plans() contract.PlanRepo {
return c.plan
}
// Instance returns an instance of a DataManager // Instance returns an instance of a DataManager
func Instance(cfg *config.Config) (contract.DataManager, error) { func Instance(cfg *config.Config) (contract.DataManager, error) {
once.Do(func() { once.Do(func() {
@@ -111,6 +121,8 @@ func Instance(cfg *config.Config) (contract.DataManager, error) {
instance.notification = newNotificationRepo(db) instance.notification = newNotificationRepo(db)
instance.profile = newProfileRepo(db) instance.profile = newProfileRepo(db)
instance.organization = newOrganizationRepo(db) instance.organization = newOrganizationRepo(db)
instance.zipcodes = newZipcodeRepo(db)
instance.plan = newPlanRepo(db)
}) })
return instance, connErr return instance, connErr

View File

@@ -24,6 +24,11 @@ func (c *organizationRepo) getProfileQuery(user entity.User) (query string, wher
if len(user.Profiles) > 0 { if len(user.Profiles) > 0 {
for _, p := range user.Profiles { for _, p := range user.Profiles {
switch p.Key { switch p.Key {
case "VIRPT":
switch p.Organization.Type.Key {
case "provider":
return
}
case "AD", "BCBSIAD", "BDCAD", "PLANAD": case "AD", "BCBSIAD", "BDCAD", "PLANAD":
switch p.Organization.Type.Key { switch p.Organization.Type.Key {
case "techsupport", "bcbsi", "bcbsa": case "techsupport", "bcbsi", "bcbsa":
@@ -214,7 +219,11 @@ func (c *organizationRepo) parseEntity(row scanner) (retVal entity.Organization,
err = row.Scan( err = row.Scan(
&retVal.ID, &retVal.UUID, &retVal.Type.ID, &retVal.Type.Name, &retVal.Type.Key, &retVal.Name, &retVal.Description, &retVal.ReferenceID, &retVal.ParentID, &retVal.Main, &retVal.Created, &retVal.Updated, &retVal.Active, &retVal.Suspended, &retVal.Blocked, &retVal.Author.ID, &retVal.Author.UUID, &retVal.Author.Name, &retVal.LastEditor.ID, &retVal.LastEditor.UUID, &retVal.LastEditor.Name) &retVal.ID, &retVal.UUID, &retVal.Type.ID, &retVal.Type.Name, &retVal.Type.Key, &retVal.Name, &retVal.Description, &retVal.ReferenceID, &retVal.ParentID, &retVal.Main, &retVal.Created, &retVal.Updated, &retVal.Active, &retVal.Suspended, &retVal.Blocked, &retVal.Author.ID, &retVal.Author.UUID, &retVal.Author.Name, &retVal.LastEditor.ID, &retVal.LastEditor.UUID, &retVal.LastEditor.Name)
return retVal, errors.Wrap(err) if err == sql.ErrNoRows {
return retVal, nil
} else {
return retVal, errors.Wrap(err)
}
} }
// parseSet parses a result set result to an entity array // parseSet parses a result set result to an entity array
@@ -294,7 +303,7 @@ func (c *organizationRepo) GetAllTypes() ([]entity.OrganizationType, error) {
} }
func (c *organizationRepo) GetTypeByKey(key string) (entity.OrganizationType, error) { func (c *organizationRepo) GetTypeByKey(key string) (entity.OrganizationType, error) {
return c.parseTypeEntity(c.conn.QueryRow(c.getTypeQuery()+" WHERE b.organization_type_key=?", key)) return c.parseTypeEntity(c.conn.QueryRow(c.getTypeQuery()+" WHERE organization_type_key=? ", key))
} }
func (c *organizationRepo) GetByType(organizationTypeKey string, user entity.User) ([]entity.Organization, error) { func (c *organizationRepo) GetByType(organizationTypeKey string, user entity.User) ([]entity.Organization, error) {
@@ -337,7 +346,6 @@ func (c *organizationRepo) GetByUUID(organizationUUID string, user entity.User)
} }
query = c.getQuery() + query + " WHERE a.organization_uuid = ? " + where query = c.getQuery() + query + " WHERE a.organization_uuid = ? " + where
return c.parseEntity(c.conn.QueryRow(query, organizationUUID)) return c.parseEntity(c.conn.QueryRow(query, organizationUUID))
} }
@@ -352,6 +360,17 @@ func (c *organizationRepo) GetByID(organizationID int64, user entity.User) (enti
return c.parseEntity(c.conn.QueryRow(query, organizationID)) return c.parseEntity(c.conn.QueryRow(query, organizationID))
} }
func (c *organizationRepo) GetByTypeAndReferenceID(typeKey string, referenceID int64, user entity.User) (entity.Organization, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Organization{}, err
}
query = c.getQuery() + query + " WHERE b.organization_type_key = ? AND a.organization_reference_id = ? " + where
return c.parseEntity(c.conn.QueryRow(query, typeKey, referenceID))
}
func (c *organizationRepo) GetChildsByID(organizationID int64, user entity.User) ([]entity.Organization, error) { func (c *organizationRepo) GetChildsByID(organizationID int64, user entity.User) ([]entity.Organization, error) {
query, where, err := c.getProfileQuery(user) query, where, err := c.getProfileQuery(user)
if err != nil { if err != nil {
@@ -431,13 +450,16 @@ func (c *organizationRepo) SetOrganizationAddress(address entity.OrganizationAdd
return entity.OrganizationAddress{}, errors.NewNotFoundError() return entity.OrganizationAddress{}, errors.NewNotFoundError()
} }
organization, err := c.GetByUUID(address.Organization.UUID, user) if address.Organization.ID == 0 {
if err != nil { organization, err := c.GetByUUID(address.Organization.UUID, user)
return entity.OrganizationAddress{}, err if err != nil {
return entity.OrganizationAddress{}, err
}
address.Organization = &organization
} }
UUID, _ := uuid.NewV4() UUID, _ := uuid.NewV4()
result, err := c.conn.Exec(query, UUID.String(), organization.ID, address.InternalID, address.Name, address.Address, address.Description, address.Latitude, address.Longitude, address.CreatedUser.ID, address.UpdatedUser.ID) result, err := c.conn.Exec(query, UUID.String(), address.Organization.ID, address.InternalID, address.Name, address.Address, address.Description, address.Latitude, address.Longitude, address.CreatedUser.ID, address.UpdatedUser.ID)
if err != nil { if err != nil {
return entity.OrganizationAddress{}, err return entity.OrganizationAddress{}, err
} }

82
data/datamysql/plan.go Normal file
View File

@@ -0,0 +1,82 @@
package datamysql
import (
"database/sql"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
type planRepo struct {
conn executor
}
func newPlanRepo(conn executor) *planRepo {
return &planRepo{
conn: conn,
}
}
func (c *planRepo) getQuery() string {
const query = `SELECT
a.plan_id,
a.plan_uuid,
a.plan_name,
a.plan_internal_id,
a.plan_internal_status,
a.plan_entity_id,
a.entity_id,
a.payer_id,
a.payer_name,
a.active,
a.created,
a.updated,
b.plan_prefix_id,
b.plan_prefix_uuid,
b.alpha_prefix
FROM
tab_plan a
INNER JOIN
tab_plan_alpha_prefix b ON a.plan_id = b.plan_id `
return query
}
func (c *planRepo) parseSet(rows *sql.Rows, err error) ([]entity.Plan, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Plan, 0)
for rows.Next() {
entity, err := c.parseEntity(rows)
if err != nil {
return nil, errors.Wrap(err)
}
result = append(result, entity)
}
return result, nil
}
func (c *planRepo) parseEntity(row scanner) (retVal entity.Plan, err error) {
err = row.Scan(
&retVal.ID, &retVal.UUID, &retVal.Name, &retVal.InternalID, &retVal.Status, &retVal.PlanEntityID, &retVal.EntityID, &retVal.PayerID, &retVal.PayerName,
&retVal.Active, &retVal.Created, &retVal.Updated, &retVal.PrefixID, &retVal.PrefixUUID, &retVal.AlphaPrefix)
return retVal, errors.Wrap(err)
}
func (c *planRepo) GetByAlphaPrefix(alphaPrefix string) (entity.Plan, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE b.alpha_prefix = ? ", alphaPrefix))
}
func (c *planRepo) GetByUUID(planUUID string) ([]entity.Plan, error) {
return c.parseSet(c.conn.Query(c.getQuery()+" WHERE a.plan_uuid = ? ", planUUID))
}
func (c *planRepo) GetByID(planID int64) ([]entity.Plan, error) {
return c.parseSet(c.conn.Query(c.getQuery()+" WHERE a.plan_id = ? ", planID))
}
func (c *planRepo) GetByPrefixUUID(prefixUUID string) (entity.Plan, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE b.plan_prefix_uuid = ? ", prefixUUID))
}

View File

@@ -27,7 +27,7 @@ func (c *providerRepo) getProfileQuery(user entity.User) (query string, where st
if len(user.Profiles) > 0 { if len(user.Profiles) > 0 {
for _, p := range user.Profiles { for _, p := range user.Profiles {
switch p.Key { switch p.Key {
case "AD", "BCBSIAD", "BDCAD", "PLANAD": case "AD", "BCBSIAD", "BDCAD", "PLANAD", "VIRPT":
return return
case "SP", "SPT": case "SP", "SPT":
switch p.Organization.Type.Key { switch p.Organization.Type.Key {
@@ -72,44 +72,44 @@ func (c *providerRepo) getSelectQueryBaseKey() string {
func (c *providerRepo) getSelectQueryBase() string { func (c *providerRepo) getSelectQueryBase() string {
return `SELECT DISTINCT return `SELECT DISTINCT
a.provider_id, a.provider_id,
a.provider_uuid, a.provider_uuid,
a.provider_internal_id, a.provider_internal_id,
a.provider_internal_id_suffix, IFNULL(a.provider_internal_id_suffix, '') provider_internal_id_suffix,
a.provider_muk_id, IFNULL(a.provider_muk_id, '') provider_muk_id,
a.organization_name, IFNULL(a.organization_name, '') organization_name,
a.gender, IFNULL(a.gender, '') gender,
a.accept_new_patients, IFNULL(a.accept_new_patients, '') accept_new_patients,
a.provider_name, IFNULL(a.provider_name, '') provider_name,
a.first_name, IFNULL(a.first_name, '') first_name,
a.last_name, IFNULL(a.last_name, '') last_name,
a.middle_name, IFNULL(a.middle_name, '') middle_name,
a.provider_title, IFNULL(a.provider_title, '') provider_title,
a.street_name1, IFNULL(a.street_name1, '') street_name1,
a.street_name2, IFNULL(a.street_name2, '') street_name2,
a.city_name, IFNULL(a.city_name, '') city_name,
a.state, IFNULL(a.state, '') state,
a.zipcode, IFNULL(a.zipcode, '') zipcode,
a.country, IFNULL(a.country, '') country,
a.latitude, IFNULL(a.latitude, 0) latitude,
a.longitude, IFNULL(a.longitude, 0) longitude,
a.phone_number, IFNULL(a.phone_number, '') phone_number,
a.create_at, a.create_at,
a.update_at, a.update_at,
a.active, a.active,
a.enabled, a.enabled,
a.created_user, a.created_user,
(3959 * acos ( (3959 * acos (
cos ( radians(?) ) cos ( radians(?) )
* cos( radians( a.latitude ) ) * cos( radians( IFNULL(a.latitude, 0) ) )
* cos( radians( a.longitude ) - radians(?) ) * cos( radians( IFNULL(a.longitude, 0) ) - radians(?) )
+ sin ( radians(?) ) + sin ( radians(?) )
* sin( radians( a.latitude ) ) * sin( radians( IFNULL(a.latitude, 0) ) )
)) AS distance_in_miles )) AS distance_in_miles
FROM FROM
tab_provider a tab_provider a
INNER JOIN tab_provider_key b INNER JOIN tab_provider_key b
ON a.provider_id = b.provider_id ` ON a.provider_id = b.provider_id `
} }
func (c *providerRepo) GetAll(user entity.User) ([]entity.Provider, error) { func (c *providerRepo) GetAll(user entity.User) ([]entity.Provider, error) {
@@ -131,6 +131,34 @@ func (c *providerRepo) GetAll(user entity.User) ([]entity.Provider, error) {
return c.getKeys("", "", providers) return c.getKeys("", "", providers)
} }
func (c *providerRepo) GetByUUID(providerUUID string, user entity.User) (entity.Provider, error) {
lat := 41.886406
long := -87.624225
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Provider{}, err
}
query = c.getSelectQueryBase() + query + " WHERE a.provider_uuid = ? " + where
return c.parseEntity(c.conn.QueryRow(query, lat, long, lat, providerUUID))
}
func (c *providerRepo) GetByID(providerID int64, user entity.User) (entity.Provider, error) {
lat := 41.886406
long := -87.624225
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Provider{}, err
}
query = c.getSelectQueryBase() + query + " WHERE a.provider_id = ? " + where
return c.parseEntity(c.conn.QueryRow(query, lat, long, lat, providerID))
}
func (c *providerRepo) GetByMukID(mukID string, user entity.User) (entity.Provider, error) { func (c *providerRepo) GetByMukID(mukID string, user entity.User) (entity.Provider, error) {
lat := 41.886406 lat := 41.886406
long := -87.624225 long := -87.624225
@@ -145,6 +173,20 @@ func (c *providerRepo) GetByMukID(mukID string, user entity.User) (entity.Provid
return c.parseEntity(c.conn.QueryRow(query, lat, long, lat, mukID)) return c.parseEntity(c.conn.QueryRow(query, lat, long, lat, mukID))
} }
func (c *providerRepo) GetByNPI(NPI string, user entity.User) (entity.Provider, error) {
lat := 41.886406
long := -87.624225
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Provider{}, err
}
query = c.getSelectQueryBase() + query + " WHERE a.provider_internal_id = ? " + where
return c.parseEntity(c.conn.QueryRow(query, lat, long, lat, NPI))
}
func (c *providerRepo) Get(query string, lat float64, long float64, distance int64, planCode string, productID string, mukID string, internalID string, sort string, user entity.User) ([]entity.Provider, error) { func (c *providerRepo) Get(query string, lat float64, long float64, distance int64, planCode string, productID string, mukID string, internalID string, sort string, user entity.User) ([]entity.Provider, error) {
filter := " WHERE 1 = 1 " filter := " WHERE 1 = 1 "
params := make([]interface{}, 0) params := make([]interface{}, 0)
@@ -293,7 +335,11 @@ func (c *providerRepo) parseEntity(row scanner) (retVal entity.Provider, err err
err = row.Scan( err = row.Scan(
&retVal.ProviderID, &retVal.ProviderUUID, &retVal.InternalID, &retVal.InternalSuffixID, &retVal.MukID, &retVal.OrganizatioName, &retVal.Gender, &retVal.AcceptNewPatients, &retVal.Name, &retVal.FirstName, &retVal.LastName, &retVal.MiddleName, &retVal.Title, &retVal.Address.StreetAddress1, &retVal.Address.StreetAddress2, &retVal.Address.CityName, &retVal.Address.State, &retVal.Address.ZipCode, &retVal.Address.Country, &retVal.Address.Latitude, &retVal.Address.Longitude, &retVal.Address.PhoneNumber, &retVal.CreateDate, &retVal.UpdateDate, &retVal.Active, &retVal.Enabled, &retVal.CreatedUser.ID, &retVal.Distance) &retVal.ProviderID, &retVal.ProviderUUID, &retVal.InternalID, &retVal.InternalSuffixID, &retVal.MukID, &retVal.OrganizatioName, &retVal.Gender, &retVal.AcceptNewPatients, &retVal.Name, &retVal.FirstName, &retVal.LastName, &retVal.MiddleName, &retVal.Title, &retVal.Address.StreetAddress1, &retVal.Address.StreetAddress2, &retVal.Address.CityName, &retVal.Address.State, &retVal.Address.ZipCode, &retVal.Address.Country, &retVal.Address.Latitude, &retVal.Address.Longitude, &retVal.Address.PhoneNumber, &retVal.CreateDate, &retVal.UpdateDate, &retVal.Active, &retVal.Enabled, &retVal.CreatedUser.ID, &retVal.Distance)
return retVal, errors.Wrap(err) if err == sql.ErrNoRows {
return retVal, nil
} else {
return retVal, errors.Wrap(err)
}
} }
func (c *providerRepo) Save(providers []entity.ProviderResponse, user entity.User) ([]entity.Provider, error) { func (c *providerRepo) Save(providers []entity.ProviderResponse, user entity.User) ([]entity.Provider, error) {

View File

@@ -29,7 +29,7 @@ func (c *rideRepo) getQuery() string {
b.user_id, b.user_id,
b.user_uuid, b.user_uuid,
b.name, b.name,
b.member, b.subscriber_id,
c.ride_status_id, c.ride_status_id,
c.ride_status, c.ride_status,
c.key ride_status_key, c.key ride_status_key,
@@ -144,13 +144,13 @@ func (c *rideRepo) getProfileQuery(user entity.User) (query string, where string
switch p.Key { switch p.Key {
case "AD", "BCBSIAD", "BDCAD", "PLANAD": case "AD", "BCBSIAD", "BDCAD", "PLANAD":
return return
case "SP", "SPT": case "SP", "SPT", "VIRPT":
switch p.Organization.Type.Key { switch p.Organization.Type.Key {
case "techsupport", "bcbsi", "bcbsa", "plan": case "techsupport", "bcbsi", "bcbsa", "plan":
return return
case "provider": case "provider":
query = `INNER JOIN viw_visit_provider o ON a.ride_id = o.ride_id` query = `INNER JOIN viw_visit_provider z ON a.ride_id = z.ride_id`
where = fmt.Sprintf(` AND (o.organization_uuid = '%s' OR o.parent_organization_uuid = '%s') `, p.Organization.UUID, p.Organization.UUID) where = fmt.Sprintf(` AND (z.organization_uuid = '%s' OR z.parent_organization_uuid = '%s') `, p.Organization.UUID, p.Organization.UUID)
return return
} }
} }
@@ -514,14 +514,14 @@ func (c *rideRepo) saveHeader(ride entity.Ride) (retVal entity.Ride, err error)
dataQuery = `SELECT dataQuery = `SELECT
a.user_id user_id, a.user_id user_id,
a.name, a.name,
a.member, a.subscriber_id,
b.ride_status_id, b.ride_status_id,
b.ride_status, b.ride_status,
c.ride_type_id, c.ride_type_id,
c.value ride_type, c.value ride_type,
d.user_id created_user_id, d.user_id created_user_id,
d.name created_name, d.name created_name,
IFNULL(d.member, '') created_member, IFNULL(d.subscriber_id, '') created_member,
e.trip_type_id, e.trip_type_id,
e.trip_type_key, e.trip_type_key,
e.trip_type e.trip_type
@@ -676,6 +676,7 @@ func (c *rideRepo) GetByUUID(uuid string, user entity.User) (entity.Ride, error)
} }
query = c.getQuery() + query + " WHERE a.ride_uuid = ? " + where query = c.getQuery() + query + " WHERE a.ride_uuid = ? " + where
return c.parseEntity(c.conn.QueryRow(query, uuid)) return c.parseEntity(c.conn.QueryRow(query, uuid))
} }

View File

@@ -16,6 +16,8 @@ type transaction struct {
notification *notificationRepo notification *notificationRepo
profile *profileRepo profile *profileRepo
organization *organizationRepo organization *organizationRepo
zipcodes *zipcodeRepo
plan *planRepo
} }
func newTransaction(tx *sql.Tx) *transaction { func newTransaction(tx *sql.Tx) *transaction {
@@ -27,6 +29,11 @@ func newTransaction(tx *sql.Tx) *transaction {
t.rides = newRideRepo(tx) t.rides = newRideRepo(tx)
t.visits = newVisitRepo(tx) t.visits = newVisitRepo(tx)
t.provider = newProviderRepo(tx) t.provider = newProviderRepo(tx)
t.notification = newNotificationRepo(tx)
t.profile = newProfileRepo(tx)
t.organization = newOrganizationRepo(tx)
t.zipcodes = newZipcodeRepo(tx)
t.plan = newPlanRepo(tx)
return t return t
} }
@@ -66,6 +73,14 @@ func (t transaction) Organization() contract.OrganizationRepo {
return t.organization return t.organization
} }
func (t transaction) Zipcodes() contract.ZipcodeRepo {
return t.zipcodes
}
func (t transaction) Plans() contract.PlanRepo {
return t.plan
}
func (t *transaction) Commit() error { func (t *transaction) Commit() error {
err := t.tx.Commit() err := t.tx.Commit()

View File

@@ -22,6 +22,32 @@ func newUserRepo(conn executor) *userRepo {
} }
} }
func (c *userRepo) GetByMemberID(memberID string) (entity.User, error) {
finalQuery := c.getQuery() + " AND a.subscriber_id = ? AND e.key = 'US'"
user, err := c.parseSet(c.conn.Query(finalQuery, memberID))
if err != nil {
return entity.User{}, err
}
if len(user) > 0 {
retVal := user[0]
retVal.Contacts, err = c.GetContacts(retVal.ID)
if err != nil {
return entity.User{}, err
}
retVal.Addresses = nil
retVal.Addresses, err = c.getAddressByUserID(retVal.ID)
if err != nil {
return entity.User{}, err
}
return retVal, nil
} else {
return entity.User{}, nil
}
}
func (c *userRepo) GetByUUID(uuid string, profile string) (entity.User, error) { func (c *userRepo) GetByUUID(uuid string, profile string) (entity.User, error) {
params := make([]interface{}, 0) params := make([]interface{}, 0)
params = append(params, uuid) params = append(params, uuid)
@@ -63,7 +89,8 @@ func (c *userRepo) GetContacts(userID int64) ([]entity.ContactInfo, error) {
a.user_id, a.user_id,
b.contact_type_id, b.contact_type_id,
b.key contact_type_key, b.key contact_type_key,
b.name contact_type_name b.name contact_type_name,
a.contact_uuid
FROM tab_contact a FROM tab_contact a
INNER JOIN tab_contact_type b INNER JOIN tab_contact_type b
ON a.contact_type_id = b.contact_type_id ON a.contact_type_id = b.contact_type_id
@@ -79,7 +106,7 @@ func (c *userRepo) GetContacts(userID int64) ([]entity.ContactInfo, error) {
retVal := make([]entity.ContactInfo, 0) retVal := make([]entity.ContactInfo, 0)
for rows.Next() { for rows.Next() {
contact := entity.ContactInfo{} contact := entity.ContactInfo{}
err = rows.Scan(&contact.ID, &contact.Value, &contact.UserID, &contact.Type.ID, &contact.Type.Key, &contact.Type.Value) err = rows.Scan(&contact.ID, &contact.Value, &contact.User.ID, &contact.Type.ID, &contact.Type.Key, &contact.Type.Value, &contact.UUID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -165,7 +192,7 @@ func (c *userRepo) parseEntity(row scanner) (retVal entity.User, err error) {
err = row.Scan(&retVal.ID, &retVal.UUID, &retVal.Name, &retVal.Member, &birthDate, &retVal.LoginID, &retVal.LoginUUID, &retVal.Email, &retVal.PhoneNumber, &retVal.LoginKey, &retVal.Gender, &retVal.Active, &retVal.Created, &retVal.Updated, &profile.ID, &profile.Name, &profile.Key, &profile.Active, &profile.Blocked, &profile.Suspended, &profile.Created, &profile.Updated, &profile.Organization.ID, &profile.Organization.UUID, &profile.Organization.Type.ID, &profile.Organization.Type.Name, &profile.Organization.Type.Key, &profile.Organization.Type.Description, &profile.Organization.Name, &profile.Organization.Description, &profile.Organization.ReferenceID, &profile.Organization.ParentID, &profile.Organization.Main, err = row.Scan(&retVal.ID, &retVal.UUID, &retVal.Name, &retVal.Member, &birthDate, &retVal.LoginID, &retVal.LoginUUID, &retVal.Email, &retVal.PhoneNumber, &retVal.LoginKey, &retVal.Gender, &retVal.Active, &retVal.Created, &retVal.Updated, &profile.ID, &profile.Name, &profile.Key, &profile.Active, &profile.Blocked, &profile.Suspended, &profile.Created, &profile.Updated, &profile.Organization.ID, &profile.Organization.UUID, &profile.Organization.Type.ID, &profile.Organization.Type.Name, &profile.Organization.Type.Key, &profile.Organization.Type.Description, &profile.Organization.Name, &profile.Organization.Description, &profile.Organization.ReferenceID, &profile.Organization.ParentID, &profile.Organization.Main,
&homeAddress.ID, &homeAddress.UUID, &homeAddress.AddressType.ID, &homeAddress.AddressType.Key, &homeAddress.AddressType.Name, &homeAddress.Name, &homeAddress.Address, &homeAddress.Latitude, &homeAddress.Longitude, &homeAddress.ID, &homeAddress.UUID, &homeAddress.AddressType.ID, &homeAddress.AddressType.Key, &homeAddress.AddressType.Name, &homeAddress.Name, &homeAddress.Address, &homeAddress.Latitude, &homeAddress.Longitude,
&workAddress.ID, &workAddress.UUID, &workAddress.AddressType.ID, &workAddress.AddressType.Key, &workAddress.AddressType.Name, &workAddress.Name, &workAddress.Address, &workAddress.Latitude, &workAddress.Longitude) &workAddress.ID, &workAddress.UUID, &workAddress.AddressType.ID, &workAddress.AddressType.Key, &workAddress.AddressType.Name, &workAddress.Name, &workAddress.Address, &workAddress.Latitude, &workAddress.Longitude, &retVal.Type)
if err != nil { if err != nil {
if err != sql.ErrNoRows { if err != sql.ErrNoRows {
return retVal, errors.Wrap(err) return retVal, errors.Wrap(err)
@@ -203,7 +230,7 @@ func (c *userRepo) getQuery() string {
a.user_id, a.user_id,
a.user_uuid, a.user_uuid,
a.name, a.name,
IFNULL(a.member, '') member, IFNULL(a.subscriber_id, '') subscriber_id,
a.birth_date, a.birth_date,
b.login_id, b.login_id,
b.login_uuid, b.login_uuid,
@@ -233,24 +260,25 @@ func (c *userRepo) getQuery() string {
IFNULL(f.organization_reference_id, 0) organization_reference_id, IFNULL(f.organization_reference_id, 0) organization_reference_id,
IFNULL(f.organization_parent_id, 0) organization_parent_id, IFNULL(f.organization_parent_id, 0) organization_parent_id,
(IFNULL(f.main_organization, b'0') = b'1') main_organization, (IFNULL(f.main_organization, b'0') = b'1') main_organization,
IFNULL(h.address_id, 0) home_address_id, IFNULL(h.address_id, 0) home_address_id,
IFNULL(h.address_uuid, '') home_address_uuid, IFNULL(h.address_uuid, '') home_address_uuid,
IFNULL(h.address_type_id, 0) home_address_type_id, IFNULL(h.address_type_id, 0) home_address_type_id,
IFNULL(h.address_type_key, '') home_address_type_key, IFNULL(h.address_type_key, '') home_address_type_key,
IFNULL(h.address_type_name, '') home_address_type_name, IFNULL(h.address_type_name, '') home_address_type_name,
IFNULL(h.name, '') home_name, IFNULL(h.name, '') home_name,
IFNULL(h.address, '') home_address, IFNULL(h.address, '') home_address,
IFNULL(h.lat, 0) home_lat, IFNULL(h.lat, 0) home_lat,
IFNULL(h.long, 0) home_long, IFNULL(h.long, 0) home_long,
IFNULL(i.address_id, 0) work_address_id, IFNULL(i.address_id, 0) work_address_id,
IFNULL(i.address_uuid, '') work_address_uuid, IFNULL(i.address_uuid, '') work_address_uuid,
IFNULL(i.address_type_id, 0) work_address_type_id, IFNULL(i.address_type_id, 0) work_address_type_id,
IFNULL(i.address_type_key, '') work_address_type_key, IFNULL(i.address_type_key, '') work_address_type_key,
IFNULL(i.address_type_name, '') work_address_type_name, IFNULL(i.address_type_name, '') work_address_type_name,
IFNULL(i.name, '') work_name, IFNULL(i.name, '') work_name,
IFNULL(i.address, '') work_address, IFNULL(i.address, '') work_address,
IFNULL(i.lat, 0) work_lat, IFNULL(i.lat, 0) work_lat,
IFNULL(i.long, 0) work_long IFNULL(i.long, 0) work_long,
IFNULL(a.member_type, 'S') member_type
FROM FROM
tab_user a tab_user a
INNER JOIN INNER JOIN
@@ -354,9 +382,11 @@ func (c *userRepo) Create(user entity.User) (retVal entity.User, err error) {
if retVal.Email != "" { if retVal.Email != "" {
contact := entity.ContactInfo{ contact := entity.ContactInfo{
Type: entity.ContactType{Key: "email"}, Type: entity.ContactType{Key: "email"},
Value: retVal.Email, Value: retVal.Email,
UserID: retVal.ID, User: entity.User{
ID: retVal.ID,
},
} }
contact, err = c.addContactInfo(contact) contact, err = c.addContactInfo(contact)
@@ -367,9 +397,11 @@ func (c *userRepo) Create(user entity.User) (retVal entity.User, err error) {
if retVal.PhoneNumber != "" { if retVal.PhoneNumber != "" {
contact := entity.ContactInfo{ contact := entity.ContactInfo{
Type: entity.ContactType{Key: "phone"}, Type: entity.ContactType{Key: "phone"},
Value: retVal.PhoneNumber, Value: retVal.PhoneNumber,
UserID: retVal.ID, User: entity.User{
ID: retVal.ID,
},
} }
contact, err = c.addContactInfo(contact) contact, err = c.addContactInfo(contact)
@@ -385,21 +417,30 @@ func (c *userRepo) SaveContact(contact entity.ContactInfo) (entity.ContactInfo,
return c.addContactInfo(contact) return c.addContactInfo(contact)
} }
func (c *userRepo) RemoveContact(contact entity.ContactInfo) (entity.ContactInfo, error) { func (c *userRepo) UpdateLogin(user entity.User) error {
const ( const (
query = `INSERT INTO tab_contact(contact_type_id, user_id, contact) query = `UPDATE tab_login a
SELECT a.contact_type_id, ? user_id, ? contact INNER JOIN tab_user b
FROM ON a.user_id = b.user_id
tab_contact_type a SET a.email = ?,
LEFT JOIN tab_contact b a.phone_number = ?
ON a.contact_type_id = b.contact_type_id WHERE
AND b.user_id = ? b.user_uuid = ?`
AND b.contact = ?
WHERE a.key = ?
AND b.contact_id IS NULL;`
) )
result, err := c.conn.Exec(query, contact.UserID, contact.Value, contact.UserID, contact.Value, contact.Type.Key) if _, err := c.conn.Exec(query, user.Email, user.PhoneNumber, user.UUID); err != nil {
return err
}
return nil
}
func (c *userRepo) RemoveContact(contact entity.ContactInfo) (entity.ContactInfo, error) {
const (
query = `DELETE FROM tab_contact WHERE contact_uuid = ?;`
)
result, err := c.conn.Exec(query, contact.UUID)
if err != nil { if err != nil {
return contact, err return contact, err
} }
@@ -415,8 +456,8 @@ func (c *userRepo) RemoveContact(contact entity.ContactInfo) (entity.ContactInfo
func (c *userRepo) addContactInfo(contact entity.ContactInfo) (entity.ContactInfo, error) { func (c *userRepo) addContactInfo(contact entity.ContactInfo) (entity.ContactInfo, error) {
const ( const (
query = `INSERT INTO tab_contact(contact_type_id, user_id, contact) query = `INSERT INTO tab_contact(contact_type_id, user_id, contact, contact_uuid)
SELECT a.contact_type_id, ? user_id, ? contact SELECT a.contact_type_id, ? user_id, ? contact, ? contact_uuid
FROM FROM
tab_contact_type a tab_contact_type a
LEFT JOIN tab_contact b LEFT JOIN tab_contact b
@@ -427,7 +468,13 @@ func (c *userRepo) addContactInfo(contact entity.ContactInfo) (entity.ContactInf
AND b.contact_id IS NULL;` AND b.contact_id IS NULL;`
) )
result, err := c.conn.Exec(query, contact.UserID, contact.Value, contact.UserID, contact.Value, contact.Type.Key) sUUID, err := uuid.NewV4()
if err != nil {
return contact, err
}
contact.UUID = sUUID.String()
result, err := c.conn.Exec(query, contact.User.ID, contact.Value, contact.UUID, contact.User.ID, contact.Value, contact.Type.Key)
if err != nil { if err != nil {
return contact, err return contact, err
} }
@@ -475,7 +522,7 @@ func (c *userRepo) addProfileToUser(loginID int64, profileID int64, organization
func (c *userRepo) getUserByMember(u entity.User) (user entity.User, err error) { func (c *userRepo) getUserByMember(u entity.User) (user entity.User, err error) {
user = u user = u
users, err := c.parseSet(c.conn.Query(c.getQuery()+" AND a.active = 1 AND e.key = 'US' AND IFNULL(a.member, '') = ?;", u.Member)) users, err := c.parseSet(c.conn.Query(c.getQuery()+" AND a.active = 1 AND e.key = 'US' AND IFNULL(a.subscriber_id, '') = ?;", u.Member))
if err != nil { if err != nil {
return user, errors.Wrap(err) return user, errors.Wrap(err)
} }
@@ -540,11 +587,11 @@ func (c *userRepo) createLogin(user entity.User) (int64, string, error) {
func (c *userRepo) createUser(user entity.User) (int64, string, error) { func (c *userRepo) createUser(user entity.User) (int64, string, error) {
const ( const (
query = "INSERT INTO tab_user(user_uuid, `name`, member, birth_date, gender) VALUES(?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE user_uuid = ?, `name` = ?, member = ?, birth_date = ?, gender = ?;" query = "INSERT INTO tab_user(user_uuid, `name`, subscriber_id, birth_date, gender, member_type, user_hash) VALUES(?, ?, ?, ?, ?, ?, SHA2(CONCAT_WS('-',?,?,?,?,?), 512)) ON DUPLICATE KEY UPDATE user_uuid = ?, `name` = ?, subscriber_id = ?, birth_date = ?, gender = ?;"
) )
guid, _ := uuid.NewV4() guid, _ := uuid.NewV4()
result, err := c.conn.Exec(query, guid.String(), user.Name, toNullString(user.Member), toNullTime(user.BirthDate), toNullString(user.Gender), guid.String(), user.Name, toNullString(user.Member), toNullTime(user.BirthDate), toNullString(user.Gender)) result, err := c.conn.Exec(query, guid.String(), user.Name, toNullString(user.Member), toNullTime(user.BirthDate), toNullString(user.Gender), user.Type, user.Name, toNullString(user.Member), toNullTime(user.BirthDate), toNullString(user.Gender), user.Type, guid.String(), user.Name, toNullString(user.Member), toNullTime(user.BirthDate), toNullString(user.Gender))
if err != nil { if err != nil {
return 0, "", err return 0, "", err
} }
@@ -559,7 +606,7 @@ func (c *userRepo) createUser(user entity.User) (int64, string, error) {
func (c *userRepo) RemoveAddress(addressUUID string) error { func (c *userRepo) RemoveAddress(addressUUID string) error {
const ( const (
query = "UPDATE tab_address SET active = 0 WHERE address_uuid = ?" query = "UPDATE tab_address SET active = 0 WHERE address_uuid = ?;"
) )
_, err := c.conn.Exec(query, addressUUID) _, err := c.conn.Exec(query, addressUUID)

View File

@@ -27,14 +27,13 @@ func (c *visitRepo) getProfileQuery(user entity.User) (query string, where strin
switch p.Key { switch p.Key {
case "AD", "BCBSIAD", "BDCAD", "PLANAD": case "AD", "BCBSIAD", "BDCAD", "PLANAD":
return return
case "SP", "SPT": case "SP", "SPT", "VIRPT":
switch p.Organization.Type.Key { switch p.Organization.Type.Key {
case "techsupport", "bcbsi", "bcbsa", "plan": case "techsupport", "bcbsi", "bcbsa", "plan":
return return
case "provider": case "provider":
query = ` INNER JOIN viw_visit_provider f query = ` INNER JOIN viw_visit_provider AS o ON o.visit_id = a.visit_id `
ON f.visit_id = a.visit_id ` where = fmt.Sprintf(` AND ( o.organization_uuid = '%s' OR o.parent_organization_uuid = '%s' ) `, p.Organization.UUID, p.Organization.UUID)
where = fmt.Sprintf(` AND (f.organization_uuid = '%s' OR f.parent_organization_uuid = '%s') `, p.Organization.UUID, p.Organization.UUID)
return return
} }
} }
@@ -60,7 +59,7 @@ func (c *visitRepo) getQuery() string {
a.user_id, a.user_id,
c.user_uuid, c.user_uuid,
c.name user_name, c.name user_name,
c.member user_member, c.subscriber_id user_member,
c.birth_date user_birth_date, c.birth_date user_birth_date,
c.gender user_gender, c.gender user_gender,
a.visit_datetime, a.visit_datetime,
@@ -79,23 +78,23 @@ func (c *visitRepo) getQuery() string {
IFNULL(a.pickup_id, '') visit_pickup_id, IFNULL(a.pickup_id, '') visit_pickup_id,
IFNULL(a.pickup_address_id, 0) pickup_address_id, IFNULL(a.pickup_address_id, 0) pickup_address_id,
IFNULL(a.address_id, 0) address_id, IFNULL(a.address_id, 0) address_id,
IFNULL(a.provider_id, 0) provider_id, IFNULL(a.provider_id, 0) provider_id,
IFNULL(f.provider_uuid, '') provider_uuid, IFNULL(f.provider_uuid, '') provider_uuid,
IFNULL(f.provider_internal_id, '') provider_internal_id, IFNULL(f.provider_internal_id, '') provider_internal_id,
IFNULL(f.provider_muk_id, '') provider_muk_id, IFNULL(f.provider_muk_id, '') provider_muk_id,
IFNULL(f.provider_name, '') provider_name IFNULL(f.provider_name, '') provider_name
FROM FROM
tab_visit a tab_visit AS a
INNER JOIN tab_visit_status b INNER JOIN tab_visit_status AS b
ON a.visit_status_id = b.visit_status_id ON a.visit_status_id = b.visit_status_id
INNER JOIN tab_user c INNER JOIN tab_user AS c
ON c.user_id = a.user_id ON c.user_id = a.user_id
INNER JOIN tab_user d INNER JOIN tab_user AS d
ON d.user_id = a.created_user_id ON d.user_id = a.created_user_id
INNER JOIN tab_trip_type e INNER JOIN tab_trip_type AS e
ON e.trip_type_id = a.trip_type_id ON e.trip_type_id = a.trip_type_id
INNER JOIN tab_provider f INNER JOIN tab_provider AS f
ON f.provider_id = a.provider_id ` ON f.provider_id = a.provider_id `
} }
func (c *visitRepo) GetAll(user entity.User) ([]entity.Visit, error) { func (c *visitRepo) GetAll(user entity.User) ([]entity.Visit, error) {
@@ -191,12 +190,13 @@ func (c *visitRepo) Create(visit entity.Visit) (entity.Visit, error) {
row := c.conn.QueryRow(statusQuery, retVal.Status.Key, retVal.User.UUID, retVal.CreatedUser.UUID, retVal.TripType.Key) row := c.conn.QueryRow(statusQuery, retVal.Status.Key, retVal.User.UUID, retVal.CreatedUser.UUID, retVal.TripType.Key)
if err := row.Scan(&retVal.Status.ID, &retVal.Status.Key, &retVal.Status.Value, &retVal.User.ID, &retVal.User.Name, &retVal.CreatedUser.ID, &retVal.CreatedUser.Name, &retVal.TripType.ID, &retVal.TripType.Key, &retVal.TripType.Value); err != nil { if err := row.Scan(&retVal.Status.ID, &retVal.Status.Key, &retVal.Status.Value, &retVal.User.ID, &retVal.User.Name, &retVal.CreatedUser.ID, &retVal.CreatedUser.Name, &retVal.TripType.ID, &retVal.TripType.Key, &retVal.TripType.Value); err != nil {
fmt.Println("Error to get base data: ", err.Error()) fmt.Println("data.Visit: Error getting base data: ", err.Error())
return retVal, err return retVal, err
} }
results, err := c.conn.Exec(query, retVal.UUID, retVal.Status.ID, retVal.User.ID, retVal.VisitDatetime, retVal.PickupDatetime, retVal.Notes, retVal.CreatedUser.ID, toNullInt64(retVal.VisitDuration), retVal.ExternalID, returnDate, retVal.TripType.ID, retVal.Pickup.ID, retVal.PickupAddressID, retVal.DestinationAddressID, retVal.Provider.ProviderID) results, err := c.conn.Exec(query, retVal.UUID, retVal.Status.ID, retVal.User.ID, retVal.VisitDatetime, retVal.PickupDatetime, retVal.Notes, retVal.CreatedUser.ID, toNullInt64(retVal.VisitDuration), retVal.ExternalID, returnDate, retVal.TripType.ID, retVal.Pickup.ID, retVal.PickupAddressID, retVal.DestinationAddressID, retVal.Provider.ProviderID)
if err != nil { if err != nil {
fmt.Println("data.Visit: Error inserting visit: ", err.Error())
return retVal, err return retVal, err
} }
@@ -205,6 +205,5 @@ func (c *visitRepo) Create(visit entity.Visit) (entity.Visit, error) {
return retVal, err return retVal, err
} }
fmt.Println("Visit ID: ", retVal.ID)
return retVal, nil return retVal, nil
} }

65
data/datamysql/zipcode.go Normal file
View File

@@ -0,0 +1,65 @@
package datamysql
import (
"database/sql"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
// rideRepo maps methods to database
type zipcodeRepo struct {
conn executor
}
func newZipcodeRepo(conn executor) *zipcodeRepo {
return &zipcodeRepo{
conn: conn,
}
}
func (c *zipcodeRepo) getQuery() string {
const (
query = `SELECT
a.participating_zip_code_id,
a.participating_zip_code_uuid,
a.zipcode,
(IFNULL(a.participating, b'0') = b'1') participating
FROM
tab_participating_zip_code a `
)
return query
}
// parseSet parses a result set result to an entity array
func (c *zipcodeRepo) parseSet(rows *sql.Rows, err error) ([]entity.Zipcode, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Zipcode, 0)
for rows.Next() {
entity, err := c.parseEntity(rows)
if err != nil {
return nil, errors.Wrap(err)
}
result = append(result, entity)
}
return result, nil
}
// parseEntity parses a result to an entity
func (c *zipcodeRepo) parseEntity(row scanner) (retVal entity.Zipcode, err error) {
err = row.Scan(
&retVal.ID, &retVal.UUID, &retVal.Zipcode, &retVal.Participating)
return retVal, errors.Wrap(err)
}
func (c *zipcodeRepo) GetAll() ([]entity.Zipcode, error) {
return c.parseSet(c.conn.Query(c.getQuery()))
}
func (c *zipcodeRepo) GetByParticipatingZipcode(zipcode string) (entity.Zipcode, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+"WHERE a.participating = 1 AND a.zipcode = ?", zipcode))
}

22
default.dev.conf Normal file
View File

@@ -0,0 +1,22 @@
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443;
ssl on;
ssl_certificate /opt/app/certs/ssl_certificate.cer;
ssl_certificate_key /opt/app/certs/private.key;
server_name portal-api.dev.bcbsinstitute.com;
server_tokens off;
location / {
proxy_pass http://127.0.0.1:5100;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}

22
default.prd.conf Normal file
View File

@@ -0,0 +1,22 @@
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443;
ssl on;
ssl_certificate /opt/app/certs/ssl_certificate.cer;
ssl_certificate_key /opt/app/certs/private.key;
server_name portal-api.bcbsinstitute.com;
server_tokens off;
location / {
proxy_pass http://127.0.0.1:5100;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}

22
default.stg.conf Normal file
View File

@@ -0,0 +1,22 @@
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443;
ssl on;
ssl_certificate /opt/app/certs/ssl_certificate.cer;
ssl_certificate_key /opt/app/certs/private.key;
server_name portal-api.dev.bcbsinstitute.com;
server_tokens off;
location / {
proxy_pass http://127.0.0.1:5100;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}

View File

@@ -12,6 +12,8 @@ type repoManager interface {
Notification() NotificationRepo Notification() NotificationRepo
Profile() ProfileRepo Profile() ProfileRepo
Organization() OrganizationRepo Organization() OrganizationRepo
Zipcodes() ZipcodeRepo
Plans() PlanRepo
} }
// UserRepo defines the data set for users // UserRepo defines the data set for users
@@ -19,6 +21,7 @@ type UserRepo interface {
GetAll() (list []entity.User, err error) GetAll() (list []entity.User, err error)
GetByID(userID int64) (retVal entity.User, err error) GetByID(userID int64) (retVal entity.User, err error)
GetByUUID(uuid string, profile string) (entity.User, error) GetByUUID(uuid string, profile string) (entity.User, error)
GetByMemberID(memberID string) (entity.User, error)
Login(email string, pass string) (entity.User, error) Login(email string, pass string) (entity.User, error)
FullLogin(loginType string, key string, pass string, profile string) (entity.User, error) FullLogin(loginType string, key string, pass string, profile string) (entity.User, error)
Create(user entity.User) (entity.User, error) Create(user entity.User) (entity.User, error)
@@ -27,6 +30,9 @@ type UserRepo interface {
GetAddressByUUID(addressUUID string) (entity.Address, error) GetAddressByUUID(addressUUID string) (entity.Address, error)
GetContactType() (retVal []entity.ContactType, err error) GetContactType() (retVal []entity.ContactType, err error)
RemoveAddress(addressUUID string) error RemoveAddress(addressUUID string) error
SaveContact(contact entity.ContactInfo) (entity.ContactInfo, error)
RemoveContact(contact entity.ContactInfo) (entity.ContactInfo, error)
UpdateLogin(user entity.User) error
} }
// RideRepo defines the data set for Rides // RideRepo defines the data set for Rides
@@ -54,6 +60,9 @@ type ProviderRepo interface {
GetAll(user entity.User) ([]entity.Provider, error) GetAll(user entity.User) ([]entity.Provider, error)
Get(query string, lat float64, long float64, distance int64, planCode string, productID string, mukID string, internalID string, sort string, user entity.User) ([]entity.Provider, error) Get(query string, lat float64, long float64, distance int64, planCode string, productID string, mukID string, internalID string, sort string, user entity.User) ([]entity.Provider, error)
GetByMukID(mukID string, user entity.User) (entity.Provider, error) GetByMukID(mukID string, user entity.User) (entity.Provider, error)
GetByUUID(providerUUID string, user entity.User) (entity.Provider, error)
GetByNPI(NPI string, user entity.User) (entity.Provider, error)
GetByID(providerID int64, user entity.User) (entity.Provider, error)
} }
// NotificationRepo defines the data set for Notification // NotificationRepo defines the data set for Notification
@@ -70,6 +79,7 @@ type OrganizationRepo interface {
GetAllTypes() ([]entity.OrganizationType, error) GetAllTypes() ([]entity.OrganizationType, error)
GetByType(organizationTypeKey string, user entity.User) ([]entity.Organization, error) GetByType(organizationTypeKey string, user entity.User) ([]entity.Organization, error)
GetByUUID(organizationUUID string, user entity.User) (entity.Organization, error) GetByUUID(organizationUUID string, user entity.User) (entity.Organization, error)
GetByTypeAndReferenceID(typeKey string, referenceID int64, user entity.User) (entity.Organization, error)
GetContactsByOrganizationUUID(organizationUUID string) ([]entity.OrganizationContact, error) GetContactsByOrganizationUUID(organizationUUID string) ([]entity.OrganizationContact, error)
GetContactsByOrganizationID(organizationID int64) ([]entity.OrganizationContact, error) GetContactsByOrganizationID(organizationID int64) ([]entity.OrganizationContact, error)
GetContactsByUUID(contactUUID string) (entity.OrganizationContact, error) GetContactsByUUID(contactUUID string) (entity.OrganizationContact, error)
@@ -88,6 +98,13 @@ type OrganizationRepo interface {
GetTypeByKey(key string) (entity.OrganizationType, error) GetTypeByKey(key string) (entity.OrganizationType, error)
} }
type PlanRepo interface {
GetByAlphaPrefix(alphaPrefix string) (entity.Plan, error)
GetByUUID(planUUID string) ([]entity.Plan, error)
GetByID(planID int64) ([]entity.Plan, error)
GetByPrefixUUID(prefixUUID string) (entity.Plan, error)
}
// VisitRepo defines the data set for Rides // VisitRepo defines the data set for Rides
type VisitRepo interface { type VisitRepo interface {
Create(visit entity.Visit) (entity.Visit, error) Create(visit entity.Visit) (entity.Visit, error)
@@ -102,3 +119,8 @@ type ProfileRepo interface {
GetVisibles(visible bool) ([]entity.Profile, error) GetVisibles(visible bool) ([]entity.Profile, error)
GetByOrganizationType(organizationTypeID int64) ([]entity.Profile, error) GetByOrganizationType(organizationTypeID int64) ([]entity.Profile, error)
} }
type ZipcodeRepo interface {
GetAll() ([]entity.Zipcode, error)
GetByParticipatingZipcode(zipcode string) (entity.Zipcode, error)
}

21
domain/entity/plan.go Normal file
View File

@@ -0,0 +1,21 @@
package entity
import "time"
type Plan struct {
ID int64 `json:"-"`
UUID string `json:"id"`
Name string `json:"name"`
InternalID string `json:"key"`
Status bool `json:"desc"`
PlanEntityID int64 `json:"plan_entity_id"`
EntityID int64 `json:"entity_id"`
PayerID int64 `json:"payer_id"`
PayerName string `json:"payer_name"`
PrefixID int64 `json:"prefix_id"`
PrefixUUID string `json:"prefix_uuid"`
AlphaPrefix string `json:"alpha_prefix"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Active bool `json:"active"`
}

View File

@@ -26,6 +26,7 @@ type Provider struct {
Keys []ProviderKey `json:"keys"` Keys []ProviderKey `json:"keys"`
Address ProviderAddress `json:"address"` Address ProviderAddress `json:"address"`
Distance float64 `json:"distance"` Distance float64 `json:"distance"`
Organization Organization `json:"organization"`
} }
type ProviderKey struct { type ProviderKey struct {

View File

@@ -30,12 +30,15 @@ type User struct {
Profiles []Profile `json:"profiles,omitempty"` Profiles []Profile `json:"profiles,omitempty"`
Types []OrganizationType `json:"types,omitempty"` Types []OrganizationType `json:"types,omitempty"`
Organizations []Organization `json:"organizations,omitempty"` Organizations []Organization `json:"organizations,omitempty"`
Type string `json:"type,omitempty"`
} }
type ContactInfo struct { type ContactInfo struct {
ID int64 `db:"contact_id" json:"contact_id"` ID int64 `db:"contact_id" json:"contact_id"`
UUID string `db:"contact_uuid" json:"contact_uuid"`
Type ContactType `db:"contact_type" json:"contact_type"` Type ContactType `db:"contact_type" json:"contact_type"`
UserID int64 `db:"user_id" json:"-"` User User `db:"user" json:"-"`
Author User `db:"author" json:"-"`
Value string `db:"value" json:"value"` Value string `db:"value" json:"value"`
} }

8
domain/entity/zipcode.go Normal file
View File

@@ -0,0 +1,8 @@
package entity
type Zipcode struct {
ID int64 `db:"participating_zip_code_id" json:"-"`
UUID string `db:"participating_zip_code_uuid" json:"uuid"`
Zipcode string `db:"zipcode" json:"zipcode"`
Participating bool `db:"participating" json:"participating"`
}

View File

@@ -28,6 +28,10 @@ func (s *organizationService) GetByName(name string, searchType string, user ent
return s.svc.db.Organization().GetByName(name, searchType, user) return s.svc.db.Organization().GetByName(name, searchType, user)
} }
func (s *organizationService) GetByTypeAndReferenceID(typeKey string, referenceID int64, user entity.User) (entity.Organization, error) {
return s.svc.db.Organization().GetByTypeAndReferenceID(typeKey, referenceID, user)
}
func (s *organizationService) GetByUUID(organizationUUID string, user entity.User) (entity.Organization, error) { func (s *organizationService) GetByUUID(organizationUUID string, user entity.User) (entity.Organization, error) {
organization, err := s.svc.db.Organization().GetByUUID(organizationUUID, user) organization, err := s.svc.db.Organization().GetByUUID(organizationUUID, user)
if err != nil { if err != nil {

31
domain/service/plan.go Normal file
View File

@@ -0,0 +1,31 @@
package service
import (
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
type planService struct {
svc *Service
}
func newPlanService(svc *Service) *planService {
return &planService{
svc: svc,
}
}
func (s *planService) GetByAlphaPrefix(alphaPrefix string) (entity.Plan, error) {
return s.svc.db.Plans().GetByAlphaPrefix(alphaPrefix)
}
func (s *planService) GetByUUID(planUUID string) ([]entity.Plan, error) {
return s.svc.db.Plans().GetByUUID(planUUID)
}
func (s *planService) GetByID(planID int64) ([]entity.Plan, error) {
return s.svc.db.Plans().GetByID(planID)
}
func (s *planService) GetByPrefixUUID(prefixUUID string) (entity.Plan, error) {
return s.svc.db.Plans().GetByPrefixUUID(prefixUUID)
}

View File

@@ -1,6 +1,9 @@
package service package service
import ( import (
"errors"
"fmt"
"bitbucket.org/nemt/nemt-portal-api/domain/entity" "bitbucket.org/nemt/nemt-portal-api/domain/entity"
) )
@@ -42,5 +45,68 @@ func (s *providerService) Get(query string, lat float64, long float64, distance
} }
func (s *providerService) GetByMukID(mukID string, user entity.User) (entity.Provider, error) { func (s *providerService) GetByMukID(mukID string, user entity.User) (entity.Provider, error) {
return s.svc.db.Provider().GetByMukID(mukID, user) provider, err := s.svc.db.Provider().GetByMukID(mukID, user)
if err != nil {
return provider, err
}
organization, err := s.svc.db.Organization().GetByTypeAndReferenceID("provider", provider.ProviderID, user)
if err != nil {
return provider, err
}
provider.Organization = organization
return provider, nil
}
func (s *providerService) GetByUUID(providerUUID string, user entity.User) (entity.Provider, error) {
provider, err := s.svc.db.Provider().GetByUUID(providerUUID, user)
if err != nil {
fmt.Println("providerService.GetByUUID: Provider UUID: ", providerUUID)
fmt.Println("providerService.GetByUUID: Provider Error: ", err.Error())
return provider, err
}
organization, err := s.svc.db.Organization().GetByTypeAndReferenceID("provider", provider.ProviderID, user)
if err != nil {
fmt.Println("providerService.GetByUUID: OrganizationByType ProviderID : ", provider.ProviderID)
fmt.Println("providerService.GetByUUID: OrganizationByType Error: ", err.Error())
return provider, err
}
provider.Organization = organization
return provider, nil
}
func (s *providerService) GetByNPI(NPI string, user entity.User) (entity.Provider, error) {
provider, err := s.svc.db.Provider().GetByNPI(NPI, user)
if err != nil {
return provider, err
}
organization, err := s.svc.db.Organization().GetByTypeAndReferenceID("provider", provider.ProviderID, user)
if err != nil {
return provider, err
}
provider.Organization = organization
return provider, nil
}
func (s *providerService) GetByOrganization(organizationUUID string, user entity.User) (entity.Provider, error) {
organization, err := s.svc.db.Organization().GetByUUID(organizationUUID, user)
if err != nil {
return entity.Provider{}, err
}
if organization.Type.Key != "provider" {
return entity.Provider{}, errors.New("invalid organization")
}
provider, err := s.svc.db.Provider().GetByID(organization.ReferenceID, user)
if err != nil {
return entity.Provider{}, err
}
return provider, nil
} }

View File

@@ -1,6 +1,8 @@
package service package service
import ( import (
"fmt"
"bitbucket.org/nemt/nemt-portal-api/domain/entity" "bitbucket.org/nemt/nemt-portal-api/domain/entity"
) )
@@ -20,11 +22,13 @@ func newRideService(svc *Service) *rideService {
func (s *rideService) Save(ride entity.Ride) (entity.Ride, error) { func (s *rideService) Save(ride entity.Ride) (entity.Ride, error) {
ride, err := s.svc.db.Rides().Save(ride) ride, err := s.svc.db.Rides().Save(ride)
if err != nil { if err != nil {
fmt.Println("Ride Service.Save: Error saving Ride: ", err.Error())
return ride, err return ride, err
} }
user, err := s.svc.db.Users().GetByID(ride.CreatedUser.ID) user, err := s.svc.db.Users().GetByID(ride.CreatedUser.ID)
if err != nil { if err != nil {
fmt.Println("Ride Service.Save: Error getting User: ", err.Error())
return ride, err return ride, err
} }
@@ -56,7 +60,14 @@ func (s *rideService) GetByID(id int64, user entity.User) (entity.Ride, error) {
// GetByUUID return a specific ride // GetByUUID return a specific ride
func (s *rideService) GetByUUID(uuid string, user entity.User) (entity.Ride, error) { func (s *rideService) GetByUUID(uuid string, user entity.User) (entity.Ride, error) {
return s.svc.db.Rides().GetByUUID(uuid, user) ride, err := s.svc.db.Rides().GetByUUID(uuid, user)
if err != nil {
fmt.Println("Ride Service.GetByUUID: Ride UUID: ", uuid)
fmt.Println("Ride Service.GetByUUID: Error getting Ride: ", err.Error())
return entity.Ride{}, err
}
return ride, nil
} }
// GetByUUID return a specific ride // GetByUUID return a specific ride

View File

@@ -25,6 +25,8 @@ type Service struct {
Notification *notificationService Notification *notificationService
Profile *profileService Profile *profileService
Organization *organizationService Organization *organizationService
Zipcodes *zipcodeService
Plans *planService
} }
// New returns a new domain Service instance // New returns a new domain Service instance
@@ -39,6 +41,8 @@ func New(db contract.DataManager, cache contract.CacheManager, cfg *config.Confi
instance.Notification = newNotificationService(instance) instance.Notification = newNotificationService(instance)
instance.Profile = newProfileService(instance) instance.Profile = newProfileService(instance)
instance.Organization = newOrganizationService(instance) instance.Organization = newOrganizationService(instance)
instance.Zipcodes = newZipcodeService(instance)
instance.Plans = newPlanService(instance)
}) })
return instance, nil return instance, nil

View File

@@ -33,6 +33,10 @@ func (s *userService) GetByUUID(uuid string, profile string) (entity.User, error
return s.svc.db.Users().GetByUUID(uuid, profile) return s.svc.db.Users().GetByUUID(uuid, profile)
} }
func (s *userService) GetByMemberID(memberID string) (entity.User, error) {
return s.svc.db.Users().GetByMemberID(memberID)
}
// Login returns a specific user by email and pass // Login returns a specific user by email and pass
func (s *userService) Login(email string, pass string) (entity.User, error) { func (s *userService) Login(email string, pass string) (entity.User, error) {
return s.svc.db.Users().Login(email, pass) return s.svc.db.Users().Login(email, pass)
@@ -68,6 +72,10 @@ func (s *userService) CreateBulk(users []entity.User) ([]entity.User, error) {
return users, nil return users, nil
} }
func (s *userService) UpdateLogin(user entity.User) error {
return s.svc.db.Users().UpdateLogin(user)
}
// GetUsersByProfile returns a list of users by profile // GetUsersByProfile returns a list of users by profile
func (s *userService) GetUsersByProfile(profile string) ([]entity.User, error) { func (s *userService) GetUsersByProfile(profile string) ([]entity.User, error) {
return s.svc.db.Users().GetUsersByProfile(profile) return s.svc.db.Users().GetUsersByProfile(profile)
@@ -82,6 +90,26 @@ func (s *userService) SaveAddress(address entity.Address) (entity.Address, error
return s.svc.db.Users().SaveAddress(address) return s.svc.db.Users().SaveAddress(address)
} }
func (s *userService) SaveContact(contact entity.ContactInfo) (entity.ContactInfo, error) {
user, err := s.svc.db.Users().GetByUUID(contact.User.UUID, "")
if err != nil {
return entity.ContactInfo{}, nil
}
contact.User = user
return s.svc.db.Users().SaveContact(contact)
}
func (s *userService) RemoveContact(contact entity.ContactInfo) (entity.ContactInfo, error) {
user, err := s.svc.db.Users().GetByUUID(contact.User.UUID, "")
if err != nil {
return entity.ContactInfo{}, nil
}
contact.User = user
return s.svc.db.Users().RemoveContact(contact)
}
// GetAddressByUUID returns a list of users by profile // GetAddressByUUID returns a list of users by profile
func (s *userService) GetAddressByUUID(addressUUID string) (entity.Address, error) { func (s *userService) GetAddressByUUID(addressUUID string) (entity.Address, error) {
return s.svc.db.Users().GetAddressByUUID(addressUUID) return s.svc.db.Users().GetAddressByUUID(addressUUID)

View File

@@ -29,10 +29,10 @@ func (s *visitService) GetAll(user entity.User) ([]entity.Visit, error) {
return nil, err return nil, err
} }
rides, err := s.svc.db.Rides().GetAll(user) rides, _ := s.svc.db.Rides().GetAll(user)
if err != nil { // if err != nil {
return nil, err // return nil, err
} // }
ridesByVisit := make(map[int64][]entity.Ride) ridesByVisit := make(map[int64][]entity.Ride)
for _, r := range rides { for _, r := range rides {
@@ -55,10 +55,10 @@ func (s *visitService) GetByUUID(visitUUID string, user entity.User) (entity.Vis
return entity.Visit{}, errors.Wrap(err) return entity.Visit{}, errors.Wrap(err)
} }
rides, err := s.svc.db.Rides().GetByVisitUUID(visitUUID, user) rides, _ := s.svc.db.Rides().GetByVisitUUID(visitUUID, user)
if err != nil { // if err != nil {
return entity.Visit{}, errors.Wrap(err) // return entity.Visit{}, errors.Wrap(err)
} // }
visit.Rides = rides visit.Rides = rides
return visit, nil return visit, nil
@@ -71,10 +71,10 @@ func (s *visitService) GetByID(visitID int64, user entity.User) (entity.Visit, e
return entity.Visit{}, errors.Wrap(err) return entity.Visit{}, errors.Wrap(err)
} }
rides, err := s.svc.db.Rides().GetByVisitUUID(visit.UUID, user) rides, _ := s.svc.db.Rides().GetByVisitUUID(visit.UUID, user)
if err != nil { // if err != nil {
return entity.Visit{}, errors.Wrap(err) // return entity.Visit{}, errors.Wrap(err)
} // }
visit.Rides = rides visit.Rides = rides
return visit, nil return visit, nil

25
domain/service/zipcode.go Normal file
View File

@@ -0,0 +1,25 @@
package service
import (
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
// userService is the domain service for user operations
type zipcodeService struct {
svc *Service
}
// newUserService returns an instance of userService
func newZipcodeService(svc *Service) *zipcodeService {
return &zipcodeService{
svc: svc,
}
}
func (s *zipcodeService) GetAll() ([]entity.Zipcode, error) {
return s.svc.db.Zipcodes().GetAll()
}
func (s *zipcodeService) GetByParticipatingZipcode(zipcode string) (entity.Zipcode, error) {
return s.svc.db.Zipcodes().GetByParticipatingZipcode(zipcode)
}

View File

@@ -1,35 +1,26 @@
{ {
"containerDefinitions": [ "containerDefinitions": [
{ {
"name": "api-development", "name": "portal-api",
"image": "xxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/dev.nemt-portal-api:latest", "image": "105690980714.dkr.ecr.us-east-2.amazonaws.com/nemt-portal-api:dev",
"cpu": 128, "cpu": 128,
"memory": 128, "memory": 128,
"essential": true, "essential": true,
"logConfiguration": { "logConfiguration": {
"logDriver": "awslogs", "logDriver": "awslogs",
"options": { "options": {
"awslogs-group": "nemt-portal-api", "awslogs-group": "portal-api",
"awslogs-region": "sa-east-1", "awslogs-region": "us-east-2",
"awslogs-stream-prefix": "development" "awslogs-stream-prefix": "test"
} }
}, },
"portMappings": [ "portMappings": [
{ {
"containerPort": 5100 "containerPort": 443,
} "hostPort": 5100
],
"environment": [
{
"name": "SERVICE_5100_NAME",
"value": "portal-api"
},
{
"name": "SERVICE_5100_TAG",
"value": "api"
} }
] ]
} }
], ],
"family": "api-development" "family": "portal-api-dev"
} }

View File

@@ -16,7 +16,7 @@
}, },
"portMappings": [ "portMappings": [
{ {
"containerPort": 5100, "containerPort": 443,
"hostPort": 5100 "hostPort": 5100
} }
] ]

View File

@@ -16,7 +16,7 @@
}, },
"portMappings": [ "portMappings": [
{ {
"containerPort": 5100, "containerPort": 443,
"hostPort": 5100 "hostPort": 5100
} }
] ]

View File

@@ -25,6 +25,7 @@ type Config struct {
Blue365 Blue365Config Blue365 Blue365Config
Email EmailConfig Email EmailConfig
GoogleShortener GoogleShortenerConfig GoogleShortener GoogleShortenerConfig
Eligibility EligibilityConfig
} }
// AppConfig represents the configuration values about the application. // AppConfig represents the configuration values about the application.
@@ -137,6 +138,10 @@ type GoogleShortenerConfig struct {
SecretKey string SecretKey string
} }
type EligibilityConfig struct {
Url string
}
// Read returns the configuration values, // Read returns the configuration values,
// based on the configuration files and environment variables. // based on the configuration files and environment variables.
func Read() (*Config, error) { func Read() (*Config, error) {
@@ -238,6 +243,9 @@ func Read() (*Config, error) {
ClientID: viper.GetString("google-shortener.client-id"), ClientID: viper.GetString("google-shortener.client-id"),
SecretKey: viper.GetString("google-shortener.secret-key"), SecretKey: viper.GetString("google-shortener.secret-key"),
}, },
Eligibility : EligibilityConfig{
Url : viper.GetString("eligibility.url"),
},
}, nil }, nil
} }

32
nginx.conf Normal file
View File

@@ -0,0 +1,32 @@
user nginx;
worker_processes 1;
daemon on;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}

1602
returnExample.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
package authorization
import (
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
)
func CanCreateAddress(user viewmodel.User, organization viewmodel.Organization) bool {
//rules are the same for address creation and for organization creation
return CanCreateOrganization(user, organization)
}
func CanUpdateAddress(user viewmodel.User, organization viewmodel.Organization) bool {
return CanCreateAddress(user, organization)
}

View File

@@ -0,0 +1 @@
package authorization

View File

@@ -0,0 +1,15 @@
package authorization
import (
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
)
func CanCreateContact(user viewmodel.User, organization viewmodel.Organization) bool {
//rules are the same for contact creation and for organization creation
return CanCreateOrganization(user, organization)
}
func CanUpdateContact(user viewmodel.User, organization viewmodel.Organization) bool {
return CanCreateAddress(user, organization)
}

View File

@@ -0,0 +1,76 @@
package authorization
import (
"fmt"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
)
func isAChildOrganization(potentialParent viewmodel.Organization, potentialChild viewmodel.Organization) bool {
for _, org := range potentialParent.ChildOrgs {
if potentialChild.UUID == org.UUID {
return true
}
}
return false
}
func isSameOrganization(organizationA viewmodel.Organization, organizationB viewmodel.Organization) bool {
return organizationA.UUID == organizationB.UUID
}
func grabOrgFromUser(user viewmodel.User) (viewmodel.Organization, error) {
if len(user.Profiles) < 1 {
return viewmodel.Organization{}, fmt.Errorf("User has no organizations %v", user)
}
return user.Profiles[0].Organization, nil
}
func grabOrgFromUserDirectly(user viewmodel.User) (viewmodel.Organization, error) {
if len(user.Organizations) < 1 {
return viewmodel.Organization{}, fmt.Errorf("User has no organizations %v", user)
}
return user.Organizations[0], nil
}
func CanCreateOrganization(user viewmodel.User, organization viewmodel.Organization ) bool {
userRole, err := grabProfileFromUser(user)
if err != nil {
return false
}
/*
Admin BCBSI
Admin Technical Support
Super Admin Technical Support
Manage all Organizations*/
if userRole.Key == bcbsiAdmin || userRole.Key == brighterDevAdmin || userRole.Key == superAdmin{
return true
}
userOrg, err := grabOrgFromUser(user)
if err != nil{
return false
}
/*
Admin Provider
Admin Plan
Manage the authenticated Authorized User's Organization and child Organizations */
if userRole.Key == providerAdmin || userRole.Key == planAdmin{
if isSameOrganization(userOrg, organization) || isAChildOrganization(userOrg, organization) {
return true
}
return false
}
return false
}
func CanUpdateOrganization(user viewmodel.User, organization viewmodel.Organization) bool{
return CanCreateOrganization(user, organization)
}

View File

@@ -0,0 +1,62 @@
package authorization
import (
"fmt"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
)
const (
superAdmin = "AD"
scheduler = "SP"
support = "SPT"
member = "US"
brighterDevAdmin = "BDCAD"
bcbsiAdmin = "BCBSIAD"
planAdmin = "PLANAD"
providerAdmin = "SCHDAD"
)
func grabProfileFromUser(user viewmodel.User) (viewmodel.Profile, error) {
if len(user.Profiles) < 1 {
return viewmodel.Profile{}, fmt.Errorf("User has no profiles %v", user)
}
return user.Profiles[0], nil
}
func morePrivileged(who viewmodel.Profile, towardsWhom viewmodel.Profile) bool {
order := []string{superAdmin, brighterDevAdmin, bcbsiAdmin, planAdmin, providerAdmin, support, scheduler, member}
for _, value := range order {
if value == who.Key {
return true
}
if value == towardsWhom.Key {
return false
}
}
// should hapen only in case profile key is empty
// and that's something fishy so let's deny!
return false
}
func equallyOrMorePrivileged(who viewmodel.Profile, towardsWhom viewmodel.Profile) bool {
if who.Key == towardsWhom.Key {
return true
}
return morePrivileged(who, towardsWhom)
}
func lessPrivilegedThanAdmin(who viewmodel.Profile) bool {
switch who.Key {
case member:
return true
case scheduler:
return true
case support:
return true
}
return false
}

View File

@@ -0,0 +1,86 @@
package authorization
import "bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
/*
CanCreateUser returns true if currentUser is allowed to create updatingUser according to
authorization rules
*/
func CanCreateUser(currentUser viewmodel.User, updatingUser viewmodel.User) bool {
if len(currentUser.Profiles) < 1 {
return false
}
if len(updatingUser.Profiles) < 1 {
return false
}
currentUserOrganization, err := grabOrgFromUser(currentUser)
if err != nil {
return false
}
updatingUserOrganization, err := grabOrgFromUserDirectly(updatingUser)
if err != nil {
return false
}
currentUserRole, err := grabProfileFromUser(currentUser)
if err != nil {
return false
}
updatingUserRole, err := grabProfileFromUser(updatingUser)
if err != nil {
return false
}
/*
Admin Provider
Manage all Authorized Users of the provider Organization or child organization
The (Provider) Admin can manage Authorized Users of their Parent/ Top-level Org , but not Admins
*/
currentUserHigherOrEqualOrg := isSameOrganization(currentUserOrganization, updatingUserOrganization) || isAChildOrganization(currentUserOrganization, updatingUserOrganization)
currentUserLowerOrg := isAChildOrganization(updatingUserOrganization, currentUserOrganization)
if currentUserRole.Key == providerAdmin && currentUserHigherOrEqualOrg && equallyOrMorePrivileged(currentUserRole, updatingUserRole) {
return true
}
if currentUserRole.Key == providerAdmin && currentUserLowerOrg && lessPrivilegedThanAdmin(updatingUserRole) {
return true
}
/* Admin BCBSI
Manage all Authorized Users except Admins
return false
*/
if currentUserRole.Key == bcbsiAdmin && lessPrivilegedThanAdmin(updatingUserRole) {
return true
}
/* Admin Technical Support Manage all Authorized Users except Admins */
if currentUserRole.Key == brighterDevAdmin && lessPrivilegedThanAdmin(updatingUserRole) {
return true
}
/* Admin Plan Manage all Authorized Users of a single participating Plan except Admins */
if currentUserRole.Key == planAdmin && lessPrivilegedThanAdmin(updatingUserRole) && isSameOrganization(currentUserOrganization, updatingUserOrganization) {
return true
}
/* Super Admin Technical Support
Manage all Members, INCLUDING Admins */
if currentUserRole.Key == superAdmin {
return true
}
return false
}

View File

@@ -1,14 +1,24 @@
package eligibilityroute package eligibilityroute
import ( import (
"context"
"encoding/xml"
"fmt"
"html"
"math/rand"
"strings"
"sync" "sync"
"time"
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice" "bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
"bitbucket.org/nemt/nemt-portal-api/application/third/eligibility/bcbsi" "bitbucket.org/nemt/nemt-portal-api/application/third/eligibility/bcbsi"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel" "bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/infra/auth"
"bitbucket.org/nemt/nemt-portal-api/infra/config" "bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils" "bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
"bitbucket.org/nemt/nemt-portal-api/server/validation"
"github.com/labstack/echo" "github.com/labstack/echo"
"googlemaps.github.io/maps"
) )
var ( var (
@@ -33,6 +43,29 @@ func controllerInstance(cfg *config.Config, svc *applicationservice.Service) *co
return instance return instance
} }
func (c *controller) rangeIn(low, hi int) string {
result := low + rand.Intn(hi-low)
return fmt.Sprintf("%v", result)
}
func (c *controller) generatePassword(n int) string {
const (
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
)
return c.stringWithCharset(n, charset)
}
func (c *controller) stringWithCharset(length int, charset string) string {
b := make([]byte, length)
var seededRand *rand.Rand = rand.New(
rand.NewSource(time.Now().UnixNano()))
for i := range b {
b[i] = charset[seededRand.Intn(len(charset))]
}
return string(b)
}
func (c *controller) handleEligibility(ctx echo.Context) error { func (c *controller) handleEligibility(ctx echo.Context) error {
var eligibility viewmodel.Eligibility var eligibility viewmodel.Eligibility
@@ -40,10 +73,190 @@ func (c *controller) handleEligibility(ctx echo.Context) error {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
ret, err := c.bcbsi.BXE.CheckEligibility(eligibility) authUser, err := auth.GetUserDetail(ctx, c.cfg)
if err != nil { if err != nil {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
return routeutils.ResponseAPIOK(ctx, ret) if validationErrors := validation.ValidateEligibility(&eligibility.User); len(validationErrors) > 0 {
return routeutils.ResponseAPICustomValidationError(ctx, "eligibility validation failed", validationErrors)
}
if eligibility.Provider.ProviderNPI == "" {
provider, err := c.svc.Provider.GetByOrganization(authUser.Profiles[0].Organization.UUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
eligibility.Provider.ProviderNPI = provider.InternalID
eligibility.Provider.ProviderName = provider.OrganizatioName
}
loc, _ := time.LoadLocation("America/Chicago")
eligibility.TrackingID = c.rangeIn(1000000, 9999999)
eligibility.ServiceInfo.DateOfService = time.Now().In(loc)
eligibility.ServiceInfo.ServiceTypeCodes = []string{"30"}
var plan viewmodel.Plan
if eligibility.Subscriber.SubscriberID != "" {
plan, err = c.svc.Plan.GetByAlphaPrefix(eligibility.Subscriber.SubscriberID[:3])
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
eligibility.Payer.PayerID = fmt.Sprintf("%v", plan.PayerID)
eligibility.Payer.PayerName = plan.PayerName
} else {
return routeutils.ResponseAPIFieldValidationError(ctx, "subscriber_id", "member # is required.")
}
ret, err := c.bcbsi.BXE.CheckEligibility(eligibility)
if err != nil {
fmt.Println("Error Here: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
if ret.QueryResult.QueryResultSummary.BenefitsFound {
xmlString := html.UnescapeString(ret.QueryResult.HIPPA271.T271)
xmlReader := strings.NewReader(xmlString)
var f viewmodel.Interchange271
err = xml.NewDecoder(xmlReader).Decode(&f)
if err != nil {
fmt.Println("Error to unmarshal: ", err.Error())
}
user, err := c.svc.Users.GetByMemberID(eligibility.Subscriber.SubscriberID)
if err != nil {
fmt.Println(err)
return routeutils.HandleAPIError(ctx, err)
}
if user.ID == "" {
user.Pass = c.generatePassword(8)
user.BirthDate = &eligibility.Subscriber.DemographicInfo.DateOfBirth
user.Member = &eligibility.Subscriber.SubscriberID
user.Gender = &eligibility.Subscriber.DemographicInfo.Gender
user.First = eligibility.Subscriber.Name.First
user.Last = eligibility.Subscriber.Name.Last
user.Active = true
user.Type = &eligibility.Subscriber.PatientType
user.PhoneNumber = eligibility.User.PhoneNumber
user.Email = eligibility.User.Email
profile, err := c.svc.Profile.GetByKey("US")
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
user.Profiles = append(user.Profiles, profile)
if user.BirthDate == nil || user.BirthDate.IsZero() {
return routeutils.ResponseAPIAuthError(ctx, "birthdate is required", false)
}
if user.Member == nil || len(*user.Member) == 0 {
return routeutils.ResponseAPIAuthError(ctx, "member is required", false)
}
if user.Gender == nil || len(*user.Gender) == 0 || (*user.Gender != "M" && *user.Gender != "F" && *user.Gender != "U") {
return routeutils.ResponseAPIAuthError(ctx, "gender is required", false)
}
if len(user.Name) == 0 && len(user.First) == 0 && len(user.Last) == 0 {
return routeutils.ResponseAPIAuthError(ctx, "name is required", false)
}
if len(user.First) != 0 && len(user.Last) != 0 {
user.Name = fmt.Sprintf("%s %s", user.First, user.Last)
}
if user.PhoneNumber != nil && len(*user.PhoneNumber) == 10 && !strings.Contains(*user.PhoneNumber, "+1") {
phoneNumber := fmt.Sprintf("+1%s", *user.PhoneNumber)
user.PhoneNumber = &phoneNumber
} else {
return routeutils.ResponseAPIFieldValidationError(ctx, "phonenumber", "Phone number is required")
}
user, err = c.svc.Users.Create(user, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
} else {
if eligibility.User.Email != nil && len(*eligibility.User.Email) > 0 {
user.Email = eligibility.User.Email
}
if eligibility.User.PhoneNumber != nil {
if len(*eligibility.User.PhoneNumber) == 10 && !strings.Contains(*eligibility.User.PhoneNumber, "+1") {
phoneNumber := fmt.Sprintf("+1%s", *eligibility.User.PhoneNumber)
eligibility.User.PhoneNumber = &phoneNumber
}
if len(*eligibility.User.PhoneNumber) > 0 {
user.PhoneNumber = eligibility.User.PhoneNumber
}
}
err = c.svc.Users.UpdateLogin(user)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
}
address := viewmodel.Address{}
header := f.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N3_0950
body := f.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N4_0960
zipCode := strings.TrimSpace(body.N403)
address.AddressTypeName = "Home"
address.AddressType = "home"
address.Name = fmt.Sprintf("%s, %s", header.N301, body.N401)
address.Address = fmt.Sprintf("%s, %s (%s)", header.N301, body.N401, zipCode)
address.CreatedUserUUID = authUser.ID
address.User = user
address.Type = "provider"
googleMapsAPI, err := maps.NewClient(maps.WithClientIDAndSignature("gme-bluecrossandblue1", "msqgD-jdqCyR0M_1u5C1HION5iI="))
if err != nil {
fmt.Println("Error to instantiate googles api: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
r := &maps.GeocodingRequest{
Address: address.Address + " " + body.N402 + ", " + zipCode,
}
result, err := googleMapsAPI.Geocode(context.Background(), r)
if err != nil {
fmt.Println("Error to instantiate googles api: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
if len(result) > 0 {
address.Latitude = result[0].Geometry.Location.Lat
address.Longitude = result[0].Geometry.Location.Lng
}
if len(user.Addresses) > 0 {
for _, a := range user.Addresses {
if a.AddressType == "home" {
err := c.svc.Users.RemoveAddress(a.UUID)
if err != nil {
fmt.Println("Error to remove old address: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
}
}
}
address, err = c.svc.Users.SaveAddress(address)
if err != nil {
fmt.Println("Error to save address: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
user.Addresses = append(user.Addresses, address)
return ctx.JSON(200, user)
} else {
return routeutils.ResponseAPINotEligibleWithMessageError(ctx, "No benefits found for member")
}
} }

View File

@@ -10,6 +10,7 @@ import (
"bitbucket.org/nemt/nemt-portal-api/infra/cache" "bitbucket.org/nemt/nemt-portal-api/infra/cache"
"bitbucket.org/nemt/nemt-portal-api/infra/config" "bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils" "bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
"bitbucket.org/nemt/nemt-portal-api/server/authorization"
"github.com/labstack/echo" "github.com/labstack/echo"
) )
@@ -64,6 +65,11 @@ func (c *controller) handleAddOrganization(ctx echo.Context) error {
if err != nil { if err != nil {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
if !authorization.CanCreateOrganization(authUser, org) {
return routeutils.ResponseAPIAuthorizationError(ctx)
}
org.Author.ID = authUser.ID org.Author.ID = authUser.ID
org.LastEditor.ID = authUser.ID org.LastEditor.ID = authUser.ID
@@ -127,6 +133,15 @@ func (c *controller) handleParent(ctx echo.Context) error {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
organization, err := c.svc.Organization.GetByUUID(orgUUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if !authorization.CanUpdateOrganization(authUser, organization){
return routeutils.ResponseAPIAuthorizationError(ctx)
}
resp, err := c.svc.Organization.SetParentOrganization(orgUUID, parent.UUID, authUser) resp, err := c.svc.Organization.SetParentOrganization(orgUUID, parent.UUID, authUser)
if err != nil { if err != nil {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
@@ -152,6 +167,15 @@ func (c *controller) handleChild(ctx echo.Context) error {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
organization, err := c.svc.Organization.GetByUUID(orgUUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if !authorization.CanUpdateOrganization(authUser, organization){
return routeutils.ResponseAPIAuthorizationError(ctx)
}
_, err = c.svc.Organization.SetParentOrganization(child.UUID, orgUUID, authUser) _, err = c.svc.Organization.SetParentOrganization(child.UUID, orgUUID, authUser)
if err != nil { if err != nil {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
@@ -246,6 +270,18 @@ func (c *controller) handleAddAddress(ctx echo.Context) error {
if err != nil { if err != nil {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
organization, err := c.svc.Organization.GetByUUID(orgUUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if !authorization.CanCreateAddress(authUser, organization) {
return routeutils.ResponseAPIAuthorizationError(ctx)
}
return routeutils.ResponseAPIAuthorizationError(ctx)
address.CreatedUser.ID = authUser.ID address.CreatedUser.ID = authUser.ID
address.UpdatedUser.ID = authUser.ID address.UpdatedUser.ID = authUser.ID
@@ -278,6 +314,7 @@ func (c *controller) handleRemoveContact(ctx echo.Context) error {
if err != nil { if err != nil {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
contact.UpdatedUser.ID = authUser.ID contact.UpdatedUser.ID = authUser.ID
err = c.svc.Organization.InactivateOrganizationContact(orgUUID, contact, authUser) err = c.svc.Organization.InactivateOrganizationContact(orgUUID, contact, authUser)
@@ -309,6 +346,16 @@ func (c *controller) handleAddContact(ctx echo.Context) error {
if err != nil { if err != nil {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
organization, err := c.svc.Organization.GetByUUID(orgUUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if !authorization.CanCreateContact(authUser, organization) {
return routeutils.ResponseAPIAuthorizationError(ctx)
}
contact.CreatedUser.ID = authUser.ID contact.CreatedUser.ID = authUser.ID
contact.UpdatedUser.ID = authUser.ID contact.UpdatedUser.ID = authUser.ID

View File

@@ -124,27 +124,27 @@ func (c *controller) handleList(ctx echo.Context) error {
name := ctx.QueryParam("name") name := ctx.QueryParam("name")
searchBy := ctx.QueryParam("searchBy") searchBy := ctx.QueryParam("searchBy")
// lat, err := routeutils.GetAndValidateFloatQueryParam(ctx, "lat", "latitude is mandatory") lat, err := routeutils.GetAndValidateFloatQueryParam(ctx, "lat", "latitude is required")
// if err != nil { if err != nil {
// return err return err
// } }
// long, err := routeutils.GetAndValidateFloatQueryParam(ctx, "long", "longitude is mandatory") long, err := routeutils.GetAndValidateFloatQueryParam(ctx, "long", "longitude is required")
// if err != nil { if err != nil {
// return err return err
// } }
distance, err := routeutils.GetAndValidateIntQueryParam(ctx, "distance", "distance is mandatory") distance, err := routeutils.GetAndValidateIntQueryParam(ctx, "distance", "distance is required")
if err != nil { if err != nil {
distance = 10 distance = 10
} }
limit, err := routeutils.GetAndValidateIntQueryParam(ctx, "limit", "limit is mandatory") limit, err := routeutils.GetAndValidateIntQueryParam(ctx, "limit", "limit is required")
if err != nil { if err != nil {
limit = 50 limit = 50
} }
sortBy, err := routeutils.GetAndValidateStringQueryParam(ctx, "sortby", "limit is mandatory") sortBy, err := routeutils.GetAndValidateStringQueryParam(ctx, "sortby", "limit is required")
if err != nil || (sortBy != "distance" && sortBy != "name") { if err != nil || (sortBy != "distance" && sortBy != "name") {
sortBy = "distance" sortBy = "distance"
} }
@@ -152,8 +152,8 @@ func (c *controller) handleList(ctx echo.Context) error {
providerParams := npdmodel.ProviderSearchParams{ providerParams := npdmodel.ProviderSearchParams{
Name: name, Name: name,
SearchBy: searchBy, SearchBy: searchBy,
Latitude: 41.819078, Latitude: lat,
Longitude: -87.623129, Longitude: long,
Distance: distance, Distance: distance,
Limit: limit, Limit: limit,
Offset: 0, Offset: 0,

View File

@@ -16,6 +16,7 @@ import (
"bitbucket.org/nemt/nemt-portal-api/server/router/placesroute" "bitbucket.org/nemt/nemt-portal-api/server/router/placesroute"
"bitbucket.org/nemt/nemt-portal-api/server/router/profileroute" "bitbucket.org/nemt/nemt-portal-api/server/router/profileroute"
"bitbucket.org/nemt/nemt-portal-api/server/router/providerroute" "bitbucket.org/nemt/nemt-portal-api/server/router/providerroute"
"bitbucket.org/nemt/nemt-portal-api/server/router/selfregisterroute"
"bitbucket.org/nemt/nemt-portal-api/server/router/tncroute" "bitbucket.org/nemt/nemt-portal-api/server/router/tncroute"
"bitbucket.org/nemt/nemt-portal-api/server/router/twilioroute" "bitbucket.org/nemt/nemt-portal-api/server/router/twilioroute"
"bitbucket.org/nemt/nemt-portal-api/server/router/usersroute" "bitbucket.org/nemt/nemt-portal-api/server/router/usersroute"
@@ -37,14 +38,16 @@ func Register(e *echo.Echo, cfg *config.Config, svc *applicationservice.Service,
lyfthookroute.Register(prefixGroup.Group("/lyfthook"), cfg, svc, tnc, notification) lyfthookroute.Register(prefixGroup.Group("/lyfthook"), cfg, svc, tnc, notification)
externalroute.Register(prefixGroup.Group("/ext"), cfg, svc, tnc, notification) externalroute.Register(prefixGroup.Group("/ext"), cfg, svc, tnc, notification)
authenticateroute.Register(prefixGroup.Group("/authenticate"), cfg, svc) authenticateroute.Register(prefixGroup.Group("/authenticate"), cfg, svc)
selfregisterroute.Register(prefixGroup.Group("/selfregister"), cfg, svc)
appGroup := prefixGroup.Group("/" + cfg.App.Name) appGroup := prefixGroup.Group("/" + cfg.App.Name)
usersroute.Register(appGroup.Group("/users"), cfg, svc) usersroute.Register(appGroup.Group("/users"), cfg, svc)
eligibilityroute.Register(appGroup.Group("/eligibility"), cfg, svc) eligibilityroute.Register(appGroup.Group("/eligibility"), cfg, svc)
tncroute.Register(appGroup.Group("/rides"), cfg, svc, tnc, notification) tncroute.Register(appGroup.Group("/rides"), cfg, svc, tnc, notification)
visitroute.Register(appGroup.Group("/visits"), cfg, svc) visitroute.Register(appGroup.Group("/visits"), cfg, svc, tnc)
providerroute.Register(appGroup.Group("/provider"), cfg, svc) providerroute.Register(appGroup.Group("/provider"), cfg, svc)
placesroute.Register(appGroup.Group("/places"), cfg, svc) placesroute.Register(appGroup.Group("/places"), cfg, svc)
profileroute.Register(appGroup.Group("/profile"), cfg, svc) profileroute.Register(appGroup.Group("/profile"), cfg, svc)
organizationroute.Register(appGroup.Group("/organization"), cfg, svc) organizationroute.Register(appGroup.Group("/organization"), cfg, svc)
} }

View File

@@ -33,6 +33,18 @@ func ResponseAPIOK(c echo.Context, data interface{}) error {
return c.JSON(http.StatusOK, data) return c.JSON(http.StatusOK, data)
} }
// ResponseAPIErrorWithData returns a standard API error with additional data to the response
func ResponseAPIErrorWithData(c echo.Context, status int, message string, redirect bool, data interface{}) error {
returnValue := resultWrapper{
Error: true,
Message: message,
Redirect: redirect,
Data: data,
}
return c.JSON(status, returnValue)
}
// ResponseAPIError returns a standard API error to the response // ResponseAPIError returns a standard API error to the response
func ResponseAPIError(c echo.Context, status int, message string, redirect bool) error { func ResponseAPIError(c echo.Context, status int, message string, redirect bool) error {
returnValue := resultWrapper{ returnValue := resultWrapper{
@@ -49,6 +61,11 @@ func ResponseAPIAuthError(c echo.Context, message string, redirect bool) error {
return ResponseAPIError(c, http.StatusUnauthorized, message, redirect) return ResponseAPIError(c, http.StatusUnauthorized, message, redirect)
} }
// ResponseAPIAuthorizationError returns a standard API auth error to the response
func ResponseAPIAuthorizationError(c echo.Context) error {
return ResponseAPIError(c, http.StatusForbidden, "Forbidden by controller", false)
}
// ResponseAPIServiceError returns a standard API service unavailable error to the response // ResponseAPIServiceError returns a standard API service unavailable error to the response
func ResponseAPIServiceError(c echo.Context, message string) error { func ResponseAPIServiceError(c echo.Context, message string) error {
return ResponseAPIError(c, http.StatusServiceUnavailable, message, false) return ResponseAPIError(c, http.StatusServiceUnavailable, message, false)
@@ -59,6 +76,11 @@ func ResponseAPIValidationError(c echo.Context, message string) error {
return ResponseAPIError(c, http.StatusUnprocessableEntity, message, false) return ResponseAPIError(c, http.StatusUnprocessableEntity, message, false)
} }
// ResponseAPICustomValidationError returns a standard API validation error with custom data to the response
func ResponseAPICustomValidationError(c echo.Context, message string, data interface{}) error {
return ResponseAPIErrorWithData(c, http.StatusUnprocessableEntity, message, false, data)
}
// ResponseAPIFieldValidationError returns a standard API field validation error to the response // ResponseAPIFieldValidationError returns a standard API field validation error to the response
func ResponseAPIFieldValidationError(c echo.Context, field string, message string) error { func ResponseAPIFieldValidationError(c echo.Context, field string, message string) error {
err := errors.NewValidationError(field, message) err := errors.NewValidationError(field, message)
@@ -70,6 +92,16 @@ func ResponseAPINotFoundError(c echo.Context) error {
return ResponseAPIError(c, http.StatusNotFound, "Not Found", false) return ResponseAPIError(c, http.StatusNotFound, "Not Found", false)
} }
//ResponseAPINotEligibleError returns a standard API not eligible to the response
func ResponseAPINotEligibleError(c echo.Context) error {
return ResponseAPIError(c, http.StatusForbidden, "Member does not have active insurance coverage", false)
}
//ResponseAPINotEligibleWithMessageError returns a standard API not eligible to the response with custom message
func ResponseAPINotEligibleWithMessageError(c echo.Context, message string) error {
return ResponseAPIError(c, http.StatusForbidden, message, false)
}
func ignoreDefaultWrappedErrors(c echo.Context, errorToHandle *errors.WrappedError, handler func(echo.Context, error) error) error { func ignoreDefaultWrappedErrors(c echo.Context, errorToHandle *errors.WrappedError, handler func(echo.Context, error) error) error {
err := errorToHandle.GetOriginalError() err := errorToHandle.GetOriginalError()

View File

@@ -0,0 +1,151 @@
package selfregisterroute
import (
"fmt"
"sync"
b64 "encoding/base64"
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
"bitbucket.org/nemt/nemt-portal-api/application/third/eligibility/bcbsi"
"bitbucket.org/nemt/nemt-portal-api/application/third/npd/npdmodel"
"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"
"bitbucket.org/nemt/nemt-portal-api/server/validation"
"github.com/labstack/echo"
)
const (
notificationEmailSubject = "Registration sucessful"
notificationEmailBody = "You have registered as a Visit Reporter for CHM NEMT.\nLogin: https://portal.bcbsinstitute.com\nReset PW: https://portal.bcbsinstitute.com/forgot"
notificationSmsBody = "You have registered as a Visit Reporter for CHM NEMT. Login: https://portal.bcbsinstitute.com Reset PW: https://portal.bcbsinstitute.com/forgot"
)
var (
instance *controller
once sync.Once
)
type controller struct {
svc *applicationservice.Service
cfg *config.Config
bcbsi *bcbsi.Service
}
func controllerInstance(svc *applicationservice.Service, cfg *config.Config) *controller {
once.Do(func() {
instance = &controller{
svc: svc,
cfg: cfg,
bcbsi: bcbsi.New(cfg),
}
})
return instance
}
func (c *controller) handle(ctx echo.Context) error {
var user viewmodel.User
if err := ctx.Bind(&user); err != nil {
return routeutils.HandleAPIError(ctx, err)
}
authUser, err := c.svc.Users.GetByUUID("573c70ff-733d-11e7-ba8f-0a6ad3fcdeaa", "")
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
pass, err := b64.StdEncoding.DecodeString(user.Pass)
if err != nil {
return routeutils.ResponseAPIValidationError(ctx, "Invalid password")
}
user.Pass = string(pass)
if validationErrors := validation.ValidateSelfregistration(&user); len(validationErrors) > 0 {
return routeutils.ResponseAPICustomValidationError(ctx, "Self registration failed", validationErrors)
}
if len(user.First) != 0 && len(user.Last) != 0 {
user.Name = fmt.Sprintf("%s %s", user.First, user.Last)
}
provider, err := c.svc.Provider.GetByNPI(user.Provider.InternalID, authUser)
if err != nil {
fmt.Println("Error to create organization", err)
return routeutils.HandleAPIError(ctx, err)
}
var organization viewmodel.Organization
if provider.ProviderUUID == "" {
org := viewmodel.Organization{
Author: authUser,
LastEditor: authUser,
Name: user.Provider.OrganizatioName,
Type: viewmodel.OrganizationType{
Key: "provider",
Name: "Provider",
},
Reference: npdmodel.ProviderResponse{
OrgName: user.Provider.OrganizatioName,
FivePartKeyGroups: []npdmodel.PartKeyGroup{
npdmodel.PartKeyGroup{
ProviderNum: user.Provider.InternalID,
},
},
},
}
organization, err = c.svc.Organization.AddOrganization(org, authUser)
if err != nil {
fmt.Println("Error to create organization", err)
return routeutils.HandleAPIError(ctx, err)
}
if organization.UUID == "" {
return routeutils.ResponseAPIValidationError(ctx, "Error to create organization")
}
} else {
organization = provider.Organization
}
user.Organizations = []viewmodel.Organization{organization}
user.Profiles = []viewmodel.Profile{viewmodel.Profile{
Name: "Visit Reporter",
Key: "VIRPT",
Organization: organization,
}}
user, err = c.svc.Users.Create(user, authUser)
if err != nil {
fmt.Println("Error to create user", err)
return routeutils.HandleAPIError(ctx, err)
}
//Send email notification to Authorized user
notification := viewmodel.Notification{
Type: applicationservice.NotificationTypeEmail,
From: c.cfg.Email.Sender,
To: *user.Email,
Subject: notificationEmailSubject,
Message: notificationEmailBody,
}
notification, err = c.svc.Notification.SendNotificationWithoutWritingToDatabase(notification)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
//Send sms notification to Authorized user
notification = viewmodel.Notification{
Type: applicationservice.NOtificationTypeSMS,
To: *user.PhoneNumber,
Message: notificationSmsBody,
}
notification, err = c.svc.Notification.SendNotificationWithoutWritingToDatabase(notification)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
return routeutils.ResponseAPIOK(ctx, user)
}

View File

@@ -0,0 +1,18 @@
package selfregisterroute
import (
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"github.com/labstack/echo"
)
const (
rootRoute = "/"
)
// Register registers the routes in the echo group
func Register(r *echo.Group, cfg *config.Config, svc *applicationservice.Service) {
ctrl := controllerInstance(svc, cfg)
r.POST(rootRoute, ctrl.handle)
}

View File

@@ -15,6 +15,7 @@ import (
"bitbucket.org/nemt/nemt-portal-api/infra/auth" "bitbucket.org/nemt/nemt-portal-api/infra/auth"
"bitbucket.org/nemt/nemt-portal-api/infra/config" "bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils" "bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
"bitbucket.org/nemt/nemt-portal-api/server/validation"
"github.com/labstack/echo" "github.com/labstack/echo"
uuid "github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
"google.golang.org/api/googleapi/transport" "google.golang.org/api/googleapi/transport"
@@ -227,8 +228,10 @@ func (c *controller) handle(ctx echo.Context) error {
if err != nil { if err != nil {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
if user.ID == "" {
return routeutils.ResponseAPIValidationError(ctx, "User not found") //Validate ride request
if validationErrors := validation.ValidateRide(&requestRide, &user); len(validationErrors) > 0 {
return routeutils.ResponseAPICustomValidationError(ctx, "ride validation failed", validationErrors)
} }
createdUser, err := auth.GetUserDetail(ctx, c.cfg) createdUser, err := auth.GetUserDetail(ctx, c.cfg)
@@ -236,6 +239,42 @@ func (c *controller) handle(ctx echo.Context) error {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
var provider viewmodel.ProviderResp
provider, err = c.svc.Provider.GetByNPI(requestRide.RawProvider.FivePartKeyGroups[0].ProviderNum, createdUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
fmt.Println("Provider Found: ", provider.ProviderUUID)
if provider.ProviderUUID == "" {
org := viewmodel.Organization{
Type: viewmodel.OrganizationType{
Key: "provider",
Name: "Provider",
},
Name: requestRide.RawProvider.OrgName,
Description: requestRide.RawProvider.OrgName,
Main: false,
Author: createdUser,
LastEditor: createdUser,
Reference: requestRide.RawProvider,
}
org, err = c.svc.Organization.AddOrganization(org, createdUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
fmt.Println("Organization Created: ", org.UUID)
provider, err = c.svc.Provider.GetByOrganization(org.UUID, createdUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
fmt.Println("Provider Found: ", provider.ProviderUUID)
}
requestRide.Provider = provider
requestRide.Destination.ID = provider.MukID
name := user.Name name := user.Name
names := strings.Split(name, " ") names := strings.Split(name, " ")
requestRide.Passenger.FirstName = names[0] requestRide.Passenger.FirstName = names[0]
@@ -301,14 +340,14 @@ func (c *controller) handle(ctx echo.Context) error {
if requestRide.TripType.Key == "from_visit" { if requestRide.TripType.Key == "from_visit" {
resp.Origin.Name = requestRide.Destination.Name resp.Origin.Name = requestRide.Destination.Name
resp.Origin.ID = requestRide.Destination.ID resp.Origin.ID = requestRide.Provider.MukID
resp.Destination.Name = requestRide.Origin.Name resp.Destination.Name = requestRide.Origin.Name
resp.Destination.ID = requestRide.Origin.ID resp.Destination.ID = requestRide.Origin.ID
} else { } else {
resp.Origin.Name = requestRide.Origin.Name resp.Origin.Name = requestRide.Origin.Name
resp.Origin.ID = requestRide.Origin.ID resp.Origin.ID = requestRide.Origin.ID
resp.Destination.Name = requestRide.Destination.Name resp.Destination.Name = requestRide.Destination.Name
resp.Destination.ID = requestRide.Destination.ID resp.Destination.ID = requestRide.Provider.MukID
} }
resp.Distance = requestRide.Distance resp.Distance = requestRide.Distance
@@ -335,6 +374,7 @@ func (c *controller) handle(ctx echo.Context) error {
entity, err := c.svc.Rides.Save(resp) entity, err := c.svc.Rides.Save(resp)
if err != nil { if err != nil {
fmt.Println("Error to save rides: ", err.Error())
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
@@ -433,7 +473,7 @@ func (c *controller) handle(ctx echo.Context) error {
go func() { go func() {
err = c.svc.Notification.SendNotification(newRide.Status, roudtripRide, newRide) err = c.svc.Notification.SendNotification(newRide.Status, roudtripRide, newRide)
if err != nil { if err != nil {
fmt.Println("Error to notify user: ", err.Error()) fmt.Println("Error notifying user: ", err.Error())
} }
}() }()
} }

View File

@@ -1,20 +1,33 @@
package usersroute package usersroute
import ( import (
"bytes"
b64 "encoding/base64" b64 "encoding/base64"
"encoding/json"
"fmt" "fmt"
"math/rand" "math/rand"
"net/http"
"strings"
"sync" "sync"
"time" "time"
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice" "bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
"bitbucket.org/nemt/nemt-portal-api/application/third/eligibility/bcbsi"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel" "bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain" "bitbucket.org/nemt/nemt-portal-api/domain"
"bitbucket.org/nemt/nemt-portal-api/infra/auth" "bitbucket.org/nemt/nemt-portal-api/infra/auth"
"bitbucket.org/nemt/nemt-portal-api/infra/cache" "bitbucket.org/nemt/nemt-portal-api/infra/cache"
"bitbucket.org/nemt/nemt-portal-api/infra/config" "bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/server/authorization"
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils" "bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
"bitbucket.org/nemt/nemt-portal-api/server/validation"
"github.com/labstack/echo" "github.com/labstack/echo"
"golang.org/x/net/context"
"googlemaps.github.io/maps"
)
const (
zipcodeTrimLength = 5
) )
var ( var (
@@ -23,15 +36,17 @@ var (
) )
type controller struct { type controller struct {
svc *applicationservice.Service svc *applicationservice.Service
cfg *config.Config cfg *config.Config
bcbsi *bcbsi.Service
} }
func controllerInstance(svc *applicationservice.Service, cfg *config.Config) *controller { func controllerInstance(svc *applicationservice.Service, cfg *config.Config) *controller {
once.Do(func() { once.Do(func() {
instance = &controller{ instance = &controller{
svc: svc, svc: svc,
cfg: cfg, cfg: cfg,
bcbsi: bcbsi.New(cfg),
} }
}) })
return instance return instance
@@ -127,6 +142,62 @@ func (c *controller) handleRemoveAddress(ctx echo.Context) error {
return routeutils.ResponseNoContent(ctx, addressID) return routeutils.ResponseNoContent(ctx, addressID)
} }
func (c *controller) handlePortalContact(ctx echo.Context) error {
userID, err := routeutils.GetAndValidateStringParam(ctx, "user_uuid", "mandatory field")
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
item, err := c.svc.Users.GetByUUID(userID, "")
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
createdUser, err := auth.GetUserDetail(ctx, c.cfg)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if item.ID == "" {
return routeutils.ResponseAPIValidationError(ctx, "User not found")
} else {
var Contact viewmodel.Contact
if err := ctx.Bind(&Contact); err != nil {
return routeutils.HandleAPIError(ctx, err)
}
Contact.User = item
Contact.Author = createdUser
Contact, err = c.svc.Users.SaveContact(Contact)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
// Contact.User, err = c.svc.Users.GetByUUID(userID, "")
// if err != nil {
// return routeutils.HandleAPIError(ctx, err)
// }
return routeutils.ResponseAPIOK(ctx, Contact)
}
}
func (c *controller) handleRemoveContact(ctx echo.Context) error {
contactUUID, err := routeutils.GetAndValidateStringParam(ctx, "contact_uuid", "mandatory field")
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
contact := viewmodel.Contact{
ID: contactUUID,
}
contact, err = c.svc.Users.RemoveContact(contact)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
return routeutils.ResponseNoContent(ctx, contact)
}
func (c *controller) handleMemberAddress(ctx echo.Context) error { func (c *controller) handleMemberAddress(ctx echo.Context) error {
userID, err := routeutils.GetAndValidateStringParam(ctx, "user_uuid", "mandatory field") userID, err := routeutils.GetAndValidateStringParam(ctx, "user_uuid", "mandatory field")
if err != nil { if err != nil {
@@ -274,6 +345,11 @@ func (c *controller) handleMember(ctx echo.Context) error {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
//Validate member
if validationErrors := validation.ValidateEligibility(&user); len(validationErrors) > 0 {
return routeutils.ResponseAPICustomValidationError(ctx, "eligibility validation failed", validationErrors)
}
authUser, err := auth.GetUserDetail(ctx, c.cfg) authUser, err := auth.GetUserDetail(ctx, c.cfg)
if err != nil { if err != nil {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
@@ -319,6 +395,112 @@ func (c *controller) handleMember(ctx echo.Context) error {
} }
user.Profiles = append(user.Profiles, profile) user.Profiles = append(user.Profiles, profile)
eligibility := viewmodel.Eligibility{}
eligibility.Provider.ProviderNPI = "1699849786"
eligibility.Provider.ProviderName = "LITHOLINK CORPORATION"
eligibility.TrackingID = user.ID
eligibility.Subscriber.SubscriberID = *user.Member
eligibility.Subscriber.PatientType = "S"
eligibility.Subscriber.Name.First = user.First
eligibility.Subscriber.Name.Last = user.Last
eligibility.Subscriber.DemographicInfo.DateOfBirth = *user.BirthDate
eligibility.Subscriber.DemographicInfo.Gender = *user.Gender
eligibility.ServiceInfo.DateOfService = time.Now()
eligibility.ServiceInfo.ServiceTypeCodes = []string{"30"}
/*
resp, err := c.bcbsi.BXE.Get271(eligibility)
if err != nil {
fmt.Println("Eligibility Not Found or Error: ", err.Error())
return routeutils.ResponseAPINotEligibleError(ctx)
}
*/
//This part is emulating eligibility check for testing purposes
client := &http.Client{}
eligibilityJson, err := json.Marshal(eligibility)
if err != nil {
return routeutils.ResponseAPINotEligibleError(ctx)
}
req, _ := http.NewRequest("POST", c.cfg.Eligibility.Url, bytes.NewBuffer(eligibilityJson))
req.Header.Add("App", c.cfg.HTTP.Auth.AppKey)
req.Header.Add("Token", ctx.Request().Header.Get("Token"))
req.Header.Add("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
return routeutils.ResponseAPINotEligibleError(ctx)
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode > 300 {
return routeutils.ResponseAPINotEligibleError(ctx)
}
eligibilityResponse := viewmodel.Interchange271{}
decoder := json.NewDecoder(resp.Body)
err = decoder.Decode(&eligibilityResponse)
if err != nil {
return routeutils.ResponseAPINotEligibleError(ctx)
}
//================================================================
if len(eligibilityResponse.Division.HealthCareEligibilityResponse.LoopHL0030) < 1 {
return routeutils.ResponseAPINotEligibleError(ctx)
}
address := viewmodel.Address{}
//header := resp.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N3_0950
//body := resp.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N4_0960
header := eligibilityResponse.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N3_0950
body := eligibilityResponse.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N4_0960
address.AddressTypeName = "Home"
address.AddressType = "home"
address.Name = fmt.Sprintf("%s, %s", header.N301, body.N401)
address.Address = fmt.Sprintf("%s, %s", header.N301, body.N401)
address.CreatedUserUUID = authUser.ID
address.User = user
cleanZipcode := strings.TrimSpace(body.N403)
trimmedZipcode := cleanZipcode
if len(cleanZipcode) > zipcodeTrimLength {
trimmedZipcode = cleanZipcode[:zipcodeTrimLength]
}
_, err = c.svc.Zipcodes.GetByParticipatingZipcode(trimmedZipcode)
if err != nil {
return routeutils.ResponseAPINotEligibleWithMessageError(ctx, "Member's Home zipcode, "+trimmedZipcode+", is not currently eligible for participation in this program")
}
googleMapsAPI, err := maps.NewClient(maps.WithClientIDAndSignature("gme-bluecrossandblue1", "msqgD-jdqCyR0M_1u5C1HION5iI="))
if err != nil {
fmt.Println("Error to instantiate googles api: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
r := &maps.GeocodingRequest{
Address: address.Address + " " + body.N402 + ", " + body.N403,
}
result, err := googleMapsAPI.Geocode(context.Background(), r)
if err != nil {
fmt.Println("Error to instantiate googles api: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
if len(result) > 0 {
address.Latitude = result[0].Geometry.Location.Lat
address.Longitude = result[0].Geometry.Location.Lng
_, err := c.svc.Users.SaveAddress(address)
if err != nil {
fmt.Println("Error to save address: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
}
user, err = c.svc.Users.Create(user, authUser) user, err = c.svc.Users.Create(user, authUser)
if err != nil { if err != nil {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
@@ -389,6 +571,10 @@ func (c *controller) handlePortal(ctx echo.Context) error {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
if !authorization.CanCreateUser(authUser, user) {
return routeutils.ResponseAPIAuthorizationError(ctx)
}
if len(user.Profiles) == 0 { if len(user.Profiles) == 0 {
return routeutils.ResponseAPIAuthError(ctx, "profile is required", false) return routeutils.ResponseAPIAuthError(ctx, "profile is required", false)
} }
@@ -411,6 +597,10 @@ func (c *controller) handlePortal(ctx echo.Context) error {
} }
user.Pass = string(pass) user.Pass = string(pass)
if passwordValidationErrors := validation.ValidatePassword(&user); len(passwordValidationErrors) > 0 {
return routeutils.ResponseAPICustomValidationError(ctx, "Password not strong enough", passwordValidationErrors)
}
if len(user.Name) == 0 && len(user.First) == 0 && len(user.Last) == 0 { if len(user.Name) == 0 && len(user.First) == 0 && len(user.Last) == 0 {
return routeutils.ResponseAPIAuthError(ctx, "name is required", false) return routeutils.ResponseAPIAuthError(ctx, "name is required", false)
} }

View File

@@ -17,6 +17,8 @@ const (
userDetailRoute = "/portal/:user_uuid" userDetailRoute = "/portal/:user_uuid"
userAddressRoute = "/portal/:user_uuid/address" userAddressRoute = "/portal/:user_uuid/address"
userRemoveAddressRoute = "/portal/:user_uuid/address/:address_uuid" userRemoveAddressRoute = "/portal/:user_uuid/address/:address_uuid"
userContactRoute = "/portal/:user_uuid/contact"
userRemoveContactRoute = "/portal/:user_uuid/contact/:contact_uuid"
portalRoute = "/portal" portalRoute = "/portal"
portalBulkRoute = "/portal/bulk" portalBulkRoute = "/portal/bulk"
contacttypeRoute = "/contacttype" contacttypeRoute = "/contacttype"
@@ -41,6 +43,9 @@ func Register(r *echo.Group, cfg *config.Config, svc *applicationservice.Service
r.POST(userAddressRoute, ctrl.handlePortalAddress) r.POST(userAddressRoute, ctrl.handlePortalAddress)
r.PUT(userRemoveAddressRoute, ctrl.handleRemoveAddress) r.PUT(userRemoveAddressRoute, ctrl.handleRemoveAddress)
r.POST(userContactRoute, ctrl.handlePortalContact)
r.PUT(userRemoveContactRoute, ctrl.handleRemoveContact)
//Can be cached //Can be cached
r.GET(contacttypeRoute, ctrl.handleContactType) r.GET(contacttypeRoute, ctrl.handleContactType)

View File

@@ -1,13 +1,26 @@
package visitroute package visitroute
import ( import (
"context"
"fmt"
"math/rand"
"strings"
"sync" "sync"
"time"
b64 "encoding/base64"
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice" "bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
"bitbucket.org/nemt/nemt-portal-api/application/third/eligibility/bcbsi"
"bitbucket.org/nemt/nemt-portal-api/application/tncservice"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/infra/auth" "bitbucket.org/nemt/nemt-portal-api/infra/auth"
"bitbucket.org/nemt/nemt-portal-api/infra/config" "bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils" "bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
"bitbucket.org/nemt/nemt-portal-api/server/validation"
"github.com/labstack/echo" "github.com/labstack/echo"
uuid "github.com/satori/go.uuid"
"googlemaps.github.io/maps"
) )
var ( var (
@@ -16,33 +29,628 @@ var (
) )
type controller struct { type controller struct {
svc *applicationservice.Service svc *applicationservice.Service
cfg *config.Config cfg *config.Config
bcbsi *bcbsi.Service
tnc *tncservice.Service
} }
func controllerInstance(svc *applicationservice.Service, cfg *config.Config) *controller { func controllerInstance(svc *applicationservice.Service, cfg *config.Config, tnc *tncservice.Service) *controller {
once.Do(func() { once.Do(func() {
instance = &controller{ instance = &controller{
svc: svc, svc: svc,
cfg: cfg, cfg: cfg,
bcbsi: bcbsi.New(cfg),
tnc: tnc,
} }
}) })
return instance return instance
} }
func (c *controller) generatePassword(n int) string {
const (
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
)
return c.stringWithCharset(n, charset)
}
func (c *controller) stringWithCharset(length int, charset string) string {
b := make([]byte, length)
var seededRand *rand.Rand = rand.New(
rand.NewSource(time.Now().UnixNano()))
for i := range b {
b[i] = charset[seededRand.Intn(len(charset))]
}
return string(b)
}
func (c *controller) handleRide(ctx echo.Context) error {
var ride viewmodel.RideRequest
if err := ctx.Bind(&ride); err != nil {
fmt.Println(err)
return routeutils.ResponseAPIValidationError(ctx, "invalid parameters")
}
authUser, err := auth.GetUserDetail(ctx, c.cfg)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
visit, err := c.svc.Visits.GetByUUID(ride.Visit.UUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
ride.Visit = visit
user, err := c.svc.Users.GetByMemberID(*visit.User.Member)
if err != nil {
fmt.Println(err)
return routeutils.HandleAPIError(ctx, err)
}
user.PhoneNumber = ride.User.PhoneNumber
user.Email = ride.User.Email
ride.Visit.User = user
if ride.Visit.User.Type == nil {
subscriber := "S"
ride.Visit.User.Type = &subscriber
}
var provider viewmodel.ProviderResp
provider, err = c.svc.Provider.GetByUUID(ride.Visit.Provider.ProviderUUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
visit.Provider = provider
eligibility := viewmodel.Eligibility{}
eligibility.Provider.ProviderNPI = provider.InternalID
eligibility.Provider.ProviderName = provider.OrganizatioName
eligibility.TrackingID = c.rangeIn(1000000, 9999999)
eligibility.Subscriber.SubscriberID = *ride.Visit.User.Member
eligibility.Subscriber.PatientType = *ride.Visit.User.Type
eligibility.Subscriber.Name.First = ride.Visit.User.First
eligibility.Subscriber.Name.Last = ride.Visit.User.Last
eligibility.Subscriber.DemographicInfo.DateOfBirth = *ride.Visit.User.BirthDate
eligibility.Subscriber.DemographicInfo.Gender = *ride.Visit.User.Gender
loc, _ := time.LoadLocation("America/Chicago")
eligibility.ServiceInfo.DateOfService = time.Now().In(loc)
eligibility.ServiceInfo.ServiceTypeCodes = []string{"30"}
resp271, err := c.bcbsi.BXE.Get271(eligibility)
if err != nil {
fmt.Println(err)
return routeutils.ResponseAPIValidationError(ctx, err.Error())
}
address := viewmodel.Address{}
header := resp271.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N3_0950
body := resp271.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N4_0960
zipCode := strings.TrimSpace(body.N403)
address.AddressTypeName = "Home"
address.AddressType = "home"
address.Name = fmt.Sprintf("%s, %s", header.N301, body.N401)
address.Address = fmt.Sprintf("%s, %s (%s)", header.N301, body.N401, zipCode)
address.CreatedUserUUID = authUser.ID
address.User = user
address.Type = "provider"
googleMapsAPI, err := maps.NewClient(maps.WithClientIDAndSignature("gme-bluecrossandblue1", "msqgD-jdqCyR0M_1u5C1HION5iI="))
if err != nil {
fmt.Println("Error to instantiate googles api: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
r := &maps.GeocodingRequest{
Address: address.Address + " " + body.N402 + ", " + zipCode,
}
result, err := googleMapsAPI.Geocode(context.Background(), r)
if err != nil {
fmt.Println("Error to instantiate googles api: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
if len(result) > 0 {
address.Latitude = result[0].Geometry.Location.Lat
address.Longitude = result[0].Geometry.Location.Lng
}
if address.Latitude != 0 && address.Longitude != 0 {
if len(user.Addresses) > 0 {
for _, a := range user.Addresses {
if a.AddressType == "home" {
err := c.svc.Users.RemoveAddress(a.UUID)
if err != nil {
fmt.Println("Error to remove old address: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
}
}
}
address, err = c.svc.Users.SaveAddress(address)
if err != nil {
fmt.Println("Error to save address: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
user.Addresses = append(user.Addresses, address)
}
homeAddress := viewmodel.Address{}
for _, a := range visit.User.Addresses {
if a.AddressType == "home" {
homeAddress = a
}
}
ride.CreateUserUUID = authUser.ID
ride.Destination = viewmodel.Location{
ID: visit.Provider.ProviderUUID,
Name: visit.Provider.OrganizatioName,
Latitude: visit.Provider.Address.Latitude,
Longitude: visit.Provider.Address.Longitude,
Address: visit.Provider.Address.StreetAddress1,
}
if len(ride.Origin.ID) == 0 {
ride.Origin = viewmodel.Location{
ID: homeAddress.UUID,
Name: homeAddress.AddressTypeName,
Latitude: homeAddress.Latitude,
Longitude: homeAddress.Longitude,
Address: homeAddress.Address,
}
}
ride.Notes = ride.Notes
ride.Passenger.FirstName = visit.User.First
ride.Passenger.LastName = " "
ride.Passenger.PhoneNumber = *visit.User.PhoneNumber
ride.RideType = "lyft"
ride.VisitDate = &visit.VisitDatetime
ride.VisitTime = &visit.VisitDatetime
ride.UserConsent = true
if validationErrors := validation.ValidateVisitRide(&ride, &user); len(validationErrors) > 0 {
return routeutils.ResponseAPICustomValidationError(ctx, "ride validation failed", validationErrors)
}
var resp viewmodel.RideRequest
if ride.TripType.Key != "from_visit_call" {
if ride.TripType.Key == "from_visit" {
newOrigin := ride.Origin
ride.Origin = ride.Destination
ride.Destination = newOrigin
}
if c.cfg.LyftProd.UserUUID != authUser.ID {
resp, err = c.tnc.Lyft.RequestRide(ride)
} else {
fmt.Println("In Production")
resp, err = c.tnc.LyftProd.RequestRide(ride)
}
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if ride.TripType.Key == "from_visit" {
newOrigin := resp.Origin
resp.Origin = resp.Destination
resp.Destination = newOrigin
}
resp.RideID = strings.Replace(resp.RideID, "s_", "", -1)
} else {
resp = ride
UUID, _ := uuid.NewV4()
resp.RideID = UUID.String()
}
if resp.Status == "scheduled" || ride.TripType.Key == "from_visit_call" {
if ride.PickupTime == nil {
currentDate := time.Now()
ride.PickupTime = &currentDate
}
requestMS := (ride.PickupTime.UnixNano() / int64(time.Millisecond))
generateDate := time.Now()
generateMS := (generateDate.UnixNano() / int64(time.Millisecond))
resp.RequestAt = ride.PickupTime
resp.RequestAtMS = &requestMS
resp.GeneratedAt = &generateDate
resp.GeneratedAtMS = &generateMS
}
resp.Passenger.FirstName = visit.User.First
resp.Passenger.LastName = visit.User.Last
resp.Passenger.PhoneNumber = *visit.User.PhoneNumber
if resp.Passenger.ImageURL == nil {
imageURL := " "
resp.Passenger.ImageURL = &imageURL
}
resp.UserUUID = visit.User.ID
if ride.TripType.Key == "from_visit" {
resp.Origin.Name = ride.Destination.Name
resp.Origin.ID = ride.Destination.ID
resp.Destination.Name = ride.Origin.Name
resp.Destination.ID = ride.Origin.ID
} else {
resp.Origin.Name = ride.Origin.Name
resp.Origin.ID = ride.Origin.ID
resp.Destination.Name = ride.Destination.Name
resp.Destination.ID = ride.Destination.ID
}
resp.Distance = ride.Distance
resp.Duration = ride.Duration
resp.ETA = ride.ETA
resp.PickupTime = ride.PickupTime
resp.VisitDate = &ride.Visit.VisitDatetime
resp.VisitTime = &ride.Visit.VisitDatetime
resp.VisitExternalID = ride.Visit.ExternalID
resp.CreateUserUUID = authUser.ID
resp.Visit.TripType = ride.Visit.TripType
resp.Visit = visit
if resp.TripType.Key == "from_visit_call" {
resp.Status = "willCall"
resp.Passenger.UserID = &resp.UserUUID
}
resp.TripType.Key = ride.TripType.Key
if ride.TripType.Key == "roundtrip" || ride.TripType.Key == "roundtrip_call" {
resp.TripType.Key = "to_visit"
} else if ride.TripType.Key == "from_visit_call" {
resp.TripType.Key = "from_visit_call"
}
entity, err := c.svc.Rides.Save(resp)
if err != nil {
fmt.Println("Error to save first ride: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
go func() {
err = c.svc.Notification.SendNotification(resp.Status, entity, resp)
if err != nil {
fmt.Println("Error to notify user: ", err.Error())
}
}()
if ride.TripType.Key == "roundtrip" || ride.TripType.Key == "roundtrip_call" {
newRide := ride
if ride.TripType.Key == "roundtrip" {
destination := newRide.Origin
newRide.Origin = newRide.Destination
newRide.Destination = destination
if ride.ReturnTime != nil {
newRide.PickupTime = ride.ReturnTime
}
scheduledRide := make(map[string]interface{})
scheduledRide["timestamp_ms"] = ride.PickupTime.Unix()
newRide.ScheduledPickupRange = scheduledRide
newRide.Passenger.FirstName = visit.User.First
newRide.Passenger.LastName = " "
newRide.Passenger.PhoneNumber = *visit.User.PhoneNumber
if c.cfg.LyftProd.UserUUID != authUser.ID {
newRide, err = c.tnc.Lyft.RequestRide(newRide)
} else {
fmt.Println("In Production")
newRide, err = c.tnc.LyftProd.RequestRide(newRide)
}
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
destination = newRide.Origin
newRide.Origin = newRide.Destination
newRide.Destination = destination
if newRide.Error != "" {
fmt.Println("Error to schedule a ride on lyft: ", newRide.Error, newRide.ErrorDescription)
} else {
fmt.Println("Ride Scheduled: ", newRide.Status)
}
newRide.TripType.Key = "from_visit"
} else {
newRide.TripType.Key = "from_visit_call"
newRide.Status = "willCall"
newRide.RideID = entity.UUID
}
newRide.Visit = visit
newRide.PickupTime = ride.ReturnTime
requestMS := (newRide.PickupTime.UnixNano() / int64(time.Millisecond))
generateDate := time.Now()
generateMS := (generateDate.UnixNano() / int64(time.Millisecond))
newRide.RequestAt = newRide.PickupTime
newRide.RequestAtMS = &requestMS
newRide.GeneratedAt = &generateDate
newRide.GeneratedAtMS = &generateMS
newRide.Passenger.FirstName = visit.User.First
newRide.Passenger.LastName = visit.User.Last
newRide.Passenger.PhoneNumber = *visit.User.PhoneNumber
newRide.Passenger.UserID = &ride.UserUUID
if newRide.Passenger.ImageURL == nil {
imageURL := " "
newRide.Passenger.ImageURL = &imageURL
}
newRide.UserUUID = ride.UserUUID
newRide.Origin.Name = ride.Destination.Name
newRide.Origin.ID = ride.Destination.ID
newRide.Destination.Name = ride.Origin.Name
newRide.Destination.ID = ride.Origin.ID
newRide.Distance = ride.Distance
newRide.Duration = ride.Duration
newRide.ETA = ride.ETA
newRide.VisitDate = ride.VisitDate
newRide.VisitTime = ride.VisitTime
newRide.VisitExternalID = ride.VisitExternalID
newRide.CreateUserUUID = authUser.ID
roudtripRide, err := c.svc.Rides.Save(newRide)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
go func() {
err = c.svc.Notification.SendNotification(newRide.Status, roudtripRide, newRide)
if err != nil {
fmt.Println("Error to notify user: ", err.Error())
}
}()
}
ctx.Response().Header().Set("Content-Type", "application/json")
return routeutils.ResponseAPIOK(ctx, entity)
}
func (c *controller) rangeIn(low, hi int) string {
result := low + rand.Intn(hi-low)
return fmt.Sprintf("%v", result)
}
func (c *controller) handle(ctx echo.Context) error {
var visit viewmodel.Visit
if err := ctx.Bind(&visit); err != nil {
fmt.Println(err)
return routeutils.ResponseAPIValidationError(ctx, "invalid parameters")
}
authUser, err := auth.GetUserDetail(ctx, c.cfg)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
var provider viewmodel.ProviderResp
provider, err = c.svc.Provider.GetByNPI(visit.RawProvider.FivePartKeyGroups[0].ProviderNum, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if provider.ProviderUUID == "" {
org := viewmodel.Organization{
Type: viewmodel.OrganizationType{
Key: "provider",
Name: "Provider",
},
Name: visit.RawProvider.OrgName,
Description: visit.RawProvider.OrgName,
Main: false,
Author: authUser,
LastEditor: authUser,
Reference: visit.RawProvider,
}
org, err = c.svc.Organization.AddOrganization(org, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
provider, err = c.svc.Provider.GetByOrganization(org.UUID, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
}
visit.Provider = provider
if validationErrors := validation.ValidateVisit(&visit, &authUser); len(validationErrors) > 0 {
return routeutils.ResponseAPICustomValidationError(ctx, "visit validation failed", validationErrors)
}
eligibility := viewmodel.Eligibility{}
eligibility.Provider.ProviderNPI = provider.InternalID
eligibility.Provider.ProviderName = provider.OrganizatioName
eligibility.TrackingID = c.rangeIn(1000000, 9999999)
eligibility.Subscriber.SubscriberID = *visit.User.Member
eligibility.Subscriber.PatientType = *visit.User.Type
eligibility.Subscriber.Name.First = visit.User.First
eligibility.Subscriber.Name.Last = visit.User.Last
eligibility.Subscriber.DemographicInfo.DateOfBirth = *visit.User.BirthDate
eligibility.Subscriber.DemographicInfo.Gender = *visit.User.Gender
loc, _ := time.LoadLocation("America/Chicago")
eligibility.ServiceInfo.DateOfService = time.Now().In(loc)
eligibility.ServiceInfo.ServiceTypeCodes = []string{"30"}
resp, err := c.bcbsi.BXE.Get271(eligibility)
if err != nil {
fmt.Println("Error to get eligibility: ", err.Error())
return routeutils.ResponseAPIValidationError(ctx, err.Error())
}
user, err := c.svc.Users.GetByMemberID(*visit.User.Member)
if err != nil {
fmt.Println("Error to get user by memberID: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
if user.ID == "" {
if len(user.Pass) == 0 {
user.Pass = c.generatePassword(8)
} else {
pass, err := b64.StdEncoding.DecodeString(user.Pass)
if err != nil {
return routeutils.ResponseAPIAuthError(ctx, "Invalid password", false)
}
user.Pass = string(pass)
}
if user.BirthDate == nil || user.BirthDate.IsZero() {
return routeutils.ResponseAPIAuthError(ctx, "birthdate is required", false)
}
if user.Member == nil || len(*user.Member) == 0 {
return routeutils.ResponseAPIAuthError(ctx, "member is required", false)
}
if user.Gender == nil || len(*user.Gender) == 0 || (*user.Gender != "M" && *user.Gender != "F" && *user.Gender != "U") {
return routeutils.ResponseAPIAuthError(ctx, "gender is required", false)
}
if len(user.Name) == 0 && len(user.First) == 0 && len(user.Last) == 0 {
return routeutils.ResponseAPIAuthError(ctx, "name is required", false)
}
if len(user.First) != 0 && len(user.Last) != 0 {
user.Name = fmt.Sprintf("%s %s", user.First, user.Last)
}
if user.PhoneNumber != nil && len(*user.PhoneNumber) == 10 && !strings.Contains(*user.PhoneNumber, "+1") {
phoneNumber := fmt.Sprintf("+1%s", *user.PhoneNumber)
user.PhoneNumber = &phoneNumber
}
profile, err := c.svc.Profile.GetByKey("US")
if err != nil {
fmt.Println("Error to get Profile: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
user.Profiles = append(user.Profiles, profile)
user, err = c.svc.Users.Create(user, authUser)
if err != nil {
fmt.Println("Error to create the user: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
} else {
if visit.User.Email != nil && len(*visit.User.Email) > 0 {
user.Email = visit.User.Email
}
if visit.User.PhoneNumber != nil {
if len(*visit.User.PhoneNumber) == 10 && !strings.Contains(*visit.User.PhoneNumber, "+1") {
phoneNumber := fmt.Sprintf("+1%s", *visit.User.PhoneNumber)
visit.User.PhoneNumber = &phoneNumber
}
user.PhoneNumber = visit.User.PhoneNumber
}
err = c.svc.Users.UpdateLogin(user)
if err != nil {
fmt.Println("Error to update login: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
}
address := viewmodel.Address{}
header := resp.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N3_0950
body := resp.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N4_0960
zipCode := strings.TrimSpace(body.N403)
address.AddressTypeName = "Home"
address.AddressType = "home"
address.Name = fmt.Sprintf("%s, %s", header.N301, body.N401)
address.Address = fmt.Sprintf("%s, %s (%s)", header.N301, body.N401, zipCode)
address.CreatedUserUUID = authUser.ID
address.User = user
address.Type = "provider"
googleMapsAPI, err := maps.NewClient(maps.WithClientIDAndSignature("gme-bluecrossandblue1", "msqgD-jdqCyR0M_1u5C1HION5iI="))
if err != nil {
fmt.Println("Error to instantiate googles api: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
r := &maps.GeocodingRequest{
Address: address.Address + " " + body.N402 + ", " + zipCode,
}
result, err := googleMapsAPI.Geocode(context.Background(), r)
if err != nil {
fmt.Println("Error to instantiate googles api: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
if len(result) > 0 {
address.Latitude = result[0].Geometry.Location.Lat
address.Longitude = result[0].Geometry.Location.Lng
}
if address.Latitude != 0 && address.Longitude != 0 {
if len(user.Addresses) > 0 {
for _, a := range user.Addresses {
if a.AddressType == "home" {
err := c.svc.Users.RemoveAddress(a.UUID)
if err != nil {
fmt.Println("Error to remove old address: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
}
}
}
address, err = c.svc.Users.SaveAddress(address)
if err != nil {
fmt.Println("Error saving address: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
user.Addresses = append(user.Addresses, address)
}
visit.TripType = viewmodel.TripType{
Key: "no_trip",
Value: "No Trip",
}
visit.User = user
visit.CreatedUser = authUser
visit, err = c.svc.Visits.Save(visit)
if err != nil {
fmt.Println("Error saving visit: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
return routeutils.ResponseAPIOK(ctx, visit)
}
func (c *controller) handleGetByID(ctx echo.Context) error { func (c *controller) handleGetByID(ctx echo.Context) error {
visit_uuid := ctx.Param("visit_uuid") visit_uuid := ctx.Param("visit_uuid")
if visit_uuid == "" { if visit_uuid == "" {
return routeutils.ResponseAPIValidationError(ctx, "visit_uuid param is mandatory") return routeutils.ResponseAPIValidationError(ctx, "visit_uuid param is mandatory")
} }
user, err := auth.GetUserDetail(ctx, c.cfg) authUser, err := auth.GetUserDetail(ctx, c.cfg)
if err != nil { if err != nil {
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }
resp, err := c.svc.Visits.GetByUUID(visit_uuid, user) resp, err := c.svc.Visits.GetByUUID(visit_uuid, authUser)
if err != nil { if err != nil {
fmt.Println("Error to get Visit: ", err.Error())
return routeutils.HandleAPIError(ctx, err) return routeutils.HandleAPIError(ctx, err)
} }

View File

@@ -2,6 +2,7 @@ package visitroute
import ( import (
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice" "bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
"bitbucket.org/nemt/nemt-portal-api/application/tncservice"
"bitbucket.org/nemt/nemt-portal-api/infra/config" "bitbucket.org/nemt/nemt-portal-api/infra/config"
"github.com/labstack/echo" "github.com/labstack/echo"
) )
@@ -9,11 +10,15 @@ import (
const ( const (
rootRoute = "/" rootRoute = "/"
idRoute = "/:visit_uuid" idRoute = "/:visit_uuid"
rideRoute = "/:visit_uuid/ride"
) )
// Register registers the routes in the echo group // Register registers the routes in the echo group
func Register(r *echo.Group, cfg *config.Config, svc *applicationservice.Service) { func Register(r *echo.Group, cfg *config.Config, svc *applicationservice.Service, tnc *tncservice.Service) {
ctrl := controllerInstance(svc, cfg) ctrl := controllerInstance(svc, cfg, tnc)
r.POST(rootRoute, ctrl.handle)
r.POST(rideRoute, ctrl.handleRide)
r.GET(rootRoute, ctrl.handleGetAll) r.GET(rootRoute, ctrl.handleGetAll)
r.GET(idRoute, ctrl.handleGetByID) r.GET(idRoute, ctrl.handleGetByID)

View File

@@ -193,8 +193,6 @@ func (a *Config) objectRelation(object interface{}, currentUser viewmodel.User)
case viewmodel.User: case viewmodel.User:
if obj.ID == currentUser.ID { if obj.ID == currentUser.ID {
return "[self]" return "[self]"
} else {
return "[other]"
} }
} }
return "[other]" return "[other]"

View File

@@ -18,7 +18,8 @@ func authSkipper(ctx echo.Context) bool {
strings.Contains(path, "/v1/ext") || strings.Contains(path, "/v1/ext") ||
strings.Contains(path, "/v1/notification/ws") || strings.Contains(path, "/v1/notification/ws") ||
strings.HasPrefix(path, "/v1/lyfthook") || strings.HasPrefix(path, "/v1/lyfthook") ||
strings.HasPrefix(path, "/v1/docs")) strings.HasPrefix(path, "/v1/docs") ||
strings.HasPrefix(path, "/v1/selfregister"))
} }
// appSkipper is the default skipper for the application routes // appSkipper is the default skipper for the application routes

View File

@@ -0,0 +1,150 @@
package validation
import (
"regexp"
"time"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
const (
firstNameMaxLength = 50
lastNameMaxLength = 50
emailMaxLength = 150
memberNumberValidNumberOfLetters = 3
)
const (
formModeVisit = 1
formModeRide = 2
)
func isAlphabetic(input string) bool {
for _, character := range input {
if !(characterIsUpperCase(character) || characterIsLowerCase(character)) {
return false
}
}
return true
}
func isNumeric(input string) bool {
for _, character := range input {
if !characterIsNumber(character) {
return false
}
}
return true
}
func isEmailValid(email string) bool {
validEmailRegex := regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
return validEmailRegex.MatchString(email)
}
func isMemberNumberValid(input string) bool {
if len(input) < memberNumberValidNumberOfLetters {
return false
}
if !isAlphabetic(input[:memberNumberValidNumberOfLetters]) {
return false
}
if !isNumeric(input[memberNumberValidNumberOfLetters:]) {
return false
}
return true
}
func ValidateEligibility(user *viewmodel.User) []errors.ValidationError {
var result []errors.ValidationError
formMode := formModeVisit // This should be red from request, not hardcoded
//First name validation
if len(user.First) < 1 {
result = append(result, errors.ValidationError{Field: "first", Message: "First Name is required"})
}
if !isAlphabetic(user.First) {
result = append(result, errors.ValidationError{Field: "first", Message: "First Name contains non-alphabetic characters"})
}
if len(user.First) > firstNameMaxLength {
result = append(result, errors.ValidationError{Field: "first", Message: "First Name is too long"})
}
//Last name validation
if len(user.Last) < 1 {
result = append(result, errors.ValidationError{Field: "last", Message: "Last Name is required"})
}
if !isAlphabetic(user.Last) {
result = append(result, errors.ValidationError{Field: "last", Message: "Last Name contains non-alphabetic characters"})
}
if len(user.Last) > lastNameMaxLength {
result = append(result, errors.ValidationError{Field: "last", Message: "Last Name is too long"})
}
//Email validation
if user.Email != nil && len(*user.Email) > 0 {
if (formMode == formModeRide) && len(*user.Email) < 1 {
result = append(result, errors.ValidationError{Field: "email", Message: "Email is required"})
}
if !isEmailValid(*user.Email) {
result = append(result, errors.ValidationError{Field: "email", Message: "Email is invalid"})
}
if len(*user.Email) > emailMaxLength {
result = append(result, errors.ValidationError{Field: "email", Message: "Email is too long"})
}
} else {
if formMode == formModeRide {
result = append(result, errors.ValidationError{Field: "email", Message: "Email is required"})
}
}
//Gender validation
if ((user.Gender != nil) && len(*user.Gender) < 1) || (user.Gender == nil) {
result = append(result, errors.ValidationError{Field: "gender", Message: "Member Gender is required"})
}
//Member type validation
if (user.Type != nil && len(*user.Type) < 1) || (user.Type == nil) {
result = append(result, errors.ValidationError{Field: "type", Message: "Member Type is required"})
}
//Member# validation
if !isMemberNumberValid(*user.Member) {
result = append(result, errors.ValidationError{Field: "member", Message: "Member# is invalid"})
}
//Birthdate validation
if user.BirthDate == nil {
result = append(result, errors.ValidationError{Field: "birthdate", Message: "Choose a Birth Date"})
} else {
yesterday := time.Now().Add(-1 * time.Hour * hoursInDay)
if user.BirthDate.After(yesterday) {
result = append(result, errors.ValidationError{Field: "birthdate", Message: "Choose a valid Birth Date"})
}
}
//Mobile validation
if formMode == formModeRide {
if (user.PhoneNumber != nil && len(*user.PhoneNumber) < 1) || (user.PhoneNumber == nil) {
result = append(result, errors.ValidationError{Field: "phonenumber", Message: "Phone number is required"})
}
}
//User consent validation
if !user.Consent {
result = append(result, errors.ValidationError{Field: "consent", Message: "Must be 'Checked'"})
}
return result
}

View File

@@ -0,0 +1,111 @@
package validation
import (
"fmt"
"strings"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
const (
minimumPasswordLength = 8
)
func validateSelfregistrationPassword(user *viewmodel.User, result *[]errors.ValidationError) {
if len(user.Pass) < minimumPasswordLength {
*result = append(*result, errors.ValidationError{Field: "password", Message: fmt.Sprint("Password must be at least ", minimumPasswordLength, " characters.")})
}
if strings.Contains(user.Pass, user.First) {
*result = append(*result, errors.ValidationError{Field: "password", Message: "Password cannot include your First Name."})
}
if strings.Contains(user.Pass, user.Last) {
*result = append(*result, errors.ValidationError{Field: "password", Message: "Password cannot include your Last Name."})
}
containsUpperCaseLetter := false
containsLowerCaseLetter := false
containsNumber := false
for _, character := range user.Pass {
containsUpperCaseLetter = containsUpperCaseLetter || characterIsUpperCase(character)
containsLowerCaseLetter = containsLowerCaseLetter || characterIsLowerCase(character)
containsNumber = containsNumber || characterIsNumber(character)
}
if !containsUpperCaseLetter || !containsLowerCaseLetter || !containsNumber {
*result = append(*result, errors.ValidationError{Field: "password", Message: "Password must contain one of EACH :"})
*result = append(*result, errors.ValidationError{Field: "password-tab", Message: "an uppercase letter"})
*result = append(*result, errors.ValidationError{Field: "password-tab", Message: "a lowercase letter"})
*result = append(*result, errors.ValidationError{Field: "password-tab", Message: "a number"})
}
}
func ValidateSelfregistration(user *viewmodel.User) []errors.ValidationError {
var result []errors.ValidationError
//Provider Organization Name validation
if len(user.Provider.OrganizatioName) < 1 {
result = append(result, errors.ValidationError{Field: "provider.org_name", Message: "Provider Organization Name is required"})
}
//Provider NPI validation
if len(user.Provider.InternalID) != 10 || !isNumeric(user.Provider.InternalID) {
result = append(result, errors.ValidationError{Field: "provider.internal_id", Message: "Provider NPI must be a 10 digit number"})
}
//First name validation
if len(user.First) < 1 {
result = append(result, errors.ValidationError{Field: "first", Message: "First Name is required"})
}
if !isAlphabetic(user.First) {
result = append(result, errors.ValidationError{Field: "first", Message: "First Name contains non-alphabetic characters"})
}
if len(user.First) > firstNameMaxLength {
result = append(result, errors.ValidationError{Field: "first", Message: "First Name is too long"})
}
//Last name validation
if len(user.Last) < 1 {
result = append(result, errors.ValidationError{Field: "last", Message: "Last Name is required"})
}
if !isAlphabetic(user.Last) {
result = append(result, errors.ValidationError{Field: "last", Message: "Last Name contains non-alphabetic characters"})
}
if len(user.Last) > lastNameMaxLength {
result = append(result, errors.ValidationError{Field: "last", Message: "Last Name is too long"})
}
//Email validation
if user.Email != nil {
if len(*user.Email) < 1 {
result = append(result, errors.ValidationError{Field: "email", Message: "Email is required"})
}
if !isEmailValid(*user.Email) {
result = append(result, errors.ValidationError{Field: "email", Message: "Email is invalid"})
}
if len(*user.Email) > emailMaxLength {
result = append(result, errors.ValidationError{Field: "email", Message: "Email is too long"})
}
} else {
result = append(result, errors.ValidationError{Field: "email", Message: "Email is required"})
}
//Mobile validation
if (user.PhoneNumber == nil) || len(*user.PhoneNumber) < 1 {
result = append(result, errors.ValidationError{Field: "phonenumber", Message: "Phone number is required"})
}
//Password validation
validateSelfregistrationPassword(user, &result)
return result
}

229
server/validation/tnc.go Normal file
View File

@@ -0,0 +1,229 @@
package validation
import (
"fmt"
"regexp"
"strconv"
"time"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
const (
tripTypeFromVisit = "from_visit"
tripTypeToVisit = "to_visit"
tripTypeFromVisitWillCall = "from_visit_call"
tripTypeRoundTrip = "roundtrip"
tripTypeRountTripWillCall = "roundtrip_call"
)
const (
loadingTime = 30 //in minutes
minimumLoadTime = 30 //in minutes
minimumPickupTime = 10 //in minutes
)
const (
hoursInDay = 24
hoursIn180Days = 24 * 180
time8Hours = 8
time10Minutes = 10
)
func isMixedIDValid(id string) bool {
hasUpperCase := false
hasLowerCase := false
hasNumber := false
for _, character := range id {
hasUpperCase = hasUpperCase || ((character >= 65) && (character <= 90))
hasLowerCase = hasLowerCase || ((character >= 97) && (character <= 122))
hasNumber = hasNumber || ((character >= 48) && (character <= 57))
}
return (hasUpperCase || hasLowerCase) && hasNumber
}
func ValidateVisitRide(requestRide *viewmodel.RideRequest, user *viewmodel.User) []errors.ValidationError {
var result []errors.ValidationError
if user.Email != nil && len(*user.Email) == 0 {
result = append(result, errors.ValidationError{Field: "email", Message: "Step #1 - Email is mandatory"})
}
if user.PhoneNumber != nil && len(*user.PhoneNumber) == 0 {
result = append(result, errors.ValidationError{Field: "phonenumber", Message: "Step #1 - Phonenumber is mandatory"})
}
rideValidation := ValidateRide(requestRide, user)
result = append(result, rideValidation...)
return result
}
func ValidateRide(requestRide *viewmodel.RideRequest, user *viewmodel.User) []errors.ValidationError {
var result []errors.ValidationError
var validUUIDregex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`)
//Step #1 validation
if !validUUIDregex.MatchString(user.ID) {
result = append(result, errors.ValidationError{Field: "user_uuid", Message: "Step #1 - Choose a Member"})
}
fmt.Println("\n\n", requestRide.Origin.ID, "\n\n")
if !isMixedIDValid(requestRide.Origin.ID) {
//it is not UUID or similar to UUID, let's try with just a number
if originID, err := strconv.Atoi(requestRide.Origin.ID); err != nil || originID <= 0 {
//it is not a number
result = append(result, errors.ValidationError{Field: "origin.id", Message: "Step #1 - Choose a Pickup Address"})
}
}
if !requestRide.UserConsent {
result = append(result, errors.ValidationError{Field: "user_consent", Message: "Step #1 - Member must consent to Terms of Use"})
}
//Step #2 validation
fmt.Println("\n\n", requestRide.Destination.ID, "\n\n")
if !isMixedIDValid(requestRide.Destination.ID) {
//it is not UUID or similar to UUID, let's try with just a number
if destinationID, err := strconv.Atoi(requestRide.Destination.ID); err != nil || destinationID <= 0 {
result = append(result, errors.ValidationError{Field: "destination.id", Message: "Step #2 - Choose a Provider"})
}
}
//Step #3 validation
isVisitDayToday := requestRide.VisitDate.Day() == time.Now().Day() && requestRide.VisitDate.Month() == time.Now().Month() && requestRide.VisitDate.Year() == time.Now().Year()
before8Hours := time.Now().Add(-time.Hour * time8Hours)
if requestRide.VisitDate == nil {
result = append(result, errors.ValidationError{Field: "visit_date", Message: "Step #3 - Choose a Date for the Visit"})
} else {
dayBeforeToday := time.Now().Add(-time.Hour * hoursInDay)
if requestRide.VisitDate.Before(dayBeforeToday) {
result = append(result, errors.ValidationError{Field: "visit_date", Message: "Step #3 - Visit cannot occur more than one day before today"})
}
dayAfter180Days := time.Now().Add(time.Hour * hoursIn180Days)
if requestRide.VisitDate.After(dayAfter180Days) {
result = append(result, errors.ValidationError{Field: "visit_date", Message: "Step #3 - Visit cannot occur more than 180 days after today"})
}
if requestRide.VisitTime == nil {
result = append(result, errors.ValidationError{Field: "visit_time", Message: "Step #3 - Choose a Time for the Visit"})
} else {
if isVisitDayToday && requestRide.VisitTime.Before(before8Hours) {
result = append(result, errors.ValidationError{Field: "visit_time", Message: "Step #3 - Visit is more than 8 hours in the past"})
}
}
}
//Step #4 validation
timeWithDurationAndLoadingTime := requestRide.VisitTime.Add(-time.Duration(requestRide.Duration) * time.Second).Add(-loadingTime * time.Minute)
after10Minutes := time.Now().Add(time.Minute * time10Minutes)
isTripTypeValid := true
switch requestRide.TripType.Key {
case tripTypeToVisit:
if requestRide.PickupTime == nil {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Choose a Pickup Time"})
} else {
if requestRide.PickupTime.After(*requestRide.VisitTime) {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Pickup Time must occur before Visit Time"})
}
if requestRide.PickupTime.After(timeWithDurationAndLoadingTime) {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Pickup Time less than required time before Visit Time"})
}
if isVisitDayToday && requestRide.PickupTime.Before(before8Hours) {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Visit cannot occour in the past"})
}
}
case tripTypeFromVisit:
if requestRide.PickupTime == nil {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Choose a Pickup Time"})
} else {
timeWithMinimumPickupTime := time.Now().Add(minimumPickupTime * time.Minute)
if isVisitDayToday && requestRide.PickupTime.Before(timeWithMinimumPickupTime) {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: fmt.Sprint("Step #4 - Time must be more than %d minutes from now", minimumPickupTime)})
}
if requestRide.PickupTime.Before(*requestRide.VisitTime) {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Pickup Time less than required time after Visit Time"})
}
timeWithMinimumLoadTime := time.Now().Add(minimumLoadTime * time.Minute)
if requestRide.PickupTime.Before(timeWithMinimumLoadTime) {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Pickup Time less than Minimum Load Time before Visit Time"})
}
}
case tripTypeFromVisitWillCall:
//no special validation for this case
case tripTypeRoundTrip:
if requestRide.PickupTime == nil {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Choose a Pickup Time"})
} else {
if requestRide.PickupTime.After(*requestRide.VisitTime) {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Pickup Time must occur before Visit Time"})
}
if requestRide.PickupTime.After(timeWithDurationAndLoadingTime) {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Pickup Time less than required time before Visit Time"})
}
if isVisitDayToday && requestRide.PickupTime.Before(after10Minutes) {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Pickup Time must be at least 10 minutes from now"})
}
}
if requestRide.ReturnTime == nil {
result = append(result, errors.ValidationError{Field: "return_time", Message: "Step #4 - Choose a Pickup Time"})
} else {
if isVisitDayToday {
if requestRide.ReturnTime.Before(before8Hours) {
result = append(result, errors.ValidationError{Field: "return_time", Message: "Step #4 - Return Time is more than 8 hours after Visit Time"})
}
if requestRide.ReturnTime.Before(after10Minutes) {
result = append(result, errors.ValidationError{Field: "return_time", Message: "Step #4 - Return Time must be at least 10 minutes from now"})
}
}
}
case tripTypeRountTripWillCall:
if requestRide.PickupTime == nil {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Choose a Pickup Time"})
} else {
if requestRide.PickupTime.After(*requestRide.VisitTime) {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Pickup Time must occur before Visit Time"})
}
if requestRide.PickupTime.After(timeWithDurationAndLoadingTime) {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Pickup Time less than required time after Visit Time"})
}
if isVisitDayToday && requestRide.PickupTime.Before(before8Hours) {
result = append(result, errors.ValidationError{Field: "pickup_time", Message: "Step #4 - Visit cannot occur in the past "})
}
}
default:
isTripTypeValid = false
}
if !isTripTypeValid {
result = append(result, errors.ValidationError{Field: "trip_type.key", Message: "Step #4 - Choose a Trip Type"})
}
return result
}

66
server/validation/user.go Normal file
View File

@@ -0,0 +1,66 @@
package validation
import (
"strings"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
func characterIsUpperCase(character rune) bool {
return (character >= 65) && (character <= 90)
}
func characterIsLowerCase(character rune) bool {
return (character >= 97) && (character <= 122)
}
func characterIsNumber(character rune) bool {
return (character >= 48) && (character <= 57)
}
func ValidatePassword(user *viewmodel.User) []errors.ValidationError {
var result []errors.ValidationError
userOrganizationName := ""
if len(user.Organizations) > 0 {
userOrganizationName = user.Organizations[0].Name
}
if len(user.Pass) < 8 {
result = append(result, errors.ValidationError{Field: "password", Message: "Password must be at least 8 characters."})
}
if strings.Contains(user.Pass, user.First) {
result = append(result, errors.ValidationError{Field: "password", Message: "Password cannot include your First Name."})
}
if strings.Contains(user.Pass, user.Last) {
result = append(result, errors.ValidationError{Field: "password", Message: "Password cannot include your Last Name."})
}
if len(userOrganizationName) > 0 {
if strings.Contains(user.Pass, userOrganizationName) {
result = append(result, errors.ValidationError{Field: "password", Message: "Password cannot include your Organization Name."})
}
}
containsUpperCaseLetter := false
containsLowerCaseLetter := false
containsNumber := false
for _, character := range user.Pass {
containsUpperCaseLetter = containsUpperCaseLetter || characterIsUpperCase(character)
containsLowerCaseLetter = containsLowerCaseLetter || characterIsLowerCase(character)
containsNumber = containsNumber || characterIsNumber(character)
}
if !containsUpperCaseLetter || !containsLowerCaseLetter || !containsNumber {
result = append(result, errors.ValidationError{Field: "password", Message: "Password must contain one of EACH :"})
result = append(result, errors.ValidationError{Field: "password-tab", Message: "an uppercase letter"})
result = append(result, errors.ValidationError{Field: "password-tab", Message: "a lowercase letter"})
result = append(result, errors.ValidationError{Field: "password-tab", Message: "a number"})
}
return result
}

View File

@@ -0,0 +1,45 @@
package validation
import (
"time"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
func ValidateVisit(visit *viewmodel.Visit, user *viewmodel.User) []errors.ValidationError {
var result []errors.ValidationError
// Step #1
if len(visit.Provider.ProviderUUID) == 0 {
result = append(result, errors.ValidationError{Field: "provider.id", Message: "Step #1 - Provider is required"})
}
// Step #2
eligibilityResult := ValidateEligibility(&visit.User)
if len(eligibilityResult) > 0 {
result = append(result, eligibilityResult...)
}
//Step #3
if visit.VisitDatetime.IsZero() {
result = append(result, errors.ValidationError{Field: "visit_datetime", Message: "Step #3 - Choose a Date for the Visit"})
} else {
isVisitDayToday := visit.VisitDatetime.Day() == time.Now().Day() && visit.VisitDatetime.Month() == time.Now().Month() && visit.VisitDatetime.Year() == time.Now().Year()
before8Hours := time.Now().Add(-time.Hour * time8Hours)
dayBeforeToday := time.Now().Add(-time.Hour * hoursInDay)
if visit.VisitDatetime.Before(dayBeforeToday) {
result = append(result, errors.ValidationError{Field: "visit_datetime", Message: "Step #3 - Visit cannot occur more than one day before today"})
}
dayAfter180Days := time.Now().Add(time.Hour * hoursIn180Days)
if visit.VisitDatetime.After(dayAfter180Days) {
result = append(result, errors.ValidationError{Field: "visit_datetime", Message: "Step #3 - Visit cannot occur more than 180 days after today"})
}
if isVisitDayToday && visit.VisitDatetime.Before(before8Hours) {
result = append(result, errors.ValidationError{Field: "visit_datetime", Message: "Step #3 - Visit is more than 8 hours in the past"})
}
}
return result
}