initial commit 2

This commit is contained in:
Senad Uka
2018-04-25 13:16:36 +02:00
parent c1520d169c
commit 99c10b75fb
167 changed files with 25057 additions and 0 deletions

23
Dockerfile.build Normal file
View File

@@ -0,0 +1,23 @@
FROM golang:1.9.2
# Install glide
RUN curl https://glide.sh/get | sh
# Sets the arguments.
ARG BIN_NAME
ARG APP_NAME
ARG WORKDIR=/go/src/bitbucket.org/nemt/${APP_NAME}
# Prepares the work directory.
RUN mkdir -p ${WORKDIR}
ADD . ${WORKDIR}
WORKDIR ${WORKDIR}
RUN rm -rf glide.lock
RUN rm -rf vendor/
# Installs dependencies and builds app.
RUN glide install -force
RUN go build -o ${BIN_NAME} .
# Pauses the container.
CMD read

22
Dockerfile.run Normal file
View File

@@ -0,0 +1,22 @@
FROM amazonlinux
# Sets the arguments.
ARG BIN_NAME=nemt-portal-api
ARG APP_NAME=nemt-portal-api
ARG WORKDIR=/opt/app/
# Creates the necessary directories.
RUN mkdir -p /opt/app/docs
RUN mkdir -p /opt/app/static
RUN mkdir -p /var/log/bsbsi
# Copies the files to the container.
COPY ./dist/${BIN_NAME} /opt/app/${BIN_NAME}
ADD ./dist/docs/ /opt/app/docs/
ADD ./dist/static/ /opt/app/static/
ADD ./dist/config.toml /opt/app/config.toml
# Sets and executes the app.
WORKDIR /opt/app
EXPOSE 5000
CMD ./nemt-portal-api

12
Dockerrun.aws.json Normal file
View File

@@ -0,0 +1,12 @@
{
"AWSEBDockerrunVersion": "1",
"Image": {
"Update": "true"
},
"Ports": [
{
"ContainerPort": "5000"
}
],
"Logging": "/var/log/eb-docker/containers/eb-current-app/stdouterr.log"
}

102
Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,102 @@
node {
stage("Setting variables") {
echo "Setting variables"
BRANCH_PRD = 'master'
BRANCH_STG = 'staging'
BRANCH_DEV = 'development'
// Gets the environment based on the current Git branch.
if (env.BRANCH_NAME == BRANCH_PRD) {
env.DEPLOY_ENV = 'prd'
} else if (env.BRANCH_NAME == BRANCH_STG) {
env.DEPLOY_ENV = 'stg'
} else if (env.BRANCH_NAME == BRANCH_DEV) {
env.DEPLOY_ENV = 'dev'
}
// Define environment variables for other files to use it.
env.APP_NAME = "nemt-portal-api"
env.ENV_NAME = "${env.APP_NAME}-${env.DEPLOY_ENV}"
echo "Branch: ${env.BRANCH_NAME}"
echo "Environment: ${env.DEPLOY_ENV}"
echo "Setting variables complete"
}
stage("Cleaning") {
echo "Cleaning"
sh "rm -rf ${pwd()}/*"
deleteDir()
echo "Cleaning complete"
}
stage("Build") {
echo "Building"
// Sets package name based on the AWS job name, the current Git tag version and the build ID.
GIT_TAG = "\$(git describe --tags --always --dirty)"
PKG_NAME = "${GIT_TAG}-${env.JOB_BASE_NAME}-${env.BUILD_ID}"
ZIP_FILE_NAME = "${PKG_NAME}.zip"
// Sets the variables used for Docker login.
AWS_DOCKER_ROLE_NAME = "rvbrazil-bsbsi-deploy"
AWS_DOCKER_ROLE_ARN = "arn:aws:iam::xxxxxxxxxxx:role/bsbsi-deploy"
// Downloads repository.
echo "Downloading repository"
checkout scm
// Assumes role into our AWS account (for Docker login).
sh "aws-assume-role ${AWS_DOCKER_ROLE_ARN} ${AWS_DOCKER_ROLE_NAME}"
// Uses the AWS CLI to get our Docker login commmand and executes it.
sh "\$(aws --region us-east-1 --profile ${AWS_DOCKER_ROLE_NAME} ecr get-login)"
// Builds the application.
sh "make build-${env.DEPLOY_ENV}"
// Zips the files that will go to S3.
sh "cp Dockerfile.run Dockerfile"
sh "rm -rf ./*.zip"
sh "zip -r ${ZIP_FILE_NAME} dist Dockerfile Dockerrun.aws.json"
echo "Building complete"
}
stage("Deploy") {
echo "Deploying"
echo "Environment: ${env.DEPLOY_ENV}"
// Sets the variables used for deploying.
S3_BUCKET = "boilerplate-builds"
S3_KEY = "${env.APP_NAME}/${env.DEPLOY_ENV}/${ZIP_FILE_NAME}"
S3_PATH = "${S3_BUCKET}/${S3_KEY}"
AWS_ROLE_NAME = "qrides-bsbsi-deploy"
AWS_ROLE_ARN = "arn:aws:iam::xxxxxxxxxx:role/bsbsi-deploy"
// Assumes role into our AWS account (for S3 deploy).
sh "aws-assume-role ${AWS_ROLE_ARN} ${AWS_ROLE_NAME}"
// Deploys container to S3.
sh "aws --region sa-east-1 --profile ${AWS_ROLE_NAME} s3 mv ${ZIP_FILE_NAME} s3://${S3_PATH}"
// Deploys to EBS.
sh "aws --region sa-east-1 --profile ${AWS_ROLE_NAME} elasticbeanstalk \
create-application-version \
--application-name \"${env.APP_NAME}\" \
--version-label \"${PKG_NAME}\" \
--description \"${ZIP_FILE_NAME}\" \
--source-bundle S3Bucket=\"${S3_BUCKET}\",S3Key=\"${S3_KEY}\""
// Updates EBS environment.
sh "aws --region sa-east-1 --profile ${AWS_ROLE_NAME} elasticbeanstalk \
update-environment \
--application-name \"${env.APP_NAME}\" \
--environment-name \"${env.ENV_NAME}\" \
--version-label \"${PKG_NAME}\""
echo "Deploying complete"
}
}

147
Makefile Normal file
View File

@@ -0,0 +1,147 @@
PORT ?= 5000
DEPLOY_ENV ?= loc
BIN_NAME ?= nemt-portal-api
APP_NAME ?= nemt-portal-api
BUILD_CONTAINER_NAME = ${APP_NAME}-build
RUN_CONTAINER_NAME = ${APP_NAME}-run
#############################
## Environment definition. ##
#############################
set-loc:
$(eval DEPLOY_ENV := loc)
set-dev:
$(eval DEPLOY_ENV := dev)
set-stg:
$(eval DEPLOY_ENV := stg)
set-prd:
$(eval DEPLOY_ENV := prd)
######################
## Building process ##
######################
# Creates the container for the building process.
create-build-container:
# Verifies if the container already exists.
$(eval CONTAINER_ID:=$(shell docker ps -q --filter ancestor=$(BUILD_CONTAINER_NAME)))
# If it does, removes it.
if [ $(CONTAINER_ID) ]; then \
docker stop $(CONTAINER_ID) && \
docker rm $(CONTAINER_ID) && \
docker rmi -f $(BUILD_CONTAINER_NAME); \
fi
# Creates "build" container.
docker build -f Dockerfile.build -t ${BUILD_CONTAINER_NAME}:latest --build-arg BIN_NAME=${BIN_NAME} --build-arg APP_NAME=${APP_NAME} --force-rm .
# Runs the `build` container and gets its binary.
build: clean create-build-container
# Creates the necessary folders.
mkdir -p dist/static
mkdir -p dist/docs
# Builds inside the container.
docker run \
--name ${BUILD_CONTAINER_NAME} -d ${BUILD_CONTAINER_NAME}
# Gets the binary.
docker cp \
${BUILD_CONTAINER_NAME}:/go/src/bitbucket.org/nemt/${APP_NAME}/${BIN_NAME} \
./dist/${BIN_NAME}
# Kills the container.
docker stop ${BUILD_CONTAINER_NAME}
docker rm ${BUILD_CONTAINER_NAME}
# Copies the docs and the static files to the correct folder.
cp -R static/* ./dist/static/
cp -R docs/swagger/ ./dist/docs/
cp config.${DEPLOY_ENV}.toml ./dist/config.toml
#################################################
## Building, based on the current environment. ##
#################################################
build-loc: set-loc build
build-dev: set-dev build
build-stg: set-stg build
build-prd: set-prd build
#####################
## Running process ##
#####################
create-run-container:
# Verifies if the container already exists.
$(eval CONTAINER_ID:=$(shell docker ps -q --filter ancestor=$(RUN_CONTAINER_NAME)))
# If it does, removes it.
if [ $(CONTAINER_ID) ]; then \
docker stop $(CONTAINER_ID) && \
docker rm $(CONTAINER_ID) && \
docker rmi -f $(RUN_CONTAINER_NAME); \
fi
# Creates "run" container.
docker build -f Dockerfile.run -t ${RUN_CONTAINER_NAME}:latest --force-rm \
--build-arg BIN_NAME=${BIN_NAME} \
--build-arg APP_NAME=${APP_NAME} \
.
run: create-run-container
docker run -p ${PORT}:${PORT} -d --rm --name ${RUN_CONTAINER_NAME} ${RUN_CONTAINER_NAME}
echo 'Container exposing port ${PORT}.'
################################################
## Running, based on the current environment. ##
################################################
build-run-loc: build-loc create-run-container
build-run-dev: build-dev create-run-container
build-run-stg: build-stg create-run-container
build-run-prd: build-prd create-run-container
run-loc: build-run-loc run
run-dev: build-run-dev run
run-stg: build-run-stg run
run-prd: build-run-prd run
############
## Others ##
############
clean:
rm -f ${BIN_NAME}
rm -rf dist
run-host:
glide install
go build -o ${BIN_NAME} .
cp config.loc.toml ./config.toml
./${BIN_NAME}
migrate:
echo "Not implemented" && exit 500
test:
echo "Not implemented" && exit 500

View File

@@ -0,0 +1,43 @@
package applicationservice
import (
"sync"
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
"bitbucket.org/nemt/nemt-portal-api/application/notificationservice"
"bitbucket.org/nemt/nemt-portal-api/domain/service"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
)
var (
instance *Service
once sync.Once
)
// Service holds the domain service repositories
type Service struct {
Users *userService
Rides *rideService
Visits *visitService
Provider *providerService
Notification *notificationService
Profile *profileService
Organization *organizationService
}
// New returns a new domain Service instance
func New(svc *service.Service, mapper *entitymapping.Mapper, notification *notificationservice.Service, cfg *config.Config) *Service {
once.Do(func() {
instance = &Service{
Users: newUserService(svc, mapper),
Rides: newRideService(svc, mapper),
Visits: newVisitService(svc, mapper),
Provider: newProviderService(svc, mapper),
Notification: newNotificationService(svc, mapper, notification, cfg),
Profile: newProfileService(svc, mapper),
Organization: newOrganizationService(svc, mapper),
}
})
return instance
}

View File

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

View File

@@ -0,0 +1,131 @@
package applicationservice
const (
MessageSMSIAmReadyOrClick = "When you ready to go back to %s, click on the following link:\n %s\n or reply this message with I AM READY"
MessageEmailIAmReadyOrClick = "When you are ready to go back to %s, click on the following link:\n %s"
MessageSMSReplyOrCancel = "Reply CANCEL RIDE to cancel or DRIVER to contact driver"
MessageSMSPendingMember = "A ride has been scheduled for your %s visit to %s on %s.\n\nThe driver will arrive at %s by %s."
MessageSMSPendingMemberTitle = "Ride Pending for %s"
MessageSMSPendingDispatcher = "A ride has been scheduled for %s's %s visit to %s on %s.\n\nThe driver will arrive at %s by %s."
MessageSMSPendingDispatcherTitle = "Ride Pending for %s on %s"
MessageEmailPendingMember = "A ride has been scheduled for your %s visit to %s on %s.\n\nThe driver will arrive at %s by %s."
MessageEmailPendingMemberTitle = "Ride Pending for %s"
MessageEmailPendingDispatcher = "A ride has been scheduled for %s's %s visit to %s on %s.\n\nThe driver will arrive at %s by %s."
MessageEmailPendingDispatcherTitle = "Ride Pending for %s on %s"
MessageAppPendingMember = "A ride has been scheduled for your %s visit to %s on %s.\n\nThe driver will arrive at %s by %s."
MessageAppPendingMemberTitle = "Pickup: %s | %s"
MessageAppPendingDispatcher = "A ride has been scheduled for %s's %s visit to %s on %s.\n\nThe driver will arrive at %s by %s."
MessageAppPendingDispatcherTitle = "Pickup: %s | %s"
MessageSMSWillCallMember = "A ride has been scheduled for your %s visit to %s on %s."
MessageSMSWillCallMemberTitle = "Ride Pending for %s"
MessageSMSWillCallDispatcher = "A ride has been scheduled for %s's %s visit to %s on %s."
MessageSMSWillCallDispatcherTitle = "Ride Pending for %s"
MessageEmailWillCallMember = "A ride has been scheduled for your %s visit to %s on %s."
MessageEmailWillCallMemberTitle = "Ride Pending for %s"
MessageEmailWillCallDispatcher = "A ride has been scheduled for %s's %s visit to %s on %s."
MessageEmailWillCallDispatcherTitle = "Ride Pending for %s"
MessageAppWillCallMember = "A ride has been scheduled for your %s visit to %s on %s."
MessageAppWillCallMemberTitle = "Pickup: %s | %s"
MessageAppWillCallDispatcher = "A ride has been scheduled for %s's %s visit to %s on %s."
MessageAppWillCallDispatcherTitle = "Pickup: %s | %s"
MessageSMSScheduledMember = "A ride has been scheduled for your %s visit to %s on %s.\n\nThe driver will arrive at %s by %s."
MessageSMSScheduledMemberTitle = "Ride Scheduled for %s"
MessageSMSScheduledDispatcher = "A ride has been scheduled for %s's %s visit to %s on %s.\n\nThe driver will arrive at %s by %s."
MessageSMSScheduledDispatcherTitle = "Ride Scheduled for %s on %s"
MessageEmailScheduledMember = "A ride has been scheduled for your %s visit to %s on %s.\n\nThe driver will arrive at %s by %s."
MessageEmailScheduledMemberTitle = "Ride Scheduled for %s"
MessageEmailScheduledDispatcher = "A ride has been scheduled for %s's %s visit to %s on %s.\n\nThe driver will arrive at %s by %s."
MessageEmailScheduledDispatcherTitle = "Ride Scheduled for %s on %s"
MessageAppScheduledMember = "A ride has been scheduled for your %s visit to %s on %s.\n\nThe driver will arrive at %s by %s."
MessageAppScheduledMemberTitle = "Pickup: %s | %s"
MessageAppScheduledDispatcher = "A ride has been scheduled for %s's %s visit to %s on %s.\n\nThe driver will arrive at %s by %s."
MessageAppScheduledDispatcherTitle = "Pickup: %s | %s"
MessageSMSAcceptedMember = "Your driver, %s, is on the way to %s and will arrive by %s in a %s %s %s (%s).\n\nView Ride %s"
MessageSMSAcceptedMemberTitle = "Your Ride is on the way !"
MessageSMSAcceptedDispatcher = "A driver, %s, is on the way to %s and will arrive by %s in a %s %s %s (%s).\n\nView Ride %s"
MessageSMSAcceptedDispatcherTitle = "Ride Accepted for %s"
MessageEmailAcceptedMember = "Your driver, %s, is on the way to %s and will arrive by %s in a %s %s %s (%s).\n\nView Ride %s"
MessageEmailAcceptedMemberTitle = "Your Ride is on the way !"
MessageEmailAcceptedDispatcher = "A driver, %s, is on the way to %s and will arrive by %s in a %s %s %s (%s).\n\nView Ride %s"
MessageEmailAcceptedDispatcherTitle = "Ride Accepted for %s"
MessageAppAcceptedMember = "Your driver, %s, is on the way to %s and will arrive by %s in a %s %s %s (%s).\n\nView Ride %s"
MessageAppAcceptedMemberTitle = "ETA: %s at %s"
MessageAppAcceptedDispatcher = "A driver, %s, is on the way to %s and will arrive by %s in a %s %s %s (%s).\n\nView Ride %s"
MessageAppAcceptedDispatcherTitle = "ETA: %s at %s"
MessageSMSArrivedMember = "Your ride has arrived at %s.\n\nPlease look for %s in a %s %s %s (%s).\n\nView Ride %s"
MessageSMSArrivedMemberTitle = "Your Ride is HERE !"
MessageSMSArrivedDispatcher = "Vehicle has arrived at %s.\n\nPlease tell member to look for %s in a %s %s %s (%s).\n\nView Ride %s"
MessageSMSArrivedDispatcherTitle = "Ride Arrived for %s"
MessageEmailArrivedMember = "Your ride has arrived at %s.\n\nPlease look for %s in a %s %s %s (%s).\n\nView Ride %s"
MessageEmailArrivedMemberTitle = "Your Ride is HERE !"
MessageEmailArrivedDispatcher = "Vehicle has arrived at %s.\n\nPlease tell member to look for %s in a %s %s %s (%s).\n\nView Ride %s"
MessageEmailArrivedDispatcherTitle = "Ride Arrived for %s"
MessageAppArrivedMember = "Your ride has arrived at %s.\n\nPlease look for %s in a %s %s %s (%s).\n\nView Ride %s"
MessageAppArrivedMemberTitle = "Look for %s %s %s (%s)"
MessageAppArrivedDispatcher = "Vehicle has arrived at %s.\n\nPlease tell member to look for %s in a %s %s %s (%s).\n\nView Ride %s"
MessageAppArrivedDispatcherTitle = "Look for %s %s %s (%s)"
MessageSMSPickedUpDispatcher = "Member %s was picked up at %s at %s.\n\nView Ride %s\n\nVISIT: %s\n\nESTIMATED ARRIVAL: %s"
MessageSMSPickedUpDispatcherTitle = "%s is in Transit"
MessageEmailPickedUpDispatcher = "Member %s was picked up at %s at %s.\n\nView Ride %s\n\nVISIT: %s\n\nESTIMATED ARRIVAL: %s"
MessageEmailPickedUpDispatcherTitle = "%s is in Transit"
MessageAppPickedUpDispatcher = "Member %s was picked up at %s at %s.\n\nView Ride %s\n\nVISIT: %s\n\nESTIMATED ARRIVAL: %s"
MessageAppPickedUpDispatcherTitle = "Actual Pickup Time: %s"
MessageSMSDroppedOffDispatcher = "Member %s was dropped off at %s at ACTUAL %s.\n\nView Ride %s\n\nVISIT: %s"
MessageSMSDroppedOffDispatcherTitle = "%s has arrived"
MessageEmailDroppedOffDispatcher = "Member %s was dropped off at %s at ACTUAL %s.\n\nView Ride %s\n\nVISIT: %s"
MessageEmailDroppedOffDispatcherTitle = "%s has arrived"
MessageAppDroppedOffDispatcher = "Member %s was dropped off at %s at ACTUAL %s.\n\nView Ride %s\n\nVISIT: %s"
MessageAppDroppedOffDispatcherTitle = "Arrival Time: %s"
MessageSMSDroppedOffMember = "Your ride has been ended, Thank you."
MessageSMSDroppedOffMemberTitle = "Ride Ended"
MessageEmailDroppedOffMember = "Your ride has been ended, Thank you."
MessageEmailDroppedOffMemberTitle = "Ride Ended"
MessageAppDroppedOffMember = "Your ride has been ended, Thank you."
MessageAppDroppedOffMemberTitle = "Arrived to %s"
MessageSMSCanceledByDriverMember = "Your scheduled ride has been CANCELLED by your assigned driver.\n\nWe will schedule a NEW ride for your %s visit and notify you when your NEW driver has been assigned.\n\nVISIT: %s"
MessageSMSCanceledByDriverMemberTitle = "Your Ride has been Canceled"
MessageSMSCanceledByDriverDispatcher = "The member's scheduled ride has been CANCELLED by the assigned driver.\n\nWe will schedule a NEW ride for your %s visit and notify you when your NEW driver has been assigned.\n\nVISIT: %s"
MessageSMSCanceledByDriverDispatcherTitle = "Ride for %s Canceled"
MessageEmailCanceledByDriverMember = "Your scheduled ride has been CANCELLED by your assigned driver.\n\nWe will schedule a NEW ride for your %s visit and notify you when your NEW driver has been assigned.\n\nVISIT: %s"
MessageEmailCanceledByDriverMemberTitle = "Your Ride has been Canceled"
MessageEmailCanceledByDriverDispatcher = "The member's scheduled ride has been CANCELLED by the assigned driver.\n\nWe will schedule a NEW ride for your %s visit and notify you when your NEW driver has been assigned.\n\nVISIT: %s"
MessageEmailCanceledByDriverDispatcherTitle = "Ride for %s Canceled"
MessageAppCanceledByDriverMember = "Your scheduled ride has been CANCELLED by your assigned driver.\n\nWe will schedule a NEW ride for your %s visit and notify you when your NEW driver has been assigned.\n\nVISIT: %s"
MessageAppCanceledByDriverMemberTitle = "Canceled by Driver"
MessageAppCanceledByDriverDispatcher = "The member's scheduled ride has been CANCELLED by the assigned driver.\n\nWe will schedule a NEW ride for your %s visit and notify you when your NEW driver has been assigned.\n\nVISIT: %s"
MessageAppCanceledByDriverDispatcherTitle = "Canceled by Driver"
MessageSMSCanceledNoDriverMember = "Your scheduled ride for your %s visit to %s on %s has been CANCELLED because no drivers are currently available in your area.\n\nYour medical provider will contact you shortly to arrange alternative transportation or reschedule your visit."
MessageSMSCanceledNoDriverMemberTitle = "Your Ride has been Canceled"
MessageSMSCanceledNoDriverDispatcher = "The member's ride to a %s visit to %s on %s has been CANCELLED because no drivers are currently available near the pickup area.\n\nPlease contact member to arrange alternative transportation or reschedule member visit.\n\nVISIT: %s"
MessageSMSCanceledNoDriverDispatcherTitle = "Ride for %s Canceled"
MessageEmailCanceledNoDriverMember = "Your scheduled ride for your %s visit to %s on %s has been CANCELLED because no drivers are currently available in your area.\n\nYour medical provider will contact you shortly to arrange alternative transportation or reschedule your visit."
MessageEmailCanceledNoDriverMemberTitle = "Your Ride has been Canceled"
MessageEmailCanceledNoDriverDispatcher = "The member's ride to a %s visit to %s on %s has been CANCELLED because no drivers are currently available near the pickup area.\n\nPlease contact member to arrange alternative transportation or reschedule member visit.\n\nVISIT: %s"
MessageEmailCanceledNoDriverDispatcherTitle = "Ride for %s Canceled"
MessageAppCanceledNoDriverMember = "Your scheduled ride for your %s visit to %s on %s has been CANCELLED because no drivers are currently available in your area.\n\nYour medical provider will contact you shortly to arrange alternative transportation or reschedule your visit."
MessageAppCanceledNoDriverMemberTitle = "No drivers available"
MessageAppCanceledNoDriverDispatcher = "The member's ride to a %s visit to %s on %s has been CANCELLED because no drivers are currently available near the pickup area.\n\nPlease contact member to arrange alternative transportation or reschedule member visit.\n\nVISIT: %s"
MessageAppCanceledNoDriverDispatcherTitle = "No drivers available"
MessageSMSCanceledMember = "Your scheduled ride has been CANCELLED by our transportation partner, Lyft, because of a technical problem with their system.\n\nWe will attempt to schedule a NEW ride for your %s visit and notify you when your NEW ride has been scheduled.\n\nVISIT: %s"
MessageSMSCanceledMemberTitle = "Your Ride has been Canceled"
MessageSMSCanceledDispatcher = "The member's scheduled ride has been CANCELLED by our transportation partner, Lyft, because of a technical problem with their system.\n\nWe will attempt to schedule a NEW ride for member's %s visit and notify you when a NEW scheduled has been scheduled.\n\nVISIT: %s"
MessageSMSCanceledDispatcherTitle = "Ride for %s Canceled"
MessageEmailCanceledMember = "Your scheduled ride has been CANCELLED by our transportation partner, Lyft, because of a technical problem with their system.\n\nWe will attempt to schedule a NEW ride for your %s visit and notify you when your NEW ride has been scheduled.\n\nVISIT: %s"
MessageEmailCanceledMemberTitle = "Your Ride has been Canceled"
MessageEmailCanceledDispatcher = "The member's scheduled ride has been CANCELLED by our transportation partner, Lyft, because of a technical problem with their system.\n\nWe will attempt to schedule a NEW ride for member's %s visit and notify you when a NEW scheduled has been scheduled.\n\nVISIT: %s"
MessageEmailCanceledDispatcherTitle = "Ride for %s Canceled"
MessageAppCanceledMember = "Your scheduled ride has been CANCELLED by our transportation partner, Lyft, because of a technical problem with their system.\n\nWe will attempt to schedule a NEW ride for your %s visit and notify you when your NEW ride has been scheduled.\n\nVISIT: %s"
MessageAppCanceledMemberTitle = "Canceled by Member"
MessageAppCanceledDispatcher = "The member's scheduled ride has been CANCELLED by our transportation partner, Lyft, because of a technical problem with their system.\n\nWe will attempt to schedule a NEW ride for member's %s visit and notify you when a NEW scheduled has been scheduled.\n\nVISIT: %s"
MessageAppCanceledDispatcherTitle = "Canceled by Member"
)

View File

@@ -0,0 +1,230 @@
package applicationservice
import (
"fmt"
"strconv"
"strings"
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
"bitbucket.org/nemt/nemt-portal-api/application/third/npd/npdmodel"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/domain/service"
"github.com/pquerna/ffjson/ffjson"
)
// providerService holds methods to provider application service
type organizationService struct {
svc *service.Service
mapEntity *entitymapping.Mapper
}
// newProviderService returns a providerService instance
func newOrganizationService(svc *service.Service, mapper *entitymapping.Mapper) *organizationService {
return &organizationService{
svc: svc,
mapEntity: mapper,
}
}
func (s *organizationService) GetAllTypes() ([]viewmodel.OrganizationType, error) {
result, err := s.svc.Organization.GetAllTypes()
if err != nil {
return nil, err
}
return s.mapEntity.Organization.ToOrganizationTypeModelSlice(result), nil
}
func (s *organizationService) GetByType(organizationTypeKey string) ([]viewmodel.Organization, error) {
result, err := s.svc.Organization.GetByType(organizationTypeKey)
if err != nil {
return nil, err
}
return s.mapEntity.Organization.ToOrganizationModelSlice(result), nil
}
func (s *organizationService) GetByUUID(organizationUUID string) (viewmodel.Organization, error) {
result, err := s.svc.Organization.GetByUUID(organizationUUID)
if err != nil {
return viewmodel.Organization{}, err
}
return s.mapEntity.Organization.ToOrganizationModel(result), nil
}
func (s *organizationService) GetByName(name string, searchType string) ([]viewmodel.Organization, error) {
result, err := s.svc.Organization.GetByName(name, searchType)
if err != nil {
return nil, err
}
return s.mapEntity.Organization.ToOrganizationModelSlice(result), nil
}
func (s *organizationService) SetParentOrganization(organizationUUID string, parentOrganizationUUID string) (viewmodel.Organization, error) {
child, err := s.svc.Organization.GetByUUID(organizationUUID)
if err != nil {
return viewmodel.Organization{}, err
}
parent, err := s.svc.Organization.GetByUUID(parentOrganizationUUID)
if err != nil {
return viewmodel.Organization{}, err
}
if err := s.svc.Organization.SetParentOrganization(child.ID, parent.ID); err != nil {
return viewmodel.Organization{}, err
}
return s.GetByUUID(organizationUUID)
}
func (s *organizationService) InactivateOrganizationAddress(organizationUUID string, address viewmodel.OrganizationAddress) error {
entityAddress := s.mapEntity.Organization.ToOrganizationAddressEntity(address)
entityAddress.Organization = &entity.Organization{
UUID: organizationUUID,
}
user, err := s.svc.Users.GetByUUID(address.UpdatedUser.ID, "")
if err != nil {
return err
}
entityAddress.UpdatedUser = user
if err := s.svc.Organization.InactivateOrganizationAddress(entityAddress); err != nil {
return err
} else {
return nil
}
}
func (s *organizationService) SetOrganizationAddress(organizationUUID string, address viewmodel.OrganizationAddress) (viewmodel.OrganizationAddress, error) {
entityAddress := s.mapEntity.Organization.ToOrganizationAddressEntity(address)
entityAddress.Organization = &entity.Organization{
UUID: organizationUUID,
}
user, err := s.svc.Users.GetByUUID(address.CreatedUser.ID, "")
if err != nil {
return viewmodel.OrganizationAddress{}, err
}
entityAddress.CreatedUser = user
entityAddress.UpdatedUser = user
entityAddress, err = s.svc.Organization.SetOrganizationAddress(entityAddress)
if err != nil {
return viewmodel.OrganizationAddress{}, err
}
return s.mapEntity.Organization.ToOrganizationAddressModel(entityAddress), nil
}
func (s *organizationService) InactivateOrganizationContact(organizationUUID string, contact viewmodel.OrganizationContact) error {
entityContact := s.mapEntity.Organization.ToOrganizationContactEntity(contact)
entityContact.Organization = &entity.Organization{
UUID: organizationUUID,
}
user, err := s.svc.Users.GetByUUID(contact.CreatedUser.ID, "")
if err != nil {
return err
}
entityContact.UpdatedUser = user
if err := s.svc.Organization.InactivateOrganizationContact(entityContact); err != nil {
return err
} else {
return nil
}
}
func (s *organizationService) SetOrganizationContact(organizationUUID string, contact viewmodel.OrganizationContact) (viewmodel.OrganizationContact, error) {
entityContact := s.mapEntity.Organization.ToOrganizationContactEntity(contact)
entityContact.Organization = &entity.Organization{
UUID: organizationUUID,
}
user, err := s.svc.Users.GetByUUID(contact.CreatedUser.ID, "")
if err != nil {
return viewmodel.OrganizationContact{}, err
}
entityContact.CreatedUser = user
entityContact.UpdatedUser = user
entityContact, err = s.svc.Organization.SetOrganizationContact(entityContact)
if err != nil {
return viewmodel.OrganizationContact{}, err
}
return s.mapEntity.Organization.ToOrganizationContactModel(entityContact), nil
}
func (s *organizationService) AddOrganization(organization viewmodel.Organization, user viewmodel.User) (viewmodel.Organization, error) {
enOrg := s.mapEntity.Organization.ToOrganizationEntity(organization)
enUser := s.mapEntity.User.ToUserEntity(user)
author, err := s.svc.Users.GetByUUID(organization.Author.ID, "")
if err != nil {
return viewmodel.Organization{}, nil
}
enOrg.Author = author
enOrg.LastEditor = enOrg.Author
if organization.Reference != nil {
switch organization.Type.Key {
case "provider":
var provider npdmodel.ProviderResponse
bProvider, err := ffjson.Marshal(organization.Reference)
if err != nil {
fmt.Println("Error to marshal provider")
return viewmodel.Organization{}, nil
}
if err := ffjson.Unmarshal(bProvider, &provider); err != nil {
fmt.Println("Error to convert provider")
return viewmodel.Organization{}, nil
}
eProviders, err := s.svc.Provider.Save(s.mapEntity.Provider.ToProviderEntitySlice([]npdmodel.ProviderResponse{provider}), enUser)
if err != nil {
fmt.Println("Error to save provider")
return viewmodel.Organization{}, nil
}
respProvider := eProviders[0]
enOrg.ReferenceID = respProvider.ProviderID
lat, _ := strconv.ParseFloat(provider.Latitude, 64)
long, _ := strconv.ParseFloat(provider.Longitude, 64)
address := entity.OrganizationAddress{
InternalID: provider.MukID,
Name: "Main Address",
Address: fmt.Sprintf("%s %s - %s, %s (%s)", provider.StreetName1, provider.StreetName2, provider.CityName, provider.State, provider.ZipCode),
Latitude: lat,
Longitude: long,
CreatedUser: enOrg.Author,
UpdatedUser: enOrg.LastEditor,
}
enOrg.Addresses = append(enOrg.Addresses, address)
fmt.Println("Phone Number: ", provider.PhoneNumber)
if provider.PhoneNumber != "" {
formattedPhone := "+1" + strings.Replace(provider.PhoneNumber, "-", "", -1)
contact := entity.OrganizationContact{
Type: entity.ContactType{
Key: "phone",
},
Contact: formattedPhone,
Name: "Main Phone",
CreatedUser: enOrg.Author,
UpdatedUser: enOrg.LastEditor,
}
enOrg.Contacts = append(enOrg.Contacts, contact)
}
}
}
enOrg, err = s.svc.Organization.AddOrganization(enOrg)
if err != nil {
return viewmodel.Organization{}, nil
}
return s.GetByUUID(enOrg.UUID)
}

View File

@@ -0,0 +1,58 @@
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 profileService struct {
svc *service.Service
mapEntity *entitymapping.Mapper
}
// newProviderService returns a providerService instance
func newProfileService(svc *service.Service, mapper *entitymapping.Mapper) *profileService {
return &profileService{
svc: svc,
mapEntity: mapper,
}
}
func (s *profileService) GetAll() ([]viewmodel.Profile, error) {
result, err := s.svc.Profile.GetAll()
if err != nil {
return nil, err
}
return s.mapEntity.Profile.ToProfileModelSlice(result), nil
}
func (s *profileService) GetByKey(key string) (viewmodel.Profile, error) {
result, err := s.svc.Profile.GetByKey(key)
if err != nil {
return viewmodel.Profile{}, err
}
return s.mapEntity.Profile.ToProfileModel(result), nil
}
func (s *profileService) GetVisibles(visible bool) ([]viewmodel.Profile, error) {
result, err := s.svc.Profile.GetVisibles(visible)
if err != nil {
return nil, err
}
return s.mapEntity.Profile.ToProfileModelSlice(result), nil
}
func (s *profileService) GetByOrganizationType(organizationTypeKey string) ([]viewmodel.Profile, error) {
orgType, err := s.svc.Organization.GetTypeByKey(organizationTypeKey)
if err != nil {
return nil, err
}
result, err := s.svc.Profile.GetByOrganizationType(orgType.ID)
if err != nil {
return nil, err
}
return s.mapEntity.Profile.ToProfileModelSlice(result), nil
}

View File

@@ -0,0 +1,50 @@
package applicationservice
import (
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
"bitbucket.org/nemt/nemt-portal-api/application/third/npd/npdmodel"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain/service"
)
// providerService holds methods to provider application service
type providerService struct {
svc *service.Service
mapEntity *entitymapping.Mapper
}
// newProviderService returns a providerService instance
func newProviderService(svc *service.Service, mapper *entitymapping.Mapper) *providerService {
return &providerService{
svc: svc,
mapEntity: mapper,
}
}
func (s *providerService) Save(providers []npdmodel.ProviderResponse, user viewmodel.User) ([]viewmodel.ProviderResp, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
entities := s.mapEntity.Provider.ToProviderEntitySlice(providers)
result, err := s.svc.Provider.Save(entities, eUser)
if err != nil {
return nil, err
}
return s.mapEntity.Provider.ToProviderRespModelSlice(result), nil
}
func (s *providerService) GetAll(user viewmodel.User) ([]viewmodel.ProviderResp, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
providers, err := s.svc.Provider.GetAll(eUser)
if err != nil {
return nil, err
}
return s.mapEntity.Provider.ToProviderRespModelSlice(providers), nil
}
func (s *providerService) Get(query string, lat float64, long float64, distance int64, planCode string, productID string, mukID string, internalID string, sort string, user viewmodel.User) ([]viewmodel.ProviderResp, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
providers, err := s.svc.Provider.Get(query, lat, long, distance, planCode, productID, mukID, internalID, sort, eUser)
if err != nil {
return nil, err
}
return s.mapEntity.Provider.ToProviderRespModelSlice(providers), nil
}

View File

@@ -0,0 +1,420 @@
package applicationservice
import (
"time"
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/domain/service"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
// rideService holds methods to user application service
type rideService struct {
svc *service.Service
mapEntity *entitymapping.Mapper
}
// newUserService returns a userService instance
func newRideService(svc *service.Service, mapper *entitymapping.Mapper) *rideService {
return &rideService{
svc: svc,
mapEntity: mapper,
}
}
func (s *rideService) UpdateNewRide(ride viewmodel.Ride, lyftRide viewmodel.RideRequest, user viewmodel.User) (viewmodel.Ride, error) {
webhookModel := viewmodel.WebhookResponse{
Ride: ride,
Event: lyftRide,
}
webhook := s.mapEntity.Ride.ToWebhookEntity(webhookModel)
eUser := s.mapEntity.User.ToUserEntity(user)
oldRide, err := s.svc.Rides.GetByUUID(ride.UUID, eUser)
if err != nil {
return viewmodel.Ride{}, err
}
requestMS := (oldRide.PickupTime.UnixNano() / int64(time.Millisecond))
generateDate := time.Now()
generateMS := (generateDate.UnixNano() / int64(time.Millisecond))
if webhook.Ride.RequestDate == nil {
webhook.Ride.RequestDate = oldRide.PickupTime
}
if webhook.Ride.RequestMiliseconds == nil {
webhook.Ride.RequestMiliseconds = &requestMS
}
if webhook.Ride.GenerateDate == nil {
webhook.Ride.GenerateDate = &generateDate
}
if webhook.Ride.GenerateMiliseconds == nil {
webhook.Ride.GenerateMiliseconds = &generateMS
}
switch webhook.Ride.Status.Key {
case "scheduled":
webhook.Ride.Route.ETA = oldRide.PickupTime.UnixNano() / int64(time.Second)
case "accepted":
if lyftRide.Origin.ETASeconds != nil {
webhook.Ride.Route.ETA = *lyftRide.Origin.ETASeconds
} else {
webhook.Ride.Route.ETA = 0
}
case "arrived", "pickedUp":
if lyftRide.Destination.ETASeconds != nil {
webhook.Ride.Route.ETA = *lyftRide.Destination.ETASeconds
} else {
webhook.Ride.Route.ETA = 0
}
case "droppedOff":
webhook.Ride.Route.ETA = 0
}
webhook.Ride.Route.Duration = int64(time.Now().Sub(*oldRide.PickupTime).Seconds())
webhook.Ride.InternalID = lyftRide.RideID
webhook.Ride.ID = oldRide.ID
webhook.Ride.UUID = oldRide.UUID
webhook.Ride.Driver.ID = oldRide.Driver.ID
webhook.Ride.Passenger.ID = oldRide.Passenger.ID
webhook.Ride.Route.ID = oldRide.Route.ID
webhook.Ride.Type.ID = oldRide.Type.ID
webhook.Ride.User = oldRide.User
webhook.Ride.CreatedUser = oldRide.CreatedUser
webhook.Ride.Vehicle.ID = oldRide.Vehicle.ID
webhook.Ride.Visit = oldRide.Visit
webhook.Ride.VisitDate = oldRide.VisitDate
webhook.Ride.VisitTime = oldRide.VisitTime
//webhook.Ride.PickupTime = oldRide.PickupTime
entityRide, err := s.svc.Rides.Update(webhook)
if err != nil {
return viewmodel.Ride{}, err
}
return s.mapEntity.Ride.ToRideModel(entityRide), nil
}
func (s *rideService) Update(ride viewmodel.WebhookResponse) (viewmodel.Ride, error) {
webhook := s.mapEntity.Ride.ToWebhookEntity(ride)
oldRide, err := s.svc.Rides.GetByInternalID(ride.Event.RideID)
if err != nil {
oldRide, err = s.svc.Rides.GetByInternalPassengerID(*ride.Event.Passenger.UserID)
if err != nil {
return viewmodel.Ride{}, err
}
}
requestMS := (oldRide.PickupTime.UnixNano() / int64(time.Millisecond))
generateDate := time.Now()
generateMS := (generateDate.UnixNano() / int64(time.Millisecond))
if webhook.Ride.RequestDate == nil {
webhook.Ride.RequestDate = oldRide.PickupTime
}
if webhook.Ride.RequestMiliseconds == nil {
webhook.Ride.RequestMiliseconds = &requestMS
}
if webhook.Ride.GenerateDate == nil {
webhook.Ride.GenerateDate = &generateDate
}
if webhook.Ride.GenerateMiliseconds == nil {
webhook.Ride.GenerateMiliseconds = &generateMS
}
switch webhook.Ride.Status.Key {
case "scheduled":
webhook.Ride.Route.ETA = oldRide.PickupTime.UnixNano() / int64(time.Second)
case "accepted":
if ride.Event.Origin.ETASeconds != nil {
webhook.Ride.Route.ETA = *ride.Event.Origin.ETASeconds
} else {
webhook.Ride.Route.ETA = 0
}
case "arrived", "pickedUp":
if ride.Event.Destination.ETASeconds != nil {
webhook.Ride.Route.ETA = *ride.Event.Destination.ETASeconds
} else {
webhook.Ride.Route.ETA = 0
}
case "droppedOff":
webhook.Ride.Route.ETA = 0
}
webhook.Ride.Route.Duration = int64(time.Now().Sub(*oldRide.PickupTime).Seconds())
webhook.Ride.InternalID = ride.Event.RideID
webhook.Ride.ID = oldRide.ID
webhook.Ride.UUID = oldRide.UUID
webhook.Ride.Driver.ID = oldRide.Driver.ID
webhook.Ride.Passenger.ID = oldRide.Passenger.ID
webhook.Ride.Route.ID = oldRide.Route.ID
webhook.Ride.Type.ID = oldRide.Type.ID
webhook.Ride.User = oldRide.User
webhook.Ride.CreatedUser = oldRide.CreatedUser
webhook.Ride.Vehicle.ID = oldRide.Vehicle.ID
webhook.Ride.Visit = oldRide.Visit
webhook.Ride.VisitDate = oldRide.VisitDate
webhook.Ride.VisitTime = oldRide.VisitTime
webhook.Ride.PickupTime = oldRide.PickupTime
entityRide, err := s.svc.Rides.Update(webhook)
if err != nil {
return viewmodel.Ride{}, err
}
return s.mapEntity.Ride.ToRideModel(entityRide), nil
}
// Save a new ride
func (s *rideService) Save(ride viewmodel.RideRequest) (viewmodel.Ride, error) {
rideEntity := s.mapEntity.Ride.ToRideEntity(ride)
if ride.Visit.UUID == "" {
visit := entity.Visit{}
visit.User = rideEntity.User
visit.Pickup = rideEntity.Route.Origin
visit.Notes = &rideEntity.Note
visit.PickupDatetime = *rideEntity.PickupTime
visit.VisitDatetime = *rideEntity.VisitTime
visit.CreatedUser.UUID = ride.CreateUserUUID
visit.ExternalID = ride.VisitExternalID
visit.TripType = rideEntity.Visit.TripType
visit.ReturnDate = ride.ReturnTime
address, _ := s.svc.Users.GetAddressByUUID(rideEntity.Route.Destination.ID)
createdUser, err := s.svc.Users.GetByUUID(ride.CreateUserUUID, "")
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
if address.ID > 0 {
visit.DestinationAddressID = address.ID
provider, err := s.svc.Provider.GetByMukID(address.InternalID, createdUser)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
visit.Provider = provider
} else {
provider, err := s.svc.Provider.GetByMukID(rideEntity.Route.Destination.ID, createdUser)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
visit.Provider = provider
}
visit, err = s.svc.Visits.Create(visit)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
rideEntity.Visit = visit
} else {
user, err := s.svc.Users.GetByUUID(ride.CreateUserUUID, "")
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
visit, err := s.svc.Visits.GetByUUID(ride.Visit.UUID, user)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
rideEntity.Visit = visit
}
retVal, err := s.svc.Rides.Save(rideEntity)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
return s.mapEntity.Ride.ToRideModel(retVal), err
}
// GetAll returns a list of users
func (s *rideService) GetAll(user viewmodel.User) ([]viewmodel.Ride, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
retVal, err := s.svc.Rides.GetAll(eUser)
if err != nil {
return nil, errors.Wrap(err)
}
return s.mapEntity.Ride.ToRideModelSlice(retVal), err
}
// GetByUUID returns a specific Ride
func (s *rideService) GetByUUID(uuid string, user viewmodel.User) (viewmodel.Ride, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
retVal, err := s.svc.Rides.GetByUUID(uuid, eUser)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
if retVal.Visit.ID > 0 {
retVal.Visit, err = s.svc.Visits.GetByID(retVal.Visit.ID, eUser)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
}
return s.mapEntity.Ride.ToRideModel(retVal), err
}
func (s *rideService) GetByVisitUUID(visitUUID string, user viewmodel.User) ([]viewmodel.Ride, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
retVal, err := s.svc.Rides.GetByVisitUUID(visitUUID, eUser)
if err != nil {
return nil, errors.Wrap(err)
}
visit, err := s.svc.Visits.GetByUUID(visitUUID, eUser)
if err != nil {
return nil, errors.Wrap(err)
}
for i, _ := range retVal {
retVal[i].Visit = visit
}
return s.mapEntity.Ride.ToRideModelSlice(retVal), err
}
func (s *rideService) GetByVisitUUIDAndTripType(visitUUID string, tripTypeKey string, user viewmodel.User) (viewmodel.Ride, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
retVal, err := s.svc.Rides.GetByVisitUUIDAndTripType(visitUUID, tripTypeKey, eUser)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
visit, err := s.svc.Visits.GetByUUID(visitUUID, eUser)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
retVal.Visit = visit
return s.mapEntity.Ride.ToRideModel(retVal), err
}
// GetByUUID returns a specific Ride
func (s *rideService) GetByUUIDAndUserUUID(uuid string, user_uuid string) (viewmodel.Ride, error) {
retVal, err := s.svc.Rides.GetByUUIDAndUserUUID(uuid, user_uuid)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
if retVal.Visit.ID > 0 {
user, err := s.svc.Users.GetByID(retVal.CreatedUser.ID)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
retVal.Visit, err = s.svc.Visits.GetByID(retVal.Visit.ID, user)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
}
return s.mapEntity.Ride.ToRideModel(retVal), err
}
// GetByInternalID returns a specific Ride
func (s *rideService) GetByInternalID(internalID string) (viewmodel.Ride, error) {
retVal, err := s.svc.Rides.GetByInternalID(internalID)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
if retVal.Visit.ID > 0 {
user, err := s.svc.Users.GetByID(retVal.CreatedUser.ID)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
retVal.Visit, err = s.svc.Visits.GetByID(retVal.Visit.ID, user)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
}
return s.mapEntity.Ride.ToRideModel(retVal), err
}
// GetByUserID returns a list of rides for an user
func (s *rideService) GetByUserID(userID int64, user viewmodel.User) ([]viewmodel.Ride, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
retVal, err := s.svc.Rides.GetByUserID(userID, eUser)
if err != nil {
return []viewmodel.Ride{}, errors.Wrap(err)
}
return s.mapEntity.Ride.ToRideModelSlice(retVal), err
}
// UpdateStatus change the status of the ride
func (s *rideService) UpdateStatus(rideUUID string, status string) error {
err := s.svc.Rides.UpdateStatus(rideUUID, status)
if err != nil {
return errors.Wrap(err)
}
return nil
}
// GetByUserID returns a list of rides for an user
func (s *rideService) GetByUserUUID(userUUID string, user viewmodel.User) ([]viewmodel.Ride, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
retVal, err := s.svc.Rides.GetByUserUUID(userUUID, eUser)
if err != nil {
return []viewmodel.Ride{}, errors.Wrap(err)
}
return s.mapEntity.Ride.ToRideModelSlice(retVal), err
}
func (s *rideService) GetLastRideByPhoneNumber(phoneNumber string, notificationType string, status string) (viewmodel.Ride, error) {
// if notificationType == ""{
// notificationType = "message"
// }
if status == "" {
status = "sms"
}
notification, err := s.svc.Notification.GetLastNotificationFromPhoneNumber(notificationType, phoneNumber, status)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
user, err := s.svc.Users.GetByID(notification.CreatedUser.ID)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
retVal, err := s.svc.Rides.GetByID(notification.Ride.ID, user)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
if retVal.Visit.ID > 0 {
retVal.Visit, err = s.svc.Visits.GetByID(retVal.Visit.ID, user)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
}
return s.mapEntity.Ride.ToRideModel(retVal), err
}
func (s *rideService) GetLastRideByDriversNumber(phoneNumber string) (viewmodel.Ride, error) {
retVal, err := s.svc.Rides.GetLastRideByDriversNumber(phoneNumber)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
if retVal.Visit.ID > 0 {
user, err := s.svc.Users.GetByID(retVal.CreatedUser.ID)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
retVal.Visit, err = s.svc.Visits.GetByID(retVal.Visit.ID, user)
if err != nil {
return viewmodel.Ride{}, errors.Wrap(err)
}
}
return s.mapEntity.Ride.ToRideModel(retVal), err
}

View File

@@ -0,0 +1,149 @@
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/entity"
"bitbucket.org/nemt/nemt-portal-api/domain/service"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
// userService holds methods to user application service
type userService struct {
svc *service.Service
mapEntity *entitymapping.Mapper
}
// newUserService returns a userService instance
func newUserService(svc *service.Service, mapper *entitymapping.Mapper) *userService {
return &userService{
svc: svc,
mapEntity: mapper,
}
}
// GetAll returns a list of users
func (s *userService) GetAll(quantity int64, page int64) (retVal []viewmodel.User, err error) {
users, err := s.svc.Users.GetAll()
if err != nil {
return retVal, errors.Wrap(err)
}
return s.mapEntity.User.ToUserModelSlice(users), nil
}
// GetByID returns a specific user by its ID
func (s *userService) GetByID(id int64) (retVal viewmodel.User, err error) {
user, err := s.svc.Users.GetByID(id)
if err != nil {
return retVal, errors.Wrap(err)
}
return s.mapEntity.User.ToUserModel(user), nil
}
// GetByID returns a specific user by its ID
func (s *userService) GetByUUID(uuid string, profile string) (retVal viewmodel.User, err error) {
user, err := s.svc.Users.GetByUUID(uuid, profile)
if err != nil {
return retVal, errors.Wrap(err)
}
return s.mapEntity.User.ToUserModel(user), nil
}
// 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) {
user, err := s.svc.Users.FullLogin(loginType, key, pass, profile)
if err != nil {
return retVal, errors.Wrap(err)
}
return s.mapEntity.User.ToUserModel(user), nil
}
// Login returns a specific user by email and pass
func (s *userService) Login(email string, pass string) (retVal viewmodel.User, err error) {
user, err := s.svc.Users.Login(email, pass)
if err != nil {
return retVal, errors.Wrap(err)
}
return s.mapEntity.User.ToUserModel(user), nil
}
func (s *userService) Create(user viewmodel.User) (retVal viewmodel.User, err error) {
entity := s.mapEntity.User.ToUserEntity(user)
for i, _ := range entity.Organizations {
entity.Organizations[i], err = s.svc.Organization.GetByUUID(entity.Organizations[i].UUID)
if err != nil {
return retVal, err
}
}
entity, err = s.svc.Users.Create(entity)
if err != nil {
return retVal, errors.Wrap(err)
}
return s.mapEntity.User.ToUserModel(entity), nil
}
func (s *userService) CreateBulk(users []viewmodel.User) (retVal []viewmodel.User, err error) {
entities := s.mapEntity.User.ToUserEntitySlice(users)
organizations := make([]entity.Organization, 0)
for i, _ := range entities {
if i == 0 {
for o, _ := range entities[i].Organizations {
org, err := s.svc.Organization.GetByUUID(entities[i].Organizations[o].UUID)
if err != nil {
return nil, err
}
organizations = append(organizations, org)
}
}
entities[i].Organizations = organizations
}
entities, err = s.svc.Users.CreateBulk(entities)
if err != nil {
return nil, errors.Wrap(err)
}
return s.mapEntity.User.ToUserModelSlice(entities), nil
}
// GetUsersByProfile returns a list of users by profile
func (s *userService) GetUsersByProfile(profile string) (retVal []viewmodel.User, err error) {
users, err := s.svc.Users.GetUsersByProfile(profile)
if err != nil {
return retVal, errors.Wrap(err)
}
list := s.mapEntity.User.ToUserModelSlice(users)
return list, nil
}
func (s *userService) RemoveAddress(addressUUID string) error {
return s.svc.Users.RemoveAddress(addressUUID)
}
func (s *userService) SaveAddress(address viewmodel.Address) (retVal viewmodel.Address, err error) {
entity := s.mapEntity.Address.ToAddressEntity(address)
entity, err = s.svc.Users.SaveAddress(entity)
if err != nil {
return retVal, errors.Wrap(err)
}
return s.mapEntity.Address.ToAddressModel(entity), err
}
func (s *userService) GetContactType() (retVal []viewmodel.ContactType, err error) {
entity, err := s.svc.Users.GetContactType()
if err != nil {
return retVal, errors.Wrap(err)
}
return s.mapEntity.User.ToContactTypeModelSlice(entity), nil
}

View File

@@ -0,0 +1,38 @@
package applicationservice
import (
"math"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
)
// getTakeSkipPaging return the take and skip from page number and item quantity
func getTakeSkipPaging(quantity int64, page int64) (take int64, skip int64) {
if page < 1 {
page = 1
}
if quantity < 1 {
quantity = 10
} else if quantity > 1000 {
quantity = 1000
}
take = quantity // itens per page
skip = (page - 1) * quantity
return take, skip
}
// buildPaginatedResult returns a paginatedResult instance
func buildPaginatedResult(list interface{}, skip int64, take int64, totalRecords int64) viewmodel.PaginatedResult {
return viewmodel.PaginatedResult{
List: list,
Pagination: viewmodel.ReturnPagination{
CurrentPage: (skip / take) + 1,
RecordsPerPage: take,
TotalRecords: totalRecords,
TotalPages: int64(math.Ceil(float64(totalRecords) / float64(take))),
},
}
}

View File

@@ -0,0 +1,55 @@
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"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
// rideService holds methods to user application service
type visitService struct {
svc *service.Service
mapEntity *entitymapping.Mapper
}
// newUserService returns a userService instance
func newVisitService(svc *service.Service, mapper *entitymapping.Mapper) *visitService {
return &visitService{
svc: svc,
mapEntity: mapper,
}
}
// Save a new ride
func (s *visitService) Create(visit viewmodel.Visit) (viewmodel.Visit, error) {
entity := s.mapEntity.Visit.ToVisitEntity(visit)
retVal, err := s.svc.Visits.Create(entity)
if err != nil {
return viewmodel.Visit{}, errors.Wrap(err)
}
return s.mapEntity.Visit.ToVisitModel(retVal), err
}
// Save a new ride
func (s *visitService) GetAll(user viewmodel.User) ([]viewmodel.Visit, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
retVal, err := s.svc.Visits.GetAll(eUser)
if err != nil {
return nil, errors.Wrap(err)
}
return s.mapEntity.Visit.ToVisitModelSlice(retVal), err
}
// Save a new ride
func (s *visitService) GetByUUID(visitUUID string, user viewmodel.User) (viewmodel.Visit, error) {
eUser := s.mapEntity.User.ToUserEntity(user)
retVal, err := s.svc.Visits.GetByUUID(visitUUID, eUser)
if err != nil {
return viewmodel.Visit{}, errors.Wrap(err)
}
return s.mapEntity.Visit.ToVisitModel(retVal), err
}

View File

@@ -0,0 +1,74 @@
package entitymapping
import (
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
// rideMapping has method to map ride entities to view models
type addressMapping struct {
mapper *Mapper
}
// ToVisitEntity maps a User entity to User view model
func (mapping *addressMapping) ToAddressEntity(item viewmodel.Address) entity.Address {
return entity.Address{
UUID: item.UUID,
InternalID: item.InternalID,
Name: item.Name,
Address: item.Address,
AddressType: mapping.ToParamEntity(item.AddressType),
Latitude: item.Latitude,
Longitude: item.Longitude,
Origin: mapping.ToParamEntity(item.Type),
User: mapping.mapper.User.ToUserEntity(item.User),
CreatedUser: entity.User{
UUID: item.CreatedUserUUID,
},
}
}
func (mapping *addressMapping) ToParamEntity(item string) entity.Params {
return entity.Params{
Key: item,
}
}
// ToVisitEntity maps a User entity to User view model
func (mapping *addressMapping) ToAddressModel(item entity.Address) viewmodel.Address {
return viewmodel.Address{
UUID: item.UUID,
InternalID: item.InternalID,
Name: item.Name,
Address: item.Address,
AddressType: item.AddressType.Key,
AddressTypeName: item.AddressType.Name,
Latitude: item.Latitude,
Longitude: item.Longitude,
Type: item.Origin.Key,
User: mapping.mapper.User.ToUserModel(item.User),
CreatedUserUUID: item.CreatedUser.UUID,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *addressMapping) ToAddressEntitySlice(list []viewmodel.Address) (retVal []entity.Address) {
retVal = make([]entity.Address, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToAddressEntity(item))
}
return retVal
}
// ToRideModelSlice maps a Ride entity slice to Ride view model slice
func (mapping *addressMapping) ToAddressModelSlice(list []entity.Address) (retVal []viewmodel.Address) {
retVal = make([]viewmodel.Address, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToAddressModel(item))
}
return retVal
}

View File

@@ -0,0 +1,51 @@
package entitymapping
import (
"strings"
"sync"
)
var (
instance *Mapper
once sync.Once
)
// Mapper has mapping methods to map entities to view models
type Mapper struct {
User *userMapping
Ride *rideMapping
Visit *visitMapping
Address *addressMapping
Provider *providerMapping
Notification *notificationMapping
Profile *profileMapping
Organization *organizationMapping
}
// New returns an EntityMapper for fluent mapping
func New() *Mapper {
once.Do(func() {
instance = &Mapper{}
instance.User = &userMapping{instance}
instance.Ride = &rideMapping{instance}
instance.Visit = &visitMapping{instance}
instance.Address = &addressMapping{instance}
instance.Provider = &providerMapping{instance}
instance.Notification = &notificationMapping{instance}
instance.Profile = &profileMapping{instance}
instance.Organization = &organizationMapping{instance}
})
return instance
}
// isEmpty returns the alternative option in case the first is empty
func ifEmpty(firstOption string, alternativeOption string) string {
if strings.TrimSpace(firstOption) == "" {
return alternativeOption
}
return firstOption
}

View File

@@ -0,0 +1,69 @@
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 notificationMapping struct {
mapper *Mapper
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *notificationMapping) ToNotificationEntitySlice(list []viewmodel.Notification) (retVal []entity.Notification) {
retVal = make([]entity.Notification, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToNotificationEntity(item))
}
return retVal
}
func (mapping *notificationMapping) ToNotificationEntity(model viewmodel.Notification) entity.Notification {
return entity.Notification{
UUID: model.UUID,
To: model.To,
From: model.From,
Type: model.Type,
Subject: model.Subject,
Message: model.Message,
Created: model.Created,
Ride: entity.Ride{
UUID: model.Ride.UUID,
},
User: mapping.mapper.User.ToUserEntity(model.User),
CreatedUser: mapping.mapper.User.ToUserEntity(model.CreatedUser),
Read: model.Read,
MessageType: model.MessageType,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *notificationMapping) ToNotificationModelSlice(list []entity.Notification) (retVal []viewmodel.Notification) {
retVal = make([]viewmodel.Notification, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToNotificationModel(item))
}
return retVal
}
func (mapping *notificationMapping) ToNotificationModel(model entity.Notification) viewmodel.Notification {
return viewmodel.Notification{
UUID: model.UUID,
To: model.To,
From: model.From,
Type: model.Type,
Subject: model.Subject,
Message: model.Message,
Created: model.Created,
Ride: mapping.mapper.Ride.ToRideModel(model.Ride),
User: mapping.mapper.User.ToUserModel(model.User),
CreatedUser: mapping.mapper.User.ToUserModel(model.CreatedUser),
Read: model.Read,
MessageType: model.MessageType,
}
}

View File

@@ -0,0 +1,256 @@
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 organizationMapping struct {
mapper *Mapper
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *organizationMapping) ToOrganizationTypeEntitySlice(list []viewmodel.OrganizationType) (retVal []entity.OrganizationType) {
retVal = make([]entity.OrganizationType, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToOrganizationTypeEntity(item))
}
return retVal
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *organizationMapping) ToOrganizationEntitySlice(list []viewmodel.Organization) (retVal []entity.Organization) {
retVal = make([]entity.Organization, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToOrganizationEntity(item))
}
return retVal
}
func (mapping *organizationMapping) ToOrganizationEntity(model viewmodel.Organization) entity.Organization {
return entity.Organization{
ID: model.ID,
UUID: model.UUID,
Type: mapping.ToOrganizationTypeEntity(model.Type),
Name: model.Name,
Description: model.Description,
ReferenceID: model.ReferenceID,
ParentID: model.ParentID,
Main: model.Main,
Created: model.Created,
Updated: model.Updated,
Active: model.Active,
Blocked: model.Blocked,
Suspended: model.Suspended,
Author: mapping.mapper.User.ToUserEntity(model.Author),
LastEditor: mapping.mapper.User.ToUserEntity(model.LastEditor),
Contacts: mapping.ToOrganizationContactEntitySlice(model.Contacts),
Addresses: mapping.ToOrganizationAddressEntitySlice(model.Addresses),
ChildOrgs: mapping.ToOrganizationEntitySlice(model.ChildOrgs),
Parent: mapping.ToOrganizationEntityPointer(model.Parent),
}
}
func (mapping *organizationMapping) ToOrganizationEntityPointer(model *viewmodel.Organization) *entity.Organization {
if model != nil {
convertibleModel := *model
convertibleEntity := mapping.ToOrganizationEntity(convertibleModel)
return &convertibleEntity
} else {
return nil
}
}
func (mapping *organizationMapping) ToOrganizationModelPointer(model *entity.Organization) *viewmodel.Organization {
if model != nil {
convertibleModel := *model
convertibleEntity := mapping.ToOrganizationModel(convertibleModel)
return &convertibleEntity
} else {
return nil
}
}
func (mapping *organizationMapping) ToOrganizationTypeEntity(model viewmodel.OrganizationType) entity.OrganizationType {
return entity.OrganizationType{
ID: model.ID,
Name: model.Name,
Key: model.Key,
Description: model.Description,
Created: model.Created,
Updated: model.Updated,
}
}
func (mapping *organizationMapping) ToOrganizationTypeModelSlice(list []entity.OrganizationType) (retVal []viewmodel.OrganizationType) {
retVal = make([]viewmodel.OrganizationType, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToOrganizationTypeModel(item))
}
return retVal
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *organizationMapping) ToOrganizationModelSlice(list []entity.Organization) (retVal []viewmodel.Organization) {
retVal = make([]viewmodel.Organization, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToOrganizationModel(item))
}
return retVal
}
func (mapping *organizationMapping) ToOrganizationModel(model entity.Organization) viewmodel.Organization {
return viewmodel.Organization{
ID: model.ID,
UUID: model.UUID,
Type: mapping.ToOrganizationTypeModel(model.Type),
Name: model.Name,
Description: model.Description,
ReferenceID: model.ReferenceID,
ParentID: model.ParentID,
Main: model.Main,
Created: model.Created,
Updated: model.Updated,
Active: model.Active,
Blocked: model.Blocked,
Suspended: model.Suspended,
Author: mapping.mapper.User.ToUserModel(model.Author),
LastEditor: mapping.mapper.User.ToUserModel(model.LastEditor),
Contacts: mapping.ToOrganizationContactModelSlice(model.Contacts),
Addresses: mapping.ToOrganizationAddressModelSlice(model.Addresses),
ChildOrgs: mapping.ToOrganizationModelSlice(model.ChildOrgs),
Parent: mapping.ToOrganizationModelPointer(model.Parent),
}
}
func (mapping *organizationMapping) ToOrganizationTypeModel(model entity.OrganizationType) viewmodel.OrganizationType {
return viewmodel.OrganizationType{
ID: model.ID,
Name: model.Name,
Key: model.Key,
Description: model.Description,
Created: model.Created,
Updated: model.Updated,
}
}
func (mapping *organizationMapping) ToOrganizationContactModel(model entity.OrganizationContact) viewmodel.OrganizationContact {
return viewmodel.OrganizationContact{
ID: model.ID,
UUID: model.UUID,
Type: mapping.mapper.User.ToContactTypeModel(model.Type),
Contact: model.Contact,
Name: model.Name,
Description: model.Description,
Created: model.Created,
CreatedUser: mapping.mapper.User.ToUserModel(model.CreatedUser),
Updated: model.Updated,
UpdatedUser: mapping.mapper.User.ToUserModel(model.UpdatedUser),
Active: model.Active,
}
}
func (mapping *organizationMapping) ToOrganizationContactEntity(model viewmodel.OrganizationContact) entity.OrganizationContact {
return entity.OrganizationContact{
ID: model.ID,
UUID: model.UUID,
Type: mapping.mapper.User.ToContactTypeEntity(model.Type),
Contact: model.Contact,
Name: model.Name,
Description: model.Description,
Created: model.Created,
CreatedUser: mapping.mapper.User.ToUserEntity(model.CreatedUser),
Updated: model.Updated,
UpdatedUser: mapping.mapper.User.ToUserEntity(model.UpdatedUser),
Active: model.Active,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *organizationMapping) ToOrganizationContactModelSlice(list []entity.OrganizationContact) (retVal []viewmodel.OrganizationContact) {
retVal = make([]viewmodel.OrganizationContact, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToOrganizationContactModel(item))
}
return retVal
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *organizationMapping) ToOrganizationContactEntitySlice(list []viewmodel.OrganizationContact) (retVal []entity.OrganizationContact) {
retVal = make([]entity.OrganizationContact, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToOrganizationContactEntity(item))
}
return retVal
}
func (mapping *organizationMapping) ToOrganizationAddressModel(model entity.OrganizationAddress) viewmodel.OrganizationAddress {
return viewmodel.OrganizationAddress{
ID: model.ID,
UUID: model.UUID,
InternalID: model.InternalID,
Address: model.Address,
Name: model.Name,
Description: model.Description,
Latitude: model.Latitude,
Longitude: model.Longitude,
Created: model.Created,
CreatedUser: mapping.mapper.User.ToUserModel(model.CreatedUser),
Updated: model.Updated,
UpdatedUser: mapping.mapper.User.ToUserModel(model.UpdatedUser),
Active: model.Active,
}
}
func (mapping *organizationMapping) ToOrganizationAddressEntity(model viewmodel.OrganizationAddress) entity.OrganizationAddress {
return entity.OrganizationAddress{
ID: model.ID,
UUID: model.UUID,
InternalID: model.InternalID,
Address: model.Address,
Name: model.Name,
Description: model.Description,
Latitude: model.Latitude,
Longitude: model.Longitude,
Created: model.Created,
CreatedUser: mapping.mapper.User.ToUserEntity(model.CreatedUser),
Updated: model.Updated,
UpdatedUser: mapping.mapper.User.ToUserEntity(model.UpdatedUser),
Active: model.Active,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *organizationMapping) ToOrganizationAddressModelSlice(list []entity.OrganizationAddress) (retVal []viewmodel.OrganizationAddress) {
retVal = make([]viewmodel.OrganizationAddress, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToOrganizationAddressModel(item))
}
return retVal
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *organizationMapping) ToOrganizationAddressEntitySlice(list []viewmodel.OrganizationAddress) (retVal []entity.OrganizationAddress) {
retVal = make([]entity.OrganizationAddress, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToOrganizationAddressEntity(item))
}
return retVal
}

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 profileMapping struct {
mapper *Mapper
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *profileMapping) ToProfileEntitySlice(list []viewmodel.Profile) (retVal []entity.Profile) {
retVal = make([]entity.Profile, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToProfileEntity(item))
}
return retVal
}
func (mapping *profileMapping) ToProfileEntity(model viewmodel.Profile) entity.Profile {
return entity.Profile{
ID: model.ID,
Key: model.Key,
Name: model.Name,
Description: model.Description,
Created: model.Created,
Updated: model.Updated,
Active: model.Active,
Visible: model.Visible,
Blocked: model.Blocked,
Suspended: model.Suspended,
Organization: mapping.mapper.Organization.ToOrganizationEntity(model.Organization),
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *profileMapping) ToProfileModelSlice(list []entity.Profile) (retVal []viewmodel.Profile) {
retVal = make([]viewmodel.Profile, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToProfileModel(item))
}
return retVal
}
func (mapping *profileMapping) ToProfileModel(model entity.Profile) viewmodel.Profile {
return viewmodel.Profile{
ID: model.ID,
Key: model.Key,
Name: model.Name,
Description: model.Description,
Created: model.Created,
Updated: model.Updated,
Active: model.Active,
Visible: model.Visible,
Blocked: model.Blocked,
Suspended: model.Suspended,
Organization: mapping.mapper.Organization.ToOrganizationModel(model.Organization),
}
}

View File

@@ -0,0 +1,375 @@
package entitymapping
import (
"bitbucket.org/nemt/nemt-portal-api/application/third/npd/npdmodel"
"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 providerMapping struct {
mapper *Mapper
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *providerMapping) ToProviderRespEntitySlice(list []viewmodel.ProviderResp) (retVal []entity.Provider) {
retVal = make([]entity.Provider, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToProviderRespEntity(item))
}
return retVal
}
func (mapping *providerMapping) ToProviderRespEntity(item viewmodel.ProviderResp) entity.Provider {
return entity.Provider{
ProviderUUID: item.ProviderUUID,
InternalID: item.InternalID,
InternalSuffixID: item.InternalSuffixID,
MukID: item.MukID,
OrganizatioName: item.OrganizatioName,
Gender: item.Gender,
AcceptNewPatients: item.AcceptNewPatients,
Name: item.Name,
FirstName: item.FirstName,
MiddleName: item.MiddleName,
LastName: item.LastName,
Title: item.Title,
Distance: item.Distance,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *providerMapping) ToProviderRespModelSlice(list []entity.Provider) (retVal []viewmodel.ProviderResp) {
retVal = make([]viewmodel.ProviderResp, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToProviderRespModel(item))
}
return retVal
}
func (mapping *providerMapping) ToProviderRespModel(item entity.Provider) viewmodel.ProviderResp {
return viewmodel.ProviderResp{
ProviderUUID: item.ProviderUUID,
InternalID: item.InternalID,
InternalSuffixID: item.InternalSuffixID,
MukID: item.MukID,
OrganizatioName: item.OrganizatioName,
Gender: item.Gender,
AcceptNewPatients: item.AcceptNewPatients,
Name: item.Name,
FirstName: item.FirstName,
MiddleName: item.MiddleName,
LastName: item.LastName,
Title: item.Title,
Keys: mapping.ToProviderKeyModelSlice(item.Keys),
Address: mapping.ToProviderRespAddressModel(item.Address),
Distance: item.Distance,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *providerMapping) ToProviderKeyModelSlice(list []entity.ProviderKey) (retVal []viewmodel.ProviderKey) {
retVal = make([]viewmodel.ProviderKey, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToProviderKeyModel(item))
}
return retVal
}
func (mapping *providerMapping) ToProviderKeyModel(item entity.ProviderKey) viewmodel.ProviderKey {
return viewmodel.ProviderKey{
InternalID: item.InternalID,
InternalSuffixID: item.InternalSuffixID,
LocationSeqNumber: item.LocationSeqNumber,
PlanCode: item.PlanCode,
ProductID: item.ProductID,
TreatmentCategoryCode: item.TreatmentCategoryCode,
}
}
func (mapping *providerMapping) ToProviderRespAddressModel(item entity.ProviderAddress) viewmodel.ProviderAddress {
return viewmodel.ProviderAddress{
StreetAddress1: item.StreetAddress1,
StreetAddress2: item.StreetAddress2,
CityName: item.CityName,
State: item.State,
ZipCode: item.ZipCode,
Country: item.Country,
Latitude: item.Latitude,
Longitude: item.Longitude,
PhoneNumber: item.PhoneNumber,
}
}
func (mapping *providerMapping) ToProviderEntity(item npdmodel.ProviderResponse) entity.ProviderResponse {
return entity.ProviderResponse{
MukID: item.MukID,
FivePartKeyGroups: mapping.ToPartKeyGroupEntitySlice(item.FivePartKeyGroups),
OrgName: item.OrgName,
Gender: item.Gender,
AcceptNewPatients: item.AcceptNewPatients,
ProviderName: item.ProviderName,
FirstName: item.FirstName,
LastName: item.LastName,
MiddleName: item.MiddleName,
ProviderTitle: item.ProviderTitle,
StreetName1: item.StreetName1,
StreetName2: item.StreetName2,
CityName: item.CityName,
State: item.State,
ZipCode: item.ZipCode,
Country: item.Country,
Latitude: item.Latitude,
Longitude: item.Longitude,
PhoneNumber: item.PhoneNumber,
ProviderEntityName: item.ProviderEntityName,
ProviderEntityCode: item.ProviderEntityCode,
ProviderTypeCode: mapping.ToProviderTypeCodeEntitySlice(item.ProviderTypeCode),
Distance: item.Distance,
AvailabilityOfCost: item.AvailabilityOfCost,
TDDPhoneNumber: item.TDDPhoneNumber,
ExtendedOfficeHours: item.ExtendedOfficeHours,
ProviderCountyCode: item.ProviderCountyCode,
ProviderCountyName: item.ProviderCountyName,
HospitalAffiliationNames: mapping.ToHospitalAffiliationNamesEntitySlice(item.HospitalAffiliationNames),
ProviderAffiliationNumber: item.ProviderAffiliationNumber,
ProviderAffiliationName: item.ProviderAffiliationName,
LanguagesSpoken: mapping.ToLanguagesEntitySlice(item.LanguagesSpoken),
OfficeLanguagesSpoken: mapping.ToLanguagesEntitySlice(item.OfficeLanguagesSpoken),
MedSchool: item.MedSchool,
MedSchoolYear: item.MedSchoolYear,
Internship: item.Internship,
Residence: item.Residence,
Specialty1: item.Specialty1,
Specialty2: item.Specialty2,
Specialty3: item.Specialty3,
Specialty4: item.Specialty4,
Certification1: item.Certification1,
Certification2: item.Certification2,
Certification3: item.Certification3,
Certification4: item.Certification4,
}
}
func (mapping *providerMapping) ToProviderModel(item entity.ProviderResponse) npdmodel.ProviderResponse {
return npdmodel.ProviderResponse{
MukID: item.MukID,
FivePartKeyGroups: mapping.ToPartKeyGroupModelSlice(item.FivePartKeyGroups),
OrgName: item.OrgName,
Gender: item.Gender,
AcceptNewPatients: item.AcceptNewPatients,
ProviderName: item.ProviderName,
FirstName: item.FirstName,
LastName: item.LastName,
MiddleName: item.MiddleName,
ProviderTitle: item.ProviderTitle,
StreetName1: item.StreetName1,
StreetName2: item.StreetName2,
CityName: item.CityName,
State: item.State,
ZipCode: item.ZipCode,
Country: item.Country,
Latitude: item.Latitude,
Longitude: item.Longitude,
PhoneNumber: item.PhoneNumber,
ProviderEntityName: item.ProviderEntityName,
ProviderEntityCode: item.ProviderEntityCode,
ProviderTypeCode: mapping.ToProviderTypeCodeModelSlice(item.ProviderTypeCode),
Distance: item.Distance,
AvailabilityOfCost: item.AvailabilityOfCost,
TDDPhoneNumber: item.TDDPhoneNumber,
ExtendedOfficeHours: item.ExtendedOfficeHours,
ProviderCountyCode: item.ProviderCountyCode,
ProviderCountyName: item.ProviderCountyName,
HospitalAffiliationNames: mapping.ToHospitalAffiliationNamesModelSlice(item.HospitalAffiliationNames),
ProviderAffiliationNumber: item.ProviderAffiliationNumber,
ProviderAffiliationName: item.ProviderAffiliationName,
LanguagesSpoken: mapping.ToLanguagesModelSlice(item.LanguagesSpoken),
OfficeLanguagesSpoken: mapping.ToLanguagesModelSlice(item.OfficeLanguagesSpoken),
MedSchool: item.MedSchool,
MedSchoolYear: item.MedSchoolYear,
Internship: item.Internship,
Residence: item.Residence,
Specialty1: item.Specialty1,
Specialty2: item.Specialty2,
Specialty3: item.Specialty3,
Specialty4: item.Specialty4,
Certification1: item.Certification1,
Certification2: item.Certification2,
Certification3: item.Certification3,
Certification4: item.Certification4}
}
func (mapping *providerMapping) ToHospitalAffiliationNamesEntity(item npdmodel.HospitalAffiliationNames) entity.HospitalAffiliationNames {
return entity.HospitalAffiliationNames{
HospAffProvOrgName: item.HospAffProvOrgName,
}
}
func (mapping *providerMapping) ToHospitalAffiliationNamesModel(item entity.HospitalAffiliationNames) npdmodel.HospitalAffiliationNames {
return npdmodel.HospitalAffiliationNames{
HospAffProvOrgName: item.HospAffProvOrgName,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *providerMapping) ToHospitalAffiliationNamesEntitySlice(list []npdmodel.HospitalAffiliationNames) (retVal []entity.HospitalAffiliationNames) {
retVal = make([]entity.HospitalAffiliationNames, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToHospitalAffiliationNamesEntity(item))
}
return retVal
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *providerMapping) ToHospitalAffiliationNamesModelSlice(list []entity.HospitalAffiliationNames) (retVal []npdmodel.HospitalAffiliationNames) {
retVal = make([]npdmodel.HospitalAffiliationNames, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToHospitalAffiliationNamesModel(item))
}
return retVal
}
func (mapping *providerMapping) ToLanguagesEntity(item npdmodel.Languages) entity.Languages {
return entity.Languages{
Code: item.Code,
}
}
func (mapping *providerMapping) ToLanguagesModel(item entity.Languages) npdmodel.Languages {
return npdmodel.Languages{
Code: item.Code,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *providerMapping) ToLanguagesEntitySlice(list []npdmodel.Languages) (retVal []entity.Languages) {
retVal = make([]entity.Languages, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToLanguagesEntity(item))
}
return retVal
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *providerMapping) ToLanguagesModelSlice(list []entity.Languages) (retVal []npdmodel.Languages) {
retVal = make([]npdmodel.Languages, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToLanguagesModel(item))
}
return retVal
}
func (mapping *providerMapping) ToProviderTypeCodeEntity(item npdmodel.ProviderTypeCode) entity.ProviderTypeCode {
return entity.ProviderTypeCode{
Code: item.Code,
}
}
func (mapping *providerMapping) ToProviderTypeCodeModel(item entity.ProviderTypeCode) npdmodel.ProviderTypeCode {
return npdmodel.ProviderTypeCode{
Code: item.Code,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *providerMapping) ToProviderTypeCodeEntitySlice(list []npdmodel.ProviderTypeCode) (retVal []entity.ProviderTypeCode) {
retVal = make([]entity.ProviderTypeCode, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToProviderTypeCodeEntity(item))
}
return retVal
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *providerMapping) ToProviderTypeCodeModelSlice(list []entity.ProviderTypeCode) (retVal []npdmodel.ProviderTypeCode) {
retVal = make([]npdmodel.ProviderTypeCode, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToProviderTypeCodeModel(item))
}
return retVal
}
func (mapping *providerMapping) ToPartKeyGroupEntity(item npdmodel.PartKeyGroup) entity.PartKeyGroup {
return entity.PartKeyGroup{
ProviderNum: item.ProviderNum,
ProviderNumSuffix: item.ProviderNumSuffix,
LocationSeqNum: item.LocationSeqNum,
PlanCode: item.PlanCode,
ProductID: item.ProductID,
TreatmentCategoryCode: item.TreatmentCategoryCode,
}
}
func (mapping *providerMapping) ToPartKeyGroupModel(item entity.PartKeyGroup) npdmodel.PartKeyGroup {
return npdmodel.PartKeyGroup{
ProviderNum: item.ProviderNum,
ProviderNumSuffix: item.ProviderNumSuffix,
LocationSeqNum: item.LocationSeqNum,
PlanCode: item.PlanCode,
ProductID: item.ProductID,
TreatmentCategoryCode: item.TreatmentCategoryCode,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *providerMapping) ToPartKeyGroupEntitySlice(list []npdmodel.PartKeyGroup) (retVal []entity.PartKeyGroup) {
retVal = make([]entity.PartKeyGroup, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToPartKeyGroupEntity(item))
}
return retVal
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *providerMapping) ToPartKeyGroupModelSlice(list []entity.PartKeyGroup) (retVal []npdmodel.PartKeyGroup) {
retVal = make([]npdmodel.PartKeyGroup, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToPartKeyGroupModel(item))
}
return retVal
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *providerMapping) ToProviderEntitySlice(list []npdmodel.ProviderResponse) (retVal []entity.ProviderResponse) {
retVal = make([]entity.ProviderResponse, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToProviderEntity(item))
}
return retVal
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *providerMapping) ToProviderModelSlice(list []entity.ProviderResponse) (retVal []npdmodel.ProviderResponse) {
retVal = make([]npdmodel.ProviderResponse, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToProviderModel(item))
}
return retVal
}

View File

@@ -0,0 +1,254 @@
package entitymapping
import (
"time"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
// rideMapping has method to map ride entities to view models
type rideMapping struct {
mapper *Mapper
}
func (mapping *rideMapping) ToRideModel(item entity.Ride) viewmodel.Ride {
return viewmodel.Ride{
User: mapping.mapper.User.ToUserModel(item.User),
Status: mapping.ToRideStatusModel(item.Status),
Type: mapping.ToRideTypeModel(item.Type),
UUID: item.UUID,
Note: item.Note,
Driver: mapping.ToDriverUserModel(item.Driver),
Passenger: mapping.ToPassengerUserModel(item.Passenger),
Vehicle: mapping.ToVehicleModel(item.Vehicle),
Route: mapping.ToRouteModel(item.Route),
PickupTime: item.PickupTime,
VisitDate: item.VisitDate,
VisitTime: item.VisitTime,
InternalID: item.InternalID,
Visit: mapping.mapper.Visit.ToVisitModel(item.Visit),
CreatedUser: mapping.mapper.User.ToUserModel(item.CreatedUser),
CreateAt: item.Created,
UpdateAt: item.Updated,
TripType: mapping.mapper.Visit.ToTripTypeModel(item.TripType),
}
}
func (mapping *rideMapping) ToRideInternalEntity(item viewmodel.Ride) entity.Ride {
return entity.Ride{
User: mapping.mapper.User.ToUserEntity(item.User),
UUID: item.UUID,
Note: item.Note,
PickupTime: item.PickupTime,
VisitDate: item.VisitDate,
VisitTime: item.VisitTime,
InternalID: item.InternalID,
TripType: mapping.mapper.Visit.ToTripTypeEntity(item.TripType),
}
}
func (mapping *rideMapping) ToRouteModel(item entity.RideRoute) viewmodel.RideRoute {
return viewmodel.RideRoute{
Origin: mapping.ToLocationModel(item.Origin),
Destination: mapping.ToLocationModel(item.Destination),
RouteKML: item.RouteKML,
ETA: item.ETA,
Distance: item.Distance,
Duration: item.Duration,
}
}
func (mapping *rideMapping) ToLocationModel(item entity.Location) viewmodel.Location {
return viewmodel.Location{
ID: item.ID,
Name: item.Name,
Address: item.Address,
Latitude: item.Latitude,
Longitude: item.Longitude,
}
}
func (mapping *rideMapping) ToVehicleModel(item entity.RideVehicle) viewmodel.Vehicle {
return viewmodel.Vehicle{
Color: item.Color,
Make: item.Make,
LicensePlate: item.LicensePlate,
ImageURL: item.ImageURL,
Year: item.Year,
LicensePlateState: item.LicensePlateState,
Model: item.Model,
}
}
func (mapping *rideMapping) ToDriverUserModel(item entity.RideDriver) viewmodel.UserLyft {
return viewmodel.UserLyft{
FirstName: item.Name,
ImageURL: item.ImageURL,
PhoneNumber: item.PhoneNumber,
Rating: item.Rating,
}
}
func (mapping *rideMapping) ToPassengerUserModel(item entity.RidePassenger) viewmodel.UserLyft {
return viewmodel.UserLyft{
FirstName: item.FirstName,
LastName: item.LastName,
ImageURL: item.ImageURL,
PhoneNumber: item.PhoneNumber,
UserID: item.InternalID,
}
}
func (mapping *rideMapping) ToRideStatusModel(item entity.RideStatus) viewmodel.RideStatus {
return viewmodel.RideStatus{
Value: item.Value,
Key: item.Key,
}
}
func (mapping *rideMapping) ToRideTypeModel(item entity.RideType) viewmodel.RideType {
return viewmodel.RideType{
Value: item.Value,
Key: item.Key,
}
}
func (mapping *rideMapping) ToWebhookEntity(item viewmodel.WebhookResponse) entity.WebhookResponse {
occurredAt, _ := time.Parse(time.RFC3339Nano, item.OccurredAt)
return entity.WebhookResponse{
EventID: item.EventID,
HREF: item.HREF,
OccurredAt: occurredAt,
EventType: item.EventType,
Ride: mapping.ToRideEntity(item.Event),
}
}
// ToUserModel maps a User entity to User view model
func (mapping *rideMapping) ToRideEntity(item viewmodel.RideRequest) entity.Ride {
return entity.Ride{
User: entity.User{
UUID: item.UserUUID,
},
Status: mapping.ToRideStatusEntity(item),
Type: mapping.ToRideTypeEntity(item),
InternalID: item.RideID,
RequestDate: item.RequestAt,
RequestMiliseconds: item.RequestAtMS,
GenerateDate: item.GeneratedAt,
GenerateMiliseconds: item.GeneratedAtMS,
Note: item.Notes,
PrimetimePercentage: item.PrimetimePercentage,
Passenger: mapping.ToRidePassengerEntity(item),
Driver: mapping.ToRideDriverEntity(item),
Vehicle: mapping.ToRideVehicleEntity(item),
Route: mapping.ToRideRouteEntity(item),
PickupTime: item.PickupTime,
VisitDate: item.VisitDate,
VisitTime: item.VisitTime,
Visit: mapping.mapper.Visit.ToVisitEntity(item.Visit),
TripType: mapping.mapper.Visit.ToTripTypeEntity(item.TripType),
CreatedUser: entity.User{
UUID: item.CreateUserUUID,
},
}
}
func (mapping *rideMapping) ToRideRouteEntity(item viewmodel.RideRequest) entity.RideRoute {
return entity.RideRoute{
Origin: mapping.ToLocationEntity(item.Origin),
Destination: mapping.ToLocationEntity(item.Destination),
RouteKML: &item.RouteURL,
ETA: item.ETA,
Distance: item.Distance,
Duration: item.Duration,
}
}
func (mapping *rideMapping) ToLocationEntity(item viewmodel.Location) entity.Location {
return entity.Location{
ID: item.ID,
Name: item.Name,
Address: item.Address,
Latitude: item.Latitude,
Longitude: item.Longitude,
}
}
func (mapping *rideMapping) ToRideVehicleEntity(item viewmodel.RideRequest) entity.RideVehicle {
return entity.RideVehicle{
Color: item.Vehicle.Color,
Make: item.Vehicle.Make,
LicensePlate: item.Vehicle.LicensePlate,
LicensePlateState: item.Vehicle.LicensePlateState,
ImageURL: item.Vehicle.ImageURL,
Model: item.Vehicle.Model,
Year: item.Vehicle.Year,
}
}
func (mapping *rideMapping) ToRideDriverEntity(item viewmodel.RideRequest) entity.RideDriver {
return entity.RideDriver{
Name: item.Driver.FirstName,
ImageURL: item.Driver.ImageURL,
PhoneNumber: item.Driver.PhoneNumber,
Rating: item.Driver.Rating,
}
}
func (mapping *rideMapping) ToRidePassengerEntity(item viewmodel.RideRequest) entity.RidePassenger {
return entity.RidePassenger{
FirstName: item.Passenger.FirstName,
LastName: item.Passenger.LastName,
ImageURL: item.Passenger.ImageURL,
PhoneNumber: item.Passenger.PhoneNumber,
InternalID: item.Passenger.UserID,
}
}
func (mapping *rideMapping) ToRideStatusEntity(item viewmodel.RideRequest) entity.RideStatus {
return entity.RideStatus{
Key: item.Status,
}
}
func (mapping *rideMapping) ToRideTypeEntity(item viewmodel.RideRequest) entity.RideType {
return entity.RideType{
Key: item.RideType,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *rideMapping) ToRideEntitySlice(list []viewmodel.RideRequest) (retVal []entity.Ride) {
retVal = make([]entity.Ride, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToRideEntity(item))
}
return retVal
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *rideMapping) ToRideInternalEntitySlice(list []viewmodel.Ride) (retVal []entity.Ride) {
retVal = make([]entity.Ride, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToRideInternalEntity(item))
}
return retVal
}
// ToRideModelSlice maps a Ride entity slice to Ride view model slice
func (mapping *rideMapping) ToRideModelSlice(list []entity.Ride) (retVal []viewmodel.Ride) {
retVal = make([]viewmodel.Ride, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToRideModel(item))
}
return retVal
}

View File

@@ -0,0 +1,194 @@
package entitymapping
import (
"fmt"
"strings"
"time"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
// userMapping has method to map User entities to view models
type userMapping struct {
mapper *Mapper
}
// ToUserModel maps a User entity to User view model
func (mapping *userMapping) ToUserModel(item entity.User) viewmodel.User {
var birthDate *time.Time
if !item.BirthDate.IsZero() {
birthDate = &item.BirthDate
}
first := ""
last := ""
fullName := strings.Split(item.Name, " ")
if len(fullName) > 0 {
first = fullName[0]
if len(fullName) > 1 {
last = fullName[len(fullName)-1]
}
}
return viewmodel.User{
ID: item.UUID,
Name: item.Name,
First: first,
Last: last,
Email: &item.Email,
PhoneNumber: &item.PhoneNumber,
Gender: &item.Gender,
Member: &item.Member,
BirthDate: birthDate,
Active: item.Active,
Created: item.Created,
Updated: item.Updated,
Contacts: mapping.ToContactModelSlice(item.Contacts),
Rides: mapping.mapper.Ride.ToRideModelSlice(item.Rides),
Addresses: mapping.mapper.Address.ToAddressModelSlice(item.Addresses),
Profiles: mapping.mapper.Profile.ToProfileModelSlice(item.Profiles),
Organizations: mapping.mapper.Organization.ToOrganizationModelSlice(item.Organizations),
Types: mapping.mapper.Organization.ToOrganizationTypeModelSlice(item.Types),
}
}
// ToUserModelSlice maps a User entity slice to User view model slice
func (mapping *userMapping) ToUserModelSlice(list []entity.User) (retVal []viewmodel.User) {
retVal = make([]viewmodel.User, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToUserModel(item))
}
return retVal
}
// ToUserModel maps a User entity to User view model
func (mapping *userMapping) ToUserEntity(item viewmodel.User) entity.User {
user := entity.User{
UUID: item.ID,
Name: item.Name,
Pass: item.Pass,
Active: item.Active,
Created: item.Created,
Updated: item.Updated,
Contacts: mapping.ToContactEntitySlice(item.Contacts),
Profiles: mapping.mapper.Profile.ToProfileEntitySlice(item.Profiles),
Organizations: mapping.mapper.Organization.ToOrganizationEntitySlice(item.Organizations),
Types: mapping.mapper.Organization.ToOrganizationTypeEntitySlice(item.Types),
}
if user.Name == "" {
user.Name = fmt.Sprintf("%s %s", item.First, item.Last)
}
if item.Email != nil {
user.Email = *item.Email
}
if item.PhoneNumber != nil {
user.PhoneNumber = *item.PhoneNumber
}
if item.Gender != nil {
user.Gender = *item.Gender
}
if item.Member != nil {
user.Member = *item.Member
}
if item.BirthDate != nil {
user.BirthDate = *item.BirthDate
}
return user
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *userMapping) ToUserEntitySlice(list []viewmodel.User) (retVal []entity.User) {
retVal = make([]entity.User, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToUserEntity(item))
}
return retVal
}
// ToContactTypeEntity maps a Contact type entity to Contact Type view model
func (mapping *userMapping) ToContactTypeEntity(item viewmodel.ContactType) entity.ContactType {
return entity.ContactType{
Key: item.Key,
Value: item.Value,
}
}
// ToContactTypeEntitySlice maps a User entity slice to Contact Type view model slice
func (mapping *userMapping) ToContactTypeEntitySlice(list []viewmodel.ContactType) (retVal []entity.ContactType) {
retVal = make([]entity.ContactType, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToContactTypeEntity(item))
}
return retVal
}
// ToContactTypeModel maps a Contact type entity to Contact Type view model
func (mapping *userMapping) ToContactTypeModel(item entity.ContactType) viewmodel.ContactType {
return viewmodel.ContactType{
Key: item.Key,
Value: item.Value,
}
}
// ToContactTypeModelSlice maps a User entity slice to Contact Type view model slice
func (mapping *userMapping) ToContactTypeModelSlice(list []entity.ContactType) (retVal []viewmodel.ContactType) {
retVal = make([]viewmodel.ContactType, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToContactTypeModel(item))
}
return retVal
}
// ToContactModel maps a Contact entity to Contact view model
func (mapping *userMapping) ToContactModel(item entity.ContactInfo) viewmodel.Contact {
return viewmodel.Contact{
Type: mapping.ToContactTypeModel(item.Type),
Value: item.Value,
}
}
// ToContactModelSlice maps a Contact entity slice to Contact view model slice
func (mapping *userMapping) ToContactModelSlice(list []entity.ContactInfo) (retVal []viewmodel.Contact) {
retVal = make([]viewmodel.Contact, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToContactModel(item))
}
return retVal
}
// ToContactEntity maps a Contact entity to Contact view model
func (mapping *userMapping) ToContactEntity(item viewmodel.Contact) entity.ContactInfo {
return entity.ContactInfo{
Type: mapping.ToContactTypeEntity(item.Type),
Value: item.Value,
}
}
// ToContactEntitySlice maps a Contact entity slice to Contact view model slice
func (mapping *userMapping) ToContactEntitySlice(list []viewmodel.Contact) (retVal []entity.ContactInfo) {
retVal = make([]entity.ContactInfo, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToContactEntity(item))
}
return retVal
}

View File

@@ -0,0 +1,131 @@
package entitymapping
import (
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
// rideMapping has method to map ride entities to view models
type visitMapping struct {
mapper *Mapper
}
// ToVisitEntity maps a User entity to User view model
func (mapping *visitMapping) ToVisitEntity(item viewmodel.Visit) entity.Visit {
return entity.Visit{
UUID: item.UUID,
Status: mapping.ToVisitStatusEntity(item.Status),
User: mapping.mapper.User.ToUserEntity(item.User),
VisitDuration: item.VisitDuration,
VisitDatetime: item.VisitDatetime,
PickupDatetime: item.PickupDatetime,
Notes: item.Notes,
PickupAddressID: item.PickupAddressID,
DestinationAddressID: item.DestinationAddressID,
Pickup: mapping.mapper.Ride.ToLocationEntity(item.Pickup),
Provider: mapping.mapper.Provider.ToProviderRespEntity(item.Provider),
CreatedUser: mapping.mapper.User.ToUserEntity(item.CreatedUser),
Created: item.CreatedDate,
Updated: item.UpdatedDate,
ReturnDate: item.ReturnDate,
ExternalID: item.ExternalID,
TripType: mapping.ToTripTypeEntity(item.TripType),
Rides: mapping.mapper.Ride.ToRideInternalEntitySlice(item.Rides),
}
}
func (mapping *visitMapping) ToVisitStatusEntity(item viewmodel.VisitStatus) entity.VisitStatus {
return entity.VisitStatus{
Value: item.Value,
Key: item.Key,
}
}
// ToVisitEntity maps a User entity to User view model
func (mapping *visitMapping) ToVisitModel(item entity.Visit) viewmodel.Visit {
return viewmodel.Visit{
UUID: item.UUID,
Status: mapping.ToVisitStatusModel(item.Status),
User: mapping.mapper.User.ToUserModel(item.User),
VisitDuration: item.VisitDuration,
VisitDatetime: item.VisitDatetime,
PickupDatetime: item.PickupDatetime,
Notes: item.Notes,
PickupAddressID: item.PickupAddressID,
DestinationAddressID: item.DestinationAddressID,
Pickup: mapping.mapper.Ride.ToLocationModel(item.Pickup),
Provider: mapping.mapper.Provider.ToProviderRespModel(item.Provider),
CreatedUser: mapping.mapper.User.ToUserModel(item.CreatedUser),
CreatedDate: item.Created,
UpdatedDate: item.Updated,
ReturnDate: item.ReturnDate,
ExternalID: item.ExternalID,
TripType: mapping.ToTripTypeModel(item.TripType),
Rides: mapping.mapper.Ride.ToRideModelSlice(item.Rides),
}
}
func (mapping *visitMapping) ToVisitStatusModel(item entity.VisitStatus) viewmodel.VisitStatus {
return viewmodel.VisitStatus{
Value: item.Value,
Key: item.Key,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *visitMapping) ToVisitEntitySlice(list []viewmodel.Visit) (retVal []entity.Visit) {
retVal = make([]entity.Visit, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToVisitEntity(item))
}
return retVal
}
// ToRideModelSlice maps a Ride entity slice to Ride view model slice
func (mapping *visitMapping) ToVisitModelSlice(list []entity.Visit) (retVal []viewmodel.Visit) {
retVal = make([]viewmodel.Visit, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToVisitModel(item))
}
return retVal
}
func (mapping *visitMapping) ToTripTypeModel(item entity.TripType) viewmodel.TripType {
return viewmodel.TripType{
Value: item.Value,
Key: item.Key,
}
}
func (mapping *visitMapping) ToTripTypeEntity(item viewmodel.TripType) entity.TripType {
return entity.TripType{
Value: item.Value,
Key: item.Key,
}
}
// ToUserEntitySlice maps a User entity slice to User view model slice
func (mapping *visitMapping) ToTripTypeEntitySlice(list []viewmodel.TripType) (retVal []entity.TripType) {
retVal = make([]entity.TripType, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToTripTypeEntity(item))
}
return retVal
}
// ToRideModelSlice maps a Ride entity slice to Ride view model slice
func (mapping *visitMapping) ToTripTypeModelSlice(list []entity.TripType) (retVal []viewmodel.TripType) {
retVal = make([]viewmodel.TripType, 0)
for _, item := range list {
retVal = append(retVal, mapping.ToTripTypeModel(item))
}
return retVal
}

View File

@@ -0,0 +1,31 @@
package notificationservice
import (
"sync"
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
"bitbucket.org/nemt/nemt-portal-api/domain/contract"
"bitbucket.org/nemt/nemt-portal-api/domain/service"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
)
var (
instance *Service
once sync.Once
)
// Service holds the domain service repositories
type Service struct {
Twilio *twilioService
}
// New returns a new domain Service instance
func New(svc *service.Service, mapper *entitymapping.Mapper, cfg *config.Config, cache contract.CacheManager) *Service {
once.Do(func() {
instance = &Service{
Twilio: newTwilioService(svc, mapper, cfg, cache),
}
})
return instance
}

View File

@@ -0,0 +1,259 @@
package notificationservice
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"strings"
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain"
"bitbucket.org/nemt/nemt-portal-api/domain/contract"
"bitbucket.org/nemt/nemt-portal-api/domain/service"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
)
const (
twilioMessageURL = "https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json"
twilioNumbersURL = "https://api.twilio.com/2010-04-01/Accounts/%s/AvailablePhoneNumbers/US/Local.json"
twiliActualNumbersURL = "https://api.twilio.com/2010-04-01/Accounts/%s/IncomingPhoneNumbers.json"
)
// twilioService holds methods to twillio application service
type twilioService struct {
svc *service.Service
mapEntity *entitymapping.Mapper
cfg *config.Config
urlMessage string
urlNumber string
urlActualNumber string
cache contract.CacheManager
}
// newTwilioService returns a twilioService instance
func newTwilioService(svc *service.Service, mapper *entitymapping.Mapper, cfg *config.Config, cache contract.CacheManager) *twilioService {
return &twilioService{
svc: svc,
mapEntity: mapper,
cfg: cfg,
urlMessage: fmt.Sprintf(twilioMessageURL, cfg.Twilio.Account),
urlNumber: fmt.Sprintf(twilioNumbersURL, cfg.Twilio.Account),
urlActualNumber: fmt.Sprintf(twiliActualNumbersURL, cfg.Twilio.Account),
cache: cache,
}
}
func (s twilioService) GetProxyNumber(to string) (viewmodel.ProxyNumber, error) {
key := "proxy" + to
var number viewmodel.ProxyNumber
err := s.cache.GetStruct(key, &number)
if err != nil || err == domain.ErrCacheMiss {
return number, err
} else {
return number, nil
}
}
func (s twilioService) GetAvaliableNumbers(to string) (viewmodel.ListNumbers, error) {
if to != "" {
if strings.Contains(to, "+1") {
to = strings.Replace(to, "+1", "", -1)
}
area := to[0:3]
msgData := url.Values{}
msgData.Set("PhoneNumber", area)
client := &http.Client{}
req, _ := http.NewRequest("GET", s.urlActualNumber+"?"+msgData.Encode(), bytes.NewBuffer([]byte{}))
req.SetBasicAuth(s.cfg.Twilio.Account, s.cfg.Twilio.Token)
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error Twilio: ", err)
}
defer resp.Body.Close()
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
var data viewmodel.ListNumbers
decoder := json.NewDecoder(resp.Body)
err := decoder.Decode(&data)
if err != nil {
return viewmodel.ListNumbers{}, err
}
return data, nil
} else {
return viewmodel.ListNumbers{}, errors.New(resp.Status)
}
}
return viewmodel.ListNumbers{}, nil
}
func (s twilioService) GetAvaliableNewNumbers(to string) (viewmodel.ListNumbers, error) {
if to != "" {
if strings.Contains(to, "+1") {
to = strings.Replace(to, "+1", "", -1)
}
area := to[0:3]
msgData := url.Values{}
msgData.Set("AreaCode", area)
client := &http.Client{}
req, _ := http.NewRequest("GET", s.urlNumber+"?"+msgData.Encode(), bytes.NewBuffer([]byte{}))
req.SetBasicAuth(s.cfg.Twilio.Account, s.cfg.Twilio.Token)
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error Twilio: ", err)
}
defer resp.Body.Close()
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
var data viewmodel.ListNumbers
decoder := json.NewDecoder(resp.Body)
err := decoder.Decode(&data)
if err != nil {
return viewmodel.ListNumbers{}, err
}
return data, nil
} else {
return viewmodel.ListNumbers{}, errors.New(resp.Status)
}
}
return viewmodel.ListNumbers{}, nil
}
func (s twilioService) SaveNewNumber(number viewmodel.Number) (viewmodel.Number, error) {
phoneNumber := number.PhoneNumber
if strings.Contains(phoneNumber, "+1") {
phoneNumber = strings.Replace(phoneNumber, "+1", "", -1)
}
area := phoneNumber[0:3]
msgData := url.Values{}
msgData.Set("PhoneNumber", number.PhoneNumber)
msgData.Set("AreaCode", area)
msgData.Set("FriendlyName", number.FriendlyName)
msgData.Set("SmsApplicationSid", s.cfg.Twilio.TwiMLSID)
msgDataReader := *strings.NewReader(msgData.Encode())
client := &http.Client{}
req, _ := http.NewRequest("POST", s.urlActualNumber, &msgDataReader)
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.SetBasicAuth(s.cfg.Twilio.Account, s.cfg.Twilio.Token)
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error Twilio: ", err)
}
defer resp.Body.Close()
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
decoder := json.NewDecoder(resp.Body)
err := decoder.Decode(&number)
if err != nil {
return viewmodel.Number{}, err
}
return number, nil
} else {
return viewmodel.Number{}, errors.New(resp.Status)
}
}
func (s twilioService) GetValidNumber(from string, to string) (viewmodel.Number, error) {
list, err := s.GetAvaliableNumbers(to)
if err != nil {
return viewmodel.Number{}, err
}
if len(list.IncomingPhones) > 0 {
return list.IncomingPhones[0], nil
}
list, err = s.GetAvaliableNewNumbers(to)
if err != nil {
return viewmodel.Number{}, err
}
if len(list.AvailableNumbers) > 0 {
number, err := s.SaveNewNumber(list.AvailableNumbers[0])
if err != nil {
fmt.Println("Error on GetValidNumber: ", err.Error())
return viewmodel.Number{}, err
}
return number, nil
} else {
return viewmodel.Number{}, errors.New("No new number available")
}
}
func (s twilioService) GetNumber(from string, to string) (string, error) {
number, err := s.GetValidNumber(from, to)
if err != nil {
return from, err
}
return number.PhoneNumber, nil
}
func (s twilioService) SendSMS(from string, to string, message string) error {
if from == "" {
return errors.New("TwilioService.SendSMS: from parameter is mandatory")
}
if to == "" {
return errors.New("TwilioService.SendSMS: to parameter is mandatory")
}
if message == "" {
return errors.New("TwilioService.SendSMS: message parameter is mandatory")
}
senderNumber, err := s.GetNumber(from, to)
if err != nil {
return err
}
msgData := url.Values{}
msgData.Set("To", to)
msgData.Set("From", senderNumber)
msgData.Set("Body", message)
msgDataReader := *strings.NewReader(msgData.Encode())
client := &http.Client{}
req, _ := http.NewRequest("POST", s.urlMessage, &msgDataReader)
req.SetBasicAuth(s.cfg.Twilio.Account, s.cfg.Twilio.Token)
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error Twilio: ", err)
}
defer resp.Body.Close()
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
var data map[string]interface{}
decoder := json.NewDecoder(resp.Body)
err := decoder.Decode(&data)
if err != nil {
return err
}
} else {
fmt.Println("Error on Twilio Response: ", resp.Status)
return errors.New(resp.Status)
}
return nil
}

View File

@@ -0,0 +1,28 @@
package bcbsi
import (
"sync"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
)
var (
instance *Service
once sync.Once
)
// Service holds the domain service repositories
type Service struct {
BXE *bxeService
}
// New returns a new domain Service instance
func New(cfg *config.Config) *Service {
once.Do(func() {
instance = &Service{
BXE: newBXEService(cfg),
}
})
return instance
}

View File

@@ -0,0 +1,150 @@
package bcbsimodel
import (
"encoding/xml"
"time"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
)
func GetEnvelope(eligibility viewmodel.Eligibility) Envelope {
soapEnvelope := Envelope{}
soapEnvelope.Namespace = "http://schemas.xmlsoap.org/soap/envelope/"
soapEnvelope.Body.MemberEligibilityRequest = GetEligibilityRequest(eligibility)
soapEnvelope.Body.MemberEligibilityRequest.Namespace = "http://v30.bx.services.bcbsa.com/eligibility-ext"
return soapEnvelope
}
func GetEligibilityRequest(eligibility viewmodel.Eligibility) MemberEligibilityRequest {
retVal := MemberEligibilityRequest{}
retVal.Version.MajorVersion = 3
retVal.Version.MinorVersion = 0
retVal.QueryHeader.TimeSent = time.Now().Format("2006-01-02T15:04:05")
retVal.QueryHeader.TrackingID = eligibility.TrackingID
retVal.Query.PayerInfo.PayerID = eligibility.Payer.PayerID
retVal.Query.PayerInfo.PayerName = eligibility.Payer.PayerName
retVal.Query.ProviderInfo.ProviderID = eligibility.Provider.ProviderID
retVal.Query.ProviderInfo.ProviderNPI = eligibility.Provider.ProviderNPI
retVal.Query.ProviderInfo.Provider.Organization = eligibility.Provider.ProviderName
retVal.Query.ProviderInfo.Provider.Name.First = eligibility.Provider.Name.First
retVal.Query.ProviderInfo.Provider.Name.Last = eligibility.Provider.Name.Last
retVal.Query.ProviderInfo.Provider.Name.Middle = eligibility.Provider.Name.Middle
retVal.Query.SubscriberInfo.SubscriberID = eligibility.Subscriber.SubscriberID
retVal.Query.SubscriberInfo.PatientType = eligibility.Subscriber.PatientType
retVal.Query.SubscriberInfo.Name.First = eligibility.Subscriber.Name.First
retVal.Query.SubscriberInfo.Name.Last = eligibility.Subscriber.Name.Last
retVal.Query.SubscriberInfo.Name.Middle = eligibility.Subscriber.Name.Middle
retVal.Query.SubscriberInfo.DemographicInfo.DateOfBirth = eligibility.Subscriber.DemographicInfo.DateOfBirth.Format("20060102")
retVal.Query.SubscriberInfo.DemographicInfo.GenderCode = eligibility.Subscriber.DemographicInfo.Gender
var dependents []Dependent
for _, d := range eligibility.Subscriber.Dependents {
dependent := Dependent{}
dependent.PatientAccountNumber = d.PatientAccountNumber
dependent.DemographicInfo.DateOfBirth = d.DemographicInfo.DateOfBirth.Format("20060102")
dependent.DemographicInfo.GenderCode = d.DemographicInfo.Gender
dependent.Name.First = d.Name.First
dependent.Name.Last = d.Name.Last
dependent.Name.Middle = d.Name.Middle
dependents = append(dependents, dependent)
}
if len(dependents) == 0 {
dependents = append(dependents, Dependent{})
}
retVal.Query.SubscriberInfo.DependentInfo.Dependents = dependents
retVal.Query.ServiceInfo.DateOfService = eligibility.ServiceInfo.DateOfService.Format("20060102")
retVal.Query.ServiceInfo.ServiceTypeCodes.ServiceTypeCode = eligibility.ServiceInfo.ServiceTypeCodes
return retVal
}
type Envelope struct {
XMLName xml.Name `xml:"soap:Envelope"`
Body EnvelopeBody `xml:"soap:Body"`
Namespace string `xml:"xmlns:soap,attr"`
}
type EnvelopeBody struct {
MemberEligibilityRequest MemberEligibilityRequest `xml:"elig:MemberEligibilityRequest"`
}
type MemberEligibilityRequest struct {
Version Version `xml:"version"`
QueryHeader QueryHeader `xml:"elig:eligibility-benefits-query-header"`
Query Query `xml:"elig:eligibility-benefits-query"`
Namespace string `xml:"xmlns:elig,attr"`
}
type Version struct {
MajorVersion int64 `xml:"majorVersion"`
MinorVersion int64 `xml:"minorVersion"`
}
type QueryHeader struct {
TrackingID string `xml:"tracking-id"`
TimeSent string `xml:"time-sent"`
}
type Query struct {
PayerInfo PayerInfo `xml:"elig:payer-info"`
ProviderInfo ProviderInfo `xml:"elig:provider-info"`
SubscriberInfo SubscriberInfo `xml:"elig:subscriber-info"`
ServiceInfo ServiceInfo `xml:"elig:service-info"`
}
type ServiceInfo struct {
DateOfService string `xml:"elig:date-of-service"`
ServiceTypeCodes ServiceTypeCodes `xml:"elig:service-type-codes"`
}
type ServiceTypeCodes struct {
ServiceTypeCode []string `xml:"elig:service-type-code"`
}
type SubscriberInfo struct {
PatientType string `xml:"elig:patient-type"`
SubscriberID string `xml:"elig:subscriber-id"`
Name Name `xml:"elig:name"`
DemographicInfo DemographicInfo `xml:"elig:demographic-info"`
DependentInfo DependentInfo `xml:"elig:dependent-info"`
}
type DependentInfo struct {
Dependents []Dependent `xml:"elig:dependent"`
}
type Dependent struct {
PatientAccountNumber string `xml:"elig:patient-account-number"`
Name Name `xml:"elig:name"`
DemographicInfo DemographicInfo `xml:"elig:demographic-info"`
}
type DemographicInfo struct {
DateOfBirth string `xml:"elig:date-of-birth"`
GenderCode string `xml:"elig:gender-code"`
}
type ProviderInfo struct {
ProviderID string `xml:"elig:provider-id"`
ProviderNPI string `xml:"elig:provider-npi"`
Provider Provider `xml:"elig:provider-name"`
}
type Provider struct {
Organization string `xml:"organization"`
Name Name `xml:"elig:name"`
}
type Name struct {
First string `xml:"elig:first"`
Last string `xml:"elig:last"`
Middle string `xml:"elig:middle"`
}
type PayerInfo struct {
PayerName string `xml:"elig:payer-name"`
PayerID string `xml:"elig:payer-id"`
}

View File

@@ -0,0 +1,44 @@
package bcbsimodel
import (
"encoding/xml"
)
type EnvelopeResponse struct {
XMLName xml.Name `xml:"Envelope"`
Body EnvelopeBodyResponse `xml:"Body"`
}
type EnvelopeBodyResponse struct {
MemberEligibilityResponse MemberEligibilityResponse `xml:"MemberEligibilityResponse"`
}
type MemberEligibilityResponse struct {
Version Version `xml:"version" json:"-"`
QueryResult QueryResult `xml:"eligibility-benefits-query-results" json:"results"`
}
type QueryResult struct {
HIPPA271 HIPAA271 `xml:"vcml-271" json:"raw"`
QueryResultSummary QueryResultSummary `xml:"query-result-summary" json:"summary"`
}
type HIPAA271 struct {
T271 string `xml:"t271" json:"t271"`
}
type QueryResultSummary struct {
BenefitsFound bool `xml:"benefits-found" json:"benefits_found"`
ProcessingInfo ProcessingInfo `xml:"processing-info" json:"-"`
}
type ProcessingInfo struct {
Message string `xml:"message" json:"-"`
}
type EntityResponse struct {
EntityID int64 `json:"entity_id"`
ID string `json:"id"`
Name string `json:"name"`
Status bool `json:"status"`
}

View File

@@ -0,0 +1,126 @@
package bcbsi
import (
"bytes"
"crypto/md5"
"encoding/hex"
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
"github.com/pquerna/ffjson/ffjson"
"bitbucket.org/nemt/nemt-portal-api/application/third/eligibility/bcbsi/bcbsimodel"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
)
type bxeService struct {
cfg *config.Config
}
func newBXEService(cfg *config.Config) *bxeService {
return &bxeService{
cfg: cfg,
}
}
func (s bxeService) getSignature(APIKey string, secretKey string) string {
rawKey := fmt.Sprintf("%s%s%v", APIKey, secretKey, time.Now().Unix())
hasher := md5.New()
hasher.Write([]byte(rawKey))
key := hex.EncodeToString(hasher.Sum(nil))
return strings.ToLower(key)
}
func (s bxeService) GetPayerDetails(subscriberID string) ([]bcbsimodel.EntityResponse, error) {
apiKey := s.cfg.Blue365.APIKey
secretKey := s.cfg.Blue365.Secret
URL := s.cfg.Blue365.URL
prefix := subscriberID[:3]
client := &http.Client{}
req, _ := http.NewRequest("GET", URL+"/"+prefix, bytes.NewBuffer([]byte{}))
req.Header.Add("X-Api-Key", apiKey)
req.Header.Add("X-Signature", s.getSignature(apiKey, secretKey))
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error Blue365: ", err)
return nil, err
}
defer resp.Body.Close()
bReturn, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error Blue365: ", err)
return nil, err
}
var response []bcbsimodel.EntityResponse
err = ffjson.Unmarshal(bReturn, &response)
if err != nil {
fmt.Println("Error Blue365: ", err)
return nil, err
}
return response, nil
}
func (s bxeService) CheckEligibility(eligibility viewmodel.Eligibility) (bcbsimodel.MemberEligibilityResponse, error) {
payer, err := s.GetPayerDetails(eligibility.Subscriber.SubscriberID)
if err != nil {
return bcbsimodel.MemberEligibilityResponse{}, err
}
eligibility.Payer.PayerID = payer[0].ID
eligibility.Payer.PayerName = payer[0].Name
envelope := bcbsimodel.GetEnvelope(eligibility)
apiKey := s.cfg.BXE.APIKey
secretKey := s.cfg.BXE.Secret
bObj, err := xml.Marshal(envelope)
if err != nil {
return bcbsimodel.MemberEligibilityResponse{}, err
}
client := &http.Client{}
req, _ := http.NewRequest("POST", s.cfg.BXE.URL, bytes.NewBuffer(bObj))
req.Header.Add("Soapaction", "CheckEligibility")
req.Header.Add("Content-Type", "text/xml")
req.Header.Add("X-Api-Key", apiKey)
req.Header.Add("X-Signature", s.getSignature(apiKey, secretKey))
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error WebService: ", err)
return bcbsimodel.MemberEligibilityResponse{}, err
}
defer resp.Body.Close()
bReturn, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error WebService: ", err)
return bcbsimodel.MemberEligibilityResponse{}, err
}
sResponse := string(bReturn)
sResponse = strings.Replace(sResponse, "soapenv:Envelope", "Envelope", -1)
sResponse = strings.Replace(sResponse, "soapenv:Body", "Body", -1)
sResponse = strings.Replace(sResponse, "ns2:", "", -1)
var result bcbsimodel.EnvelopeResponse
err = xml.Unmarshal([]byte(sResponse), &result)
if err != nil {
fmt.Println("Error WebService: ", err)
return bcbsimodel.MemberEligibilityResponse{}, err
}
return result.Body.MemberEligibilityResponse, nil
}

View File

@@ -0,0 +1,28 @@
package npd
import (
"sync"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
)
var (
instance *Service
once sync.Once
)
// Service holds the domain service repositories
type Service struct {
Provider *providerService
}
// New returns a new domain Service instance
func New(cfg *config.Config) *Service {
once.Do(func() {
instance = &Service{
Provider: newProviderService(cfg),
}
})
return instance
}

View File

@@ -0,0 +1,124 @@
package npdmodel
type ProviderHeaderResponse struct {
ResultStatus string `json:"resultStatus"`
Count CountResponse `json:"counts"`
Providers []ProviderResponse `json:"providers"`
FacetFields []FacetField `json:"facetEntries"`
}
type CountResponse struct {
Total string `json:"total"`
Groups string `json:"groups"`
}
type FacetField struct {
Name string `json:"name"`
FacetEntries []map[string]string `json:"facetEntries"`
}
type ProviderResponse struct {
MukID string `json:"mukId"`
FivePartKeyGroups []PartKeyGroup `json:"fivePartKeyGroups"`
OrgName string `json:"orgName"`
Gender string `json:"gender"`
AcceptNewPatients string `json:"acceptNewPatients"`
ProviderName string `json:"providerName"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
MiddleName string `json:"middleName"`
ProviderTitle string `json:"providerTitle"`
StreetName1 string `json:"streetName_1"`
StreetName2 string `json:"streetName_2"`
CityName string `json:"cityName"`
State string `json:"state"`
ZipCode string `json:"zipCode"`
Country string `json:"country"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
PhoneNumber string `json:"phoneNumber"`
ProviderEntityName string `json:"providerEntityName"`
ProviderEntityCode string `json:"providerEntityCode"`
ProviderTypeCode []ProviderTypeCode `json:"providerTypeCode"`
Distance string `json:"distance"`
AvailabilityOfCost string `json:"availabilityOfCost"`
TDDPhoneNumber string `json:"tddPhoneNumber"`
ExtendedOfficeHours string `json:"extendedOfficeHours"`
ProviderCountyCode string `json:"providerCountyCode"`
ProviderCountyName string `json:"providerCountyName"`
HospitalAffiliationNames []HospitalAffiliationNames `json:"hospitalAffiliationNames"`
ProviderAffiliationNumber string `json:"providerAffiliationNumber"`
ProviderAffiliationName string `json:"providerAffiliationName"`
LanguagesSpoken []Languages `json:"languagesSpoken"`
OfficeLanguagesSpoken []Languages `json:"officeLanguagesSpoken"`
MedSchool string `json:"medSchool"`
MedSchoolYear string `json:"medSchoolYear"`
Internship string `json:"internship"`
Residence string `json:"residency"`
Specialty1 string `json:"specialty1"`
Specialty2 string `json:"specialty2"`
Specialty3 string `json:"specialty3"`
Specialty4 string `json:"specialty4"`
Certification1 string `json:"certification1"`
Certification2 string `json:"certification2"`
Certification3 string `json:"certification3"`
Certification4 string `json:"certification4"`
}
type HospitalAffiliationNames struct {
HospAffProvOrgName string `json:"hospAffProvOrgName"`
}
type Languages struct {
Code string `json:"code"`
}
type ProviderTypeCode struct {
Code string `json:"code"`
}
type PartKeyGroup struct {
ProviderNum string `json:"providerNum"`
ProviderNumSuffix string `json:"providerNumSuffix"`
LocationSeqNum string `json:"locationSeqNum"`
PlanCode string `json:"planCode"`
ProductID string `json:"productId"`
TreatmentCategoryCode string `json:"treatmentCategoryCode"`
}
// ProviderSearchParams entity data
type ProviderSearchParams struct {
Name string
AlphaPrefix string
SearchBy string
Specialty string
Languages string
OfficeLanguages string
Gender string
AcceptNewPatients string
TreatmentCategoryCode string
SummaryScore string
AvailabilityOfCost string
AvailabilityOfQuality string
ExtendedOfficeHours string
HospitalAffiliation string
ProviderAffiliation string
ProviderEntityName string
NameRange string
BluPhyRcgIndicator string
Latitude float64
Longitude float64
Distance int64
Offset int64
Limit int64
SortBy string
FacetAcceptNewPatients string
FacetGender string
FacetExtendedOfficeHours string
FacetProviderEntityName string
FacetSummaryScore string
FacetLanguage string
FacetOfficeLanguages string
FacetHospitalAffiliations string
FacetProviderAffiliations string
}

View File

@@ -0,0 +1,56 @@
package npd
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"github.com/pquerna/ffjson/ffjson"
"bitbucket.org/nemt/nemt-portal-api/application/third/npd/npdmodel"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
)
type providerService struct {
cfg *config.Config
}
func newProviderService(cfg *config.Config) *providerService {
return &providerService{
cfg: cfg,
}
}
func (c *providerService) GetProviders(searchParams npdmodel.ProviderSearchParams) (npdmodel.ProviderHeaderResponse, error) {
providerURL := "https://api-pve.bcbs.com/Providers/V30%s"
params := "?name=%s&alphaPrefix=BCB&lat=%v&long=%v&distance=%v&offset=%v&limit=%v&sortBy=%s&facetAcceptNewPatients=%s&facetGender=%s&facetExtendedOfficeHours=%s&facetProviderEntityName=%s&facetSummaryScore=%s&facetlanguage=%s&facetOfficelanguages=%s&facetHospitalAffiliations=%s&facetProviderAffiliations=%s"
params = fmt.Sprintf(params, url.QueryEscape(searchParams.Name), searchParams.Latitude, searchParams.Longitude, searchParams.Distance, searchParams.Offset, searchParams.Limit, url.QueryEscape(searchParams.SortBy), url.QueryEscape(searchParams.FacetAcceptNewPatients), url.QueryEscape(searchParams.FacetGender), url.QueryEscape(searchParams.FacetExtendedOfficeHours), url.QueryEscape(searchParams.FacetProviderEntityName), url.QueryEscape(searchParams.FacetSummaryScore), url.QueryEscape(searchParams.FacetLanguage), url.QueryEscape(searchParams.FacetOfficeLanguages), url.QueryEscape(searchParams.FacetHospitalAffiliations), url.QueryEscape(searchParams.FacetProviderAffiliations))
providerURL = fmt.Sprintf(providerURL, params)
req, err := http.NewRequest("GET", providerURL, nil)
if err != nil {
return npdmodel.ProviderHeaderResponse{}, err
}
req.Header.Add("X-Api-Key", "sv6fs4dyh8macvuyyzgqs45w")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return npdmodel.ProviderHeaderResponse{}, err
}
defer resp.Body.Close()
bObject, err := ioutil.ReadAll(resp.Body)
if err != nil {
return npdmodel.ProviderHeaderResponse{}, err
}
var providers npdmodel.ProviderHeaderResponse
if err := ffjson.Unmarshal(bObject, &providers); err != nil {
return npdmodel.ProviderHeaderResponse{}, err
}
return providers, nil
}

View File

@@ -0,0 +1,305 @@
package tncservice
import (
"bytes"
"context"
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
"net/http"
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
"bitbucket.org/nemt/nemt-portal-api/application/notificationservice"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain/service"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"github.com/lyft/lyft-go-sdk/lyft"
"github.com/pquerna/ffjson/ffjson"
"golang.org/x/oauth2"
"golang.org/x/oauth2/clientcredentials"
)
const (
lyftURL = "https://api.lyft.com/v1/"
)
// lyftService holds methods to lyft application service
type lyftService struct {
svc *service.Service
mapEntity *entitymapping.Mapper
client *lyft.APIClient
httpClient *http.Client
cfg *config.Config
notification *notificationservice.Service
lyftConfig clientcredentials.Config
refreshToken string
}
// newLyftProdService returns a lyftService instance with production info
func newLyftProdService(svc *service.Service, mapper *entitymapping.Mapper, cfg *config.Config, notificationService *notificationservice.Service) *lyftService {
config := clientcredentials.Config{
ClientID: cfg.LyftProd.Lyft.Client,
ClientSecret: cfg.LyftProd.Lyft.Secret,
TokenURL: "https://api.lyft.com/oauth/token",
Scopes: []string{"public", "privileged.rides.dispatch", "rides.read", "rides.request", "profile", "offline"},
}
httpClient := config.Client(context.Background())
return &lyftService{
svc: svc,
mapEntity: mapper,
client: lyft.NewAPIClient(httpClient, "nemt"),
httpClient: httpClient,
cfg: cfg,
notification: notificationService,
lyftConfig: config,
refreshToken: cfg.LyftProd.Lyft.RefreshToken,
}
}
// newLyftService returns a lyftService instance
func newLyftService(svc *service.Service, mapper *entitymapping.Mapper, cfg *config.Config, notificationService *notificationservice.Service) *lyftService {
config := clientcredentials.Config{
ClientID: cfg.Lyft.Client,
ClientSecret: cfg.Lyft.Secret,
TokenURL: "https://api.lyft.com/oauth/token",
Scopes: []string{"public", "privileged.rides.dispatch", "rides.read", "rides.request", "profile", "offline"},
}
httpClient := config.Client(context.Background())
return &lyftService{
svc: svc,
mapEntity: mapper,
client: lyft.NewAPIClient(httpClient, "nemt"),
httpClient: httpClient,
cfg: cfg,
notification: notificationService,
lyftConfig: config,
refreshToken: cfg.Lyft.RefreshToken,
}
}
func (s *lyftService) getToken() string {
token, err := s.lyftConfig.Token(context.Background())
if err != nil {
fmt.Println("Error to get token: ", err)
return ""
}
return "Bearer " + token.AccessToken
}
func (s *lyftService) setTokenHeader(req *http.Request) string {
type Token struct {
GrantType string `json:"grant_type"`
RefreshToken string `json:"refresh_token"`
}
token := Token{
GrantType: "refresh_token",
RefreshToken: s.refreshToken,
}
bObject, err := ffjson.Marshal(token)
if err != nil {
return ""
}
tokenReq, err := http.NewRequest("POST", s.lyftConfig.TokenURL, bytes.NewBuffer(bObject))
if err != nil {
return ""
}
tokenReq.Header.Set("Content-Type", "application/json")
tokenReq.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", s.lyftConfig.ClientID, s.lyftConfig.ClientSecret))))
tokenReq.Header.Add("cache-control", "no-cache")
resp, err := http.DefaultClient.Do(tokenReq)
if err != nil {
fmt.Println("Error to refresh token: ", err.Error())
return ""
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
var returnToken oauth2.Token
err = ffjson.Unmarshal(body, &returnToken)
if err != nil {
fmt.Println("Error to parse token: ", err.Error())
return ""
}
returnToken.SetAuthHeader(req)
return "Bearer " + returnToken.AccessToken
}
func (s *lyftService) GetRideDetails(rideRequest viewmodel.RideRequest) (viewmodel.RideRequest, error) {
url := lyftURL + "dispatches/" + rideRequest.RideID
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return viewmodel.RideRequest{}, err
}
s.setTokenHeader(req)
req.Header.Add("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return viewmodel.RideRequest{}, err
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
var raw viewmodel.RideRequest
err = ffjson.Unmarshal(body, &raw)
if err != nil {
return viewmodel.RideRequest{}, err
}
return raw, nil
}
func (s *lyftService) GetRideStatus(rideRequest viewmodel.RideRequest, param string) (viewmodel.RideRequest, error) {
params := make(map[string]string)
params["status"] = param
bObject, err := ffjson.Marshal(params)
if err != nil {
return viewmodel.RideRequest{}, err
}
fmt.Println("STATUS CHANGE REQUEST ON LYFT")
fmt.Println("Ride ID: ", rideRequest.RideID)
fmt.Println("Status: ", param)
url := lyftURL + "sandbox/dispatches/" + rideRequest.RideID
req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(bObject))
if err != nil {
return viewmodel.RideRequest{}, err
}
req.Header.Add("Content-Type", "application/json")
resp, err := s.httpClient.Do(req)
if err != nil {
return viewmodel.RideRequest{}, err
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("STATUS CHANGE RESPONSE ON LYFT")
fmt.Println(string(body))
var raw viewmodel.RideRequest
err = ffjson.Unmarshal(body, &raw)
if err != nil {
return viewmodel.RideRequest{}, err
}
rideRequest.Status = raw.Status
return s.GetRideDetails(rideRequest)
}
func (s *lyftService) CancelRide(rideRequest viewmodel.RideRequest) error {
finalURL := lyftURL + "dispatches/" + rideRequest.RideID + "/cancel"
req, err := http.NewRequest("POST", finalURL, bytes.NewBuffer([]byte{}))
if err != nil {
return err
}
s.setTokenHeader(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode == 204 || resp.StatusCode == 404 {
if err != nil {
fmt.Println("Error: ", err)
}
return nil
} else {
fmt.Println("Response Body: ", string(body))
raw := map[string]interface{}{}
err = ffjson.Unmarshal(body, &raw)
if err != nil {
return err
} else {
return errors.New(raw["error_description"].(string))
}
}
}
func (s *lyftService) RequestRide(rideRequest viewmodel.RideRequest) (viewmodel.RideRequest, error) {
bObject, err := ffjson.Marshal(rideRequest)
if err != nil {
return viewmodel.RideRequest{}, err
}
req, err := http.NewRequest("POST", lyftURL+"dispatches", bytes.NewBuffer(bObject))
if err != nil {
return viewmodel.RideRequest{}, err
}
s.setTokenHeader(req)
req.Header.Add("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return viewmodel.RideRequest{}, err
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
var raw viewmodel.RideRequest
err = ffjson.Unmarshal(body, &raw)
if err != nil {
return viewmodel.RideRequest{}, err
}
if raw.Error != "" {
fmt.Println("Error to call Lyft: ", raw.Error+" - "+raw.ErrorDescription)
return viewmodel.RideRequest{}, errors.New("Lyft Error: " + raw.Error + " - " + raw.ErrorDescription)
}
return s.GetRideDetails(raw)
}
func (s *lyftService) GetETA(lag float64, log float64, params map[string]interface{}) (interface{}, error) {
resp, _, err := s.client.PublicApi.GetETA(lag, log, params)
if err != nil {
return nil, err
}
return resp, nil
}
func (s *lyftService) GetCost(lag float64, log float64, params map[string]interface{}) (interface{}, error) {
resp, _, err := s.client.PublicApi.GetCost(lag, log, params)
if err != nil {
return nil, err
}
return resp, nil
}
func (s *lyftService) GetDrivers(lag float64, log float64) (interface{}, error) {
resp, _, err := s.client.PublicApi.GetDrivers(lag, log)
if err != nil {
return nil, err
}
return resp, nil
}
func (s *lyftService) GetTypes(lag float64, log float64, params map[string]interface{}) (interface{}, error) {
resp, _, err := s.client.PublicApi.GetRideTypes(lag, log, params)
if err != nil {
return nil, err
}
return resp, nil
}

View File

@@ -0,0 +1,33 @@
package tncservice
import (
"sync"
"bitbucket.org/nemt/nemt-portal-api/application/entitymapping"
"bitbucket.org/nemt/nemt-portal-api/application/notificationservice"
"bitbucket.org/nemt/nemt-portal-api/domain/service"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
)
var (
instance *Service
once sync.Once
)
// Service holds the domain service repositories
type Service struct {
Lyft *lyftService
LyftProd *lyftService
}
// New returns a new domain Service instance
func New(svc *service.Service, mapper *entitymapping.Mapper, cfg *config.Config, notificationService *notificationservice.Service) *Service {
once.Do(func() {
instance = &Service{
Lyft: newLyftService(svc, mapper, cfg, notificationService),
LyftProd: newLyftProdService(svc, mapper, cfg, notificationService),
}
})
return instance
}

View File

@@ -0,0 +1,15 @@
package viewmodel
type Address struct {
UUID string `json:"address_uuid,omitempty"`
InternalID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Address string `json:"address,omitempty"`
AddressType string `json:"address_type,omitempty"`
AddressTypeName string `json:"address_type_name,omitempty"`
Latitude float64 `json:"lat,omitempty"`
Longitude float64 `json:"lng,omitempty"`
Type string `json:"type,omitempty"`
User User `json:"user,omitempty"`
CreatedUserUUID string `json:"-"`
}

View File

@@ -0,0 +1,9 @@
package viewmodel
// AuthResponse has data from authentication routes
type AuthResponse struct {
Token string `json:"token"`
ValidTime int64 `json:"valid_time"`
ServerTime int64 `json:"server_time"`
User User `json:"user"`
}

View File

@@ -0,0 +1,55 @@
package viewmodel
import (
"time"
)
type Eligibility struct {
TrackingID string `json:"tracking_id,omitempty"`
Payer Payer `json:"payer,omitempty"`
Provider Provider `json:"provider,omitempty"`
Subscriber Subscriber `json:"subscriber,omitempty"`
ServiceInfo ServiceInfo `json:"service_info,omitempty"`
}
type Payer struct {
PayerID string `json:"payer_id,omitempty"`
PayerName string `json:"payer_name,omitempty"`
}
type Provider struct {
ProviderID string `json:"provider_id,omitempty"`
ProviderNPI string `json:"provider_npi,omitempty"`
ProviderName string `json:"provider_name,omitempty"`
Name Name `json:"name,omitempty"`
}
type Name struct {
First string `json:"first,omitempty"`
Last string `json:"last,omitempty"`
Middle string `json:"middle,omitempty"`
}
type Subscriber struct {
PatientType string `json:"patient_type,omitempty"`
SubscriberID string `json:"subscriber_id,omitempty"`
Name Name `json:"name,omitempty"`
DemographicInfo DemographicInfo `json:"demographic_info,omitempty"`
Dependents []Dependent `json:"dependents,omitempty"`
}
type DemographicInfo struct {
DateOfBirth time.Time `json:"date_of_birth,omitempty"`
Gender string `json:"gender,omitempty"`
}
type Dependent struct {
PatientAccountNumber string `json:"patient_account_number,omitempty"`
Name Name `json:"name,omitempty"`
DemographicInfo DemographicInfo `json:"demographic_info,omitempty"`
}
type ServiceInfo struct {
DateOfService time.Time `json:"date_of_service,omitempty"`
ServiceTypeCodes []string `json:"service_type_codes,omitempty"`
}

View File

@@ -0,0 +1,34 @@
package viewmodel
import "time"
type Notification struct {
UUID string `json:"uuid"`
To string `json:"to"`
From string `json:"from"`
Type string `json:"type"`
Subject string `json:"subject"`
Message string `json:"message"`
Ride Ride `json:"ride"`
User User `json:"user"`
CreatedUser User `json:"created_user"`
Created time.Time `json:"create_at"`
MessageType string `json:"message_type"`
Read bool `json:"read"`
}
type Message struct {
DeliveryID string `json:"id"`
NotificationID string `json:"nid"`
CreateDate time.Time `json:"date"`
Read bool `json:"readed"`
Content MessageContent `json:"content"`
}
type MessageContent struct {
Type string `json:"type"`
Subject string `json:"subject"`
Content string `json:"body,omitempty"`
Payload interface{} `json:"payload,omitempty"`
RedirectLink string `json:"redirect,omitempty"`
}

View File

@@ -0,0 +1,69 @@
package viewmodel
import (
"time"
)
type OrganizationType struct {
ID int64 `json:"-"`
Name string `json:"name"`
Key string `json:"key"`
Description string `json:"desc,omitempty"`
Created time.Time `json:"-"`
Updated time.Time `json:"-"`
}
type Organization struct {
ID int64 `json:"-"`
UUID string `json:"id"`
Type OrganizationType `json:"type"`
Name string `json:"name"`
Description string `json:"desc,omitempty"`
ReferenceID int64 `json:"-"`
ParentID int64 `json:"-"`
Main bool `json:"main"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Active bool `json:"active"`
Blocked bool `json:"blocked"`
Suspended bool `json:"suspended"`
Author User `json:"author"`
LastEditor User `json:"last_editor"`
Contacts []OrganizationContact `json:"contacts"`
Addresses []OrganizationAddress `json:"addresses"`
ChildOrgs []Organization `json:"childs,omitempty"`
Parent *Organization `json:"parent,omitempty"`
Reference interface{} `json:"reference,omitempty"`
}
type OrganizationContact struct {
ID int64 `json:"-"`
UUID string `json:"id"`
Organization *Organization `json:"organization,omitempty"`
Type ContactType `json:"type"`
Contact string `json:"contact"`
Name string `json:"name"`
Description string `json:"desc"`
Created time.Time `json:"created"`
CreatedUser User `json:"author"`
Updated time.Time `json:"updated"`
UpdatedUser User `json:"last_editor"`
Active bool `json:"active"`
}
type OrganizationAddress struct {
ID int64 `json:"-"`
UUID string `json:"id"`
Organization *Organization `json:"organization,omitempty"`
InternalID string `json:"internal_id"`
Name string `json:"name"`
Address string `json:"address"`
Description string `json:"desc"`
Latitude float64 `json:"lat"`
Longitude float64 `json:"long"`
Created time.Time `json:"created"`
CreatedUser User `json:"author"`
Updated time.Time `json:"updated"`
UpdatedUser User `json:"last_editor"`
Active bool `json:"active"`
}

View File

@@ -0,0 +1,15 @@
package viewmodel
// ReturnPagination holds the pagination data result
type ReturnPagination struct {
TotalRecords int64 `json:"total_records"`
RecordsPerPage int64 `json:"records_per_page"`
TotalPages int64 `json:"total_pages"`
CurrentPage int64 `json:"current_page"`
}
// PaginatedResult is the standard paginated list result
type PaginatedResult struct {
Pagination ReturnPagination `json:"pagination,omitempty"`
List interface{} `json:"data,omitempty"`
}

View File

@@ -0,0 +1,17 @@
package viewmodel
import "time"
type Profile struct {
ID int64 `json:"-"`
Name string `json:"name"`
Key string `json:"key"`
Description string `json:"desc"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Active bool `json:"active"`
Blocked bool `json:"blocked"`
Suspended bool `json:"suspended"`
Visible bool `json:"visible"`
Organization Organization `json:"organization"`
}

View File

@@ -0,0 +1,119 @@
package viewmodel
type ProviderResp struct {
ProviderUUID string `json:"provider_uuid,omitempty"`
InternalID string `json:"internal_id,omitempty"`
InternalSuffixID string `json:"internal_suffix_id,omitempty"`
MukID string `json:"muk_id,omitempty"`
OrganizatioName string `json:"org_name,omitempty"`
Gender string `json:"gender,omitempty"`
AcceptNewPatients string `json:"accept_new_patients,omitempty"`
Name string `json:"name,omitempty"`
FirstName string `json:"first,omitempty"`
MiddleName string `json:"middle,omitempty"`
LastName string `json:"last,omitempty"`
Title string `json:"title,omitempty"`
Keys []ProviderKey `json:"keys,omitempty"`
Address ProviderAddress `json:"address,omitempty"`
Distance float64 `json:"distance,omitempty"`
}
type ProviderKey struct {
InternalID string `json:"internal_id"`
InternalSuffixID string `json:"internal_suffix_id"`
LocationSeqNumber string `json:"location_seq_number"`
PlanCode string `json:"plan_code"`
ProductID string `json:"product_id"`
TreatmentCategoryCode string `json:"treatment_category_code"`
}
type ProviderAddress struct {
StreetAddress1 string `json:"street_address_1,omitempty"`
StreetAddress2 string `json:"street_address_2,omitempty"`
CityName string `json:"city,omitempty"`
State string `json:"state,omitempty"`
ZipCode string `json:"zipcode,omitempty"`
Country string `json:"country,omitempty"`
Latitude float64 `json:"lat,omitempty"`
Longitude float64 `json:"long,omitempty"`
PhoneNumber string `json:"phone_number,omitempty"`
}
// ProviderSearchParams entity data
type ProviderSearchParams struct {
Name string
SearchBy string
Latitude float64
Longitude float64
Distance int64
Limit int64
}
type ProviderResponse struct {
MukID string `json:"mukId"`
FivePartKeyGroups []PartKeyGroup `json:"fivePartKeyGroups"`
OrgName string `json:"orgName"`
Gender string `json:"gender"`
AcceptNewPatients string `json:"acceptNewPatients"`
ProviderName string `json:"providerName"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
MiddleName string `json:"middleName"`
ProviderTitle string `json:"providerTitle"`
StreetName1 string `json:"streetName_1"`
StreetName2 string `json:"streetName_2"`
CityName string `json:"cityName"`
State string `json:"state"`
ZipCode string `json:"zipCode"`
Country string `json:"country"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
PhoneNumber string `json:"phoneNumber"`
ProviderEntityName string `json:"providerEntityName"`
ProviderEntityCode string `json:"providerEntityCode"`
ProviderTypeCode []ProviderTypeCode `json:"providerTypeCode"`
Distance string `json:"distance"`
AvailabilityOfCost string `json:"availabilityOfCost"`
TDDPhoneNumber string `json:"tddPhoneNumber"`
ExtendedOfficeHours string `json:"extendedOfficeHours"`
ProviderCountyCode string `json:"providerCountyCode"`
ProviderCountyName string `json:"providerCountyName"`
HospitalAffiliationNames []HospitalAffiliationNames `json:"hospitalAffiliationNames"`
ProviderAffiliationNumber string `json:"providerAffiliationNumber"`
ProviderAffiliationName string `json:"providerAffiliationName"`
LanguagesSpoken []Languages `json:"languagesSpoken"`
OfficeLanguagesSpoken []Languages `json:"officeLanguagesSpoken"`
MedSchool string `json:"medSchool"`
MedSchoolYear string `json:"medSchoolYear"`
Internship string `json:"internship"`
Residence string `json:"residency"`
Specialty1 string `json:"specialty1"`
Specialty2 string `json:"specialty2"`
Specialty3 string `json:"specialty3"`
Specialty4 string `json:"specialty4"`
Certification1 string `json:"certification1"`
Certification2 string `json:"certification2"`
Certification3 string `json:"certification3"`
Certification4 string `json:"certification4"`
}
type HospitalAffiliationNames struct {
HospAffProvOrgName string `json:"hospAffProvOrgName"`
}
type Languages struct {
Code string `json:"code"`
}
type ProviderTypeCode struct {
Code string `json:"code"`
}
type PartKeyGroup struct {
ProviderNum string `json:"providerNum"`
ProviderNumSuffix string `json:"providerNumSuffix"`
LocationSeqNum string `json:"locationSeqNum"`
PlanCode string `json:"planCode"`
ProductID string `json:"productId"`
TreatmentCategoryCode string `json:"treatmentCategoryCode"`
}

View File

@@ -0,0 +1,161 @@
package viewmodel
import "time"
//WebhookResponse has the data and events from the webhook
type WebhookResponse struct {
EventID string `json:"event_id,omitempty"`
HREF string `json:"href,omitempty"`
OccurredAt string `json:"occurred_at,omitempty"`
EventType string `json:"event_type,omitempty"`
Event RideRequest `json:"event,omitempty"`
Ride Ride `json:"-"`
}
//RideRequest has the data to dispatch a ride
type RideRequest struct {
UserUUID string `json:"user_uuid,omitempty"`
Status string `json:"status,omitempty"`
RideID string `json:"ride_id,omitempty"`
RideType string `json:"ride_type,omitempty"`
Origin Location `json:"origin,omitempty"`
Location Location `json:"location,omitempty"`
Destination Location `json:"destination,omitempty"`
Passenger UserLyft `json:"passenger,omitempty"`
Notes string `json:"external_note,omitempty"`
RouteURL string `json:"route_url,omitempty"`
ScheduledPickupRange interface{} `json:"scheduled_pickup_range,omitempty"`
PrimetimePercentage string `json:"primetime_percentage,omitempty"`
Pickup Location `json:"pickup,omitempty"`
DropOff Location `json:"dropoff,omitempty"`
Vehicle Vehicle `json:"vehicle,omitempty"`
Price Price `json:"price,omitempty"`
Driver UserLyft `json:"driver,omitempty"`
GeneratedAtMS *int64 `json:"generated_at_ms,omitempty"`
GeneratedAt *time.Time `json:"generated_at,omitempty"`
RequestAtMS *int64 `json:"requested_at_ms,omitempty"`
RequestAt *time.Time `json:"requested_at,omitempty"`
LineItems []Price `json:"line_items,omitempty"`
BeaconColor string `json:"beacon_color,omitempty"`
Charges []Charge `json:"charges,omitempty"`
VisitDate *time.Time `json:"visit_date,omitempty"`
VisitTime *time.Time `json:"visit_time,omitempty"`
PickupTime *time.Time `json:"pickup_time,omitempty"`
ReturnTime *time.Time `json:"return_time,omitempty"`
Distance float64 `json:"distance,omitempty"`
ETA int64 `json:"eta,omitempty"`
Duration int64 `json:"duration,omitempty"`
Visit Visit `json:"visit,omitempty"`
CreateUserUUID string `json:"created_user_uuid,omitempty"`
VisitExternalID string `json:"visit_external_id,omitempty"`
CanCancel []string `json:"can_cancel,omitempty"`
PricingDetailsURL string `json:"pricing_details_url,omitempty"`
RideProfile string `json:"ride_profile,omitempty"`
DistanceInMiles float64 `json:"distance_miles,omitempty"`
DurationInSeconds float64 `json:"duration_seconds,omitempty"`
CanceledBy string `json:"canceled_by,omitempty"`
TripType TripType `json:"trip_type,omitempty"`
Error string `json:"error,omitempty"`
ErrorDescription string `json:"error_description,omitempty"`
}
//Charge information
type Charge struct {
Currency string `json:"currency,omitempty"`
PaymentMethod string `json:"payment_method,omitempty"`
Amount int64 `json:"amount,omitempty"`
}
//Price information
type Price struct {
Currency string `json:"currency,omitempty"`
Amount float64 `json:"amount,omitempty"`
Description string `json:"description,omitempty"`
Type string `json:"type,omitempty"`
}
//Vehicle information
type Vehicle struct {
Color string `json:"color,omitempty"`
Make string `json:"make,omitempty"`
LicensePlate string `json:"license_plate,omitempty"`
ImageURL string `json:"image_url,omitempty"`
Year int64 `json:"year,omitempty"`
LicensePlateState string `json:"license_plate_state,omitempty"`
Model string `json:"model,omitempty"`
}
//Location has the coordinates from the user
type Location struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Latitude float64 `json:"lat,omitempty"`
Longitude float64 `json:"lng,omitempty"`
Address string `json:"address,omitempty"`
ETASeconds *int64 `json:"eta_seconds,omitempty"`
TimeMS *int64 `json:"time_ms,omitempty"`
Time *time.Time `json:"time,omitempty"`
Bearing *float64 `json:"bearing,omitempty"`
}
//UserLyft has the personal information
type UserLyft struct {
UserID *string `json:"user_id,omitempty"`
Rating *string `json:"rating,omitempty"`
ImageURL *string `json:"image_url,omitempty"`
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
PhoneNumber string `json:"phone_number,omitempty"`
}
// Ride entity data
type Ride struct {
UUID string `json:"ride_uuid,omitempty"`
InternalID string `json:"internal_id,omitempty"`
User User `json:"user,omitempty"`
Status RideStatus `json:"status,omitempty"`
Type RideType `json:"type,omitempty"`
Note string `json:"notes,omitempty"`
Passenger UserLyft `json:"passenger,omitempty"`
Driver UserLyft `json:"driver,omitempty"`
Vehicle Vehicle `json:"vehicle,omitempty"`
Route RideRoute `json:"route,omitempty"`
VisitDate *time.Time `json:"visit_date,omitempty"`
VisitTime *time.Time `json:"visit_time,omitempty"`
PickupTime *time.Time `json:"pickup_time,omitempty"`
Visit Visit `json:"visit,omitempty"`
CreatedUser User `json:"created_user,omitempty"`
CreateAt time.Time `json:"create_at,omitempty"`
UpdateAt time.Time `json:"update_at,omitempty"`
TripType TripType `json:"trip_type,omitempty"`
}
// RideStatus entity data
type RideStatus struct {
Key string `json:"key,omitempty"`
Value string `json:"value,omitempty"`
}
// TripType entity data
type TripType struct {
Key string `json:"key"`
Value string `json:"value"`
}
// RideType entity data
type RideType struct {
Key string `json:"key,omitempty"`
Value string `json:"value,omitempty"`
}
// RideRoute entity data
type RideRoute struct {
Origin Location `json:"origin,omitempty"`
Destination Location `json:"destination,omitempty"`
Location Location `json:"location,omitempty"`
RouteKML *string `json:"route_kml,omitempty"`
Distance float64 `json:"distance,omitempty"`
Duration int64 `json:"duration,omitempty"`
ETA int64 `json:"eta,omitempty"`
Bearing int64 `json:"bearing,omitempty"`
}

View File

@@ -0,0 +1,87 @@
package viewmodel
type ListNumbers struct {
AvailableNumbers []Number `json:"available_phone_numbers,omitempty"`
Page int64 `json:"page,omitempty"`
PageSize int64 `json:"page_size,omitempty"`
URI string `json:"uri,omitempty"`
FirstPageURI string `json:"first_page_uri,omitempty"`
PreviousPageURI string `json:"previous_page_uri,omitempty"`
NextPageURI string `json:"next_page_uri,omitempty"`
IncomingPhones []Number `json:"incoming_phone_numbers,omitempty"`
}
type Number struct {
SID *string `json:"sid,omitempty"`
AccountSID *string `json:"account_sid,omitempty"`
FriendlyName string `json:"friendly_name,omitempty"`
PhoneNumber string `json:"phone_number,omitempty"`
Lata string `json:"lata,omitempty"`
RateCenter string `json:"rate_center,omitempty"`
Latitude string `json:"latitude,omitempty"`
Longitude string `json:"longitude,omitempty"`
Region string `json:"region,omitempty"`
PostalCode string `json:"postal_code,omitempty"`
ISOCountry string `json:"iso_country,omitempty"`
Beta bool `json:"beta,omitempty"`
Capabilities Capabilities `json:"capabilities,omitempty"`
VoiceURL *string `json:"voice_url,omitempty"`
VoiceMethod *string `json:"voice_method,omitempty"`
VoiceFallbackURL *string `json:"voice_fallback_url,omitempty"`
VoiceFallbackMethod *string `json:"voice_fallback_method,omitempty"`
VoiceCallerIDLookup bool `json:"voice_caller_id_lookup,omitempty"`
VoiceApplicationSID *string `json:"voice_application_sid,omitempty"`
DateCreated *string `json:"date_created,omitempty"`
DateUpdated *string `json:"date_updated,omitempty"`
SmsURL *string `json:"sms_url,omitempty"`
SmsMethod *string `json:"sms_method,omitempty"`
SmsFallbackURL *string `json:"sms_fallback_url,omitempty"`
SmsFallbackMethod *string `json:"sms_fallback_method,omitempty"`
SmsApplicationID *string `json:"sms_application_sid,omitempty"`
StatusCallback *string `json:"status_callback,omitempty"`
StatusCallbackMethod *string `json:"status_callback_method,omitempty"`
APIVersion *string `json:"api_version,omitempty"`
}
type Capabilities struct {
Voice bool `json:"voice,omitempty"`
SMS bool `json:"SMS,omitempty"`
MMS bool `json:"MMS,omitempty"`
}
type ProxyNumber struct {
From string `json:"from,omitempty"`
To string `json:"to,omitempty"`
Proxy string `json:"proxy,omitempty"`
Number Number `json:"details,omitempty"`
}
type SocketMessage struct {
From string `json:"from"`
To string `json:"to"`
Message string `json:"message"`
Filled bool `json:"-"`
}
type TwilioWebhook struct {
ToCountry string `json:"ToCountry,omitempty"`
ToState string `json:"ToState,omitempty"`
SMSMessageSID string `json:"SmsMessageSid,omitempty"`
NumMedia string `json:"NumMedia,omitempty"`
ToCity string `json:"ToCity,omitempty"`
FromZip string `json:"FromZip,omitempty"`
SMSSID string `json:"SmsSid,omitempty"`
FromState string `json:"FromState,omitempty"`
SMSStatus string `json:"SmsStatus,omitempty"`
FromCity string `json:"FromCity,omitempty"`
Body string `json:"Body,omitempty"`
FromCountry string `json:"FromCountry,omitempty"`
To string `json:"To,omitempty"`
ToZip string `json:"ToZip,omitempty"`
AddOns string `json:"AddOns,omitempty"`
NumSegments string `json:"NumSegments,omitempty"`
MessageSID string `json:"MessageSid,omitempty"`
AccountSID string `json:"AccountSid,omitempty"`
From string `json:"From,omitempty"`
APIVersion string `json:"ApiVersion,omitempty"`
}

View File

@@ -0,0 +1,36 @@
package viewmodel
import "time"
// User model for API binding
type User struct {
ID string `json:"useruuid"`
Name string `json:"name,omitempty"`
First string `json:"first,omitempty"`
Last string `json:"last,omitempty"`
Gender *string `json:"gender,omitempty"`
Member *string `json:"member,omitempty"`
BirthDate *time.Time `json:"birthdate,omitempty"`
Email *string `json:"email,omitempty"`
PhoneNumber *string `json:"phonenumber,omitempty"`
Pass string `json:"pass,omitempty"`
Active bool `json:"active,omitempty"`
Created time.Time `json:"created,omitempty"`
Updated time.Time `json:"updated,omitempty"`
Contacts []Contact `json:"contacts,omitempty"`
Rides []Ride `json:"rides,omitempty"`
Addresses []Address `json:"addresses,omitempty"`
Profiles []Profile `json:"profiles,omitempty"`
Types []OrganizationType `json:"types,omitempty"`
Organizations []Organization `json:"organizations,omitempty"`
}
type Contact struct {
Type ContactType `json:"type,omitempty"`
Value string `json:"contact,omitempty"`
}
type ContactType struct {
Key string `json:"key,omitempty"`
Value string `json:"value,omitempty"`
}

View File

@@ -0,0 +1,33 @@
package viewmodel
import (
"time"
)
// VisitStatus entity data
type VisitStatus struct {
Key string `json:"key,omitempty"`
Value string `json:"value,omitempty"`
}
// Visit entity data
type Visit struct {
UUID string `json:"visit_uuid,omitempty"`
Status VisitStatus `json:"visit_status,omitempty"`
User User `json:"user,omitempty"`
VisitDatetime time.Time `json:"visit_datetime,omitempty"`
VisitDuration int64 `json:"visit_duration,omitempty"`
PickupDatetime time.Time `json:"pickup_datetime,omitempty"`
Notes *string `json:"notes,omitempty"`
PickupAddressID int64 `json:"pickup_address_id,omitempty"`
DestinationAddressID int64 `json:"destination_address_id,omitempty"`
Pickup Location `json:"pickup,omitempty"`
Provider ProviderResp `json:"provider,omitempty"`
CreatedUser User `json:"created_user,omitempty"`
CreatedDate time.Time `json:"created,omitempty"`
UpdatedDate time.Time `json:"updated,omitempty"`
ReturnDate *time.Time `json:"return_date,omitempty"`
TripType TripType `json:"trip_type,omitempty"`
ExternalID string `json:"visit_external_id,omitempty"`
Rides []Ride `json:"rides,omitempty"`
}

59
bitbucket-pipelines.yml Normal file
View File

@@ -0,0 +1,59 @@
image: golang:1.9.2
pipelines:
branches:
master:
- step:
script:
- curl https://glide.sh/get | sh
- mkdir -p /go/src/bitbucket.org/nemt/nemt-portal-api
- pwd
- ls -al
- cp -R ./* /go/src/bitbucket.org/nemt/nemt-portal-api/
- cd /go/src/bitbucket.org/nemt/nemt-portal-api/
- rm -rf glide.lock
- rm -rf vendor/
- glide install -force
- go build -o nemt-portal-api
- mkdir -p dist/{static,docs}
- cp nemt-portal-api ./dist/
- cp -R static/* ./dist/static/
- cp -R docs/swagger/ ./dist/docs/
- cp config.prd.toml ./dist/config.toml
- 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 .
- apt-get update -y && apt-get upgrade -y && apt-get dist-upgrade -y && apt-get -y autoremove && apt-get clean
- apt-get install python3-pip -y
- pip3 install --upgrade awscli
- eval $(aws ecr get-login --no-include-email --region us-east-2)
- docker tag nemt-portal-api-run:prod 105690980714.dkr.ecr.us-east-2.amazonaws.com/nemt-portal-api:prod
- docker push 105690980714.dkr.ecr.us-east-2.amazonaws.com/nemt-portal-api:prod
- eval $(aws --region us-east-2 ecs register-task-definition --cli-input-json file://ecs.prd.json >/dev/null)
- eval $(aws --region us-east-2 ecs update-service --cluster App --service portal-api --task-definition portal-api-prod >/dev/null)
development:
- step:
script:
- curl https://glide.sh/get | sh
- mkdir -p /go/src/bitbucket.org/nemt/nemt-portal-api
- pwd
- ls -al
- cp -R ./* /go/src/bitbucket.org/nemt/nemt-portal-api/
- cd /go/src/bitbucket.org/nemt/nemt-portal-api/
- rm -rf glide.lock
- rm -rf vendor/
- glide install -force
- go build -o nemt-portal-api
- mkdir -p dist/{static,docs}
- cp nemt-portal-api ./dist/
- cp -R static/* ./dist/static/
- cp -R docs/swagger/ ./dist/docs/
- cp config.stg.toml ./dist/config.toml
- 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 .
- apt-get update -y && apt-get upgrade -y && apt-get dist-upgrade -y && apt-get -y autoremove && apt-get clean
- apt-get install python3-pip -y
- pip3 install --upgrade awscli
- eval $(aws ecr get-login --no-include-email --region us-east-2)
- docker tag nemt-portal-api-run:dev 105690980714.dkr.ecr.us-east-2.amazonaws.com/nemt-portal-api:dev
- docker push 105690980714.dkr.ecr.us-east-2.amazonaws.com/nemt-portal-api:dev
- eval $(aws --region us-east-2 ecs register-task-definition --cli-input-json file://ecs.stg.json >/dev/null)
- eval $(aws --region us-east-2 ecs update-service --cluster NemtCluster2 --service portal-api --task-definition portal-api-dev >/dev/null)
options:
docker: true

82
config.dev.toml Normal file
View File

@@ -0,0 +1,82 @@
[app]
name = "nemt"
debug = true
[app.docs]
swagger-path = "./static/swagger-ui"
yaml-path = "./docs/swagger"
[db]
host = "dbdev01.cj5318jcaupw.us-east-2.rds.amazonaws.com"
port = 3306
name = "nemt"
user = "nemt-user"
pass = "4umQ3ENNzt"
max-life-minutes = 5
max-idle-conns = 5
max-open-conns = 100
[http]
port = 5100
prefix = "/v1"
[http.auth]
app-key = "8a266a40-ed2e-4be2-bdfc-459a507bf02e"
certificate-path = "./static/cert/nemt-portal-api.key"
frontend-urls = [
"http://localhost:3100"
]
[aws]
s3-bucket = "static.nemt-portal-api.com.br/development"
[cache]
server = "internal-REDISDEV-INT-ELB01-905785815.us-east-2.elb.amazonaws.com"
port = 6379
db = 0
pass = "3rdaP3KL2x%V"
prefix = "nemt-portal-api-dev"
default-expiration = "5m"
[log]
log-to-file = false
path = "nemt-portal-api.log"
[twilio]
account = "AC3106c1aeb2c74b7e45adc1ba0ff8c6e2"
token = "36ba77236be5eb5848b3746e4400f4e2"
sender = "+17084261667"
twiml-sid = "APc33ccb8af94ecf3d61c6bfd9a7f69749"
[email]
server = "email-smtp.us-east-1.amazonaws.com"
port = 587
user = "AKIAIP2QTIHICY5I5BBA"
pass = "AkInsFK64iCbrAftVnVGFVVJOcMIG/pv8k1aFZwAQ5lF"
sender = "no-reply@chmhub.com"
[google-shortener]
client-id = "1059812138553-t7jents4d3a7uqpb9ms9nf2luqkqplrt.apps.googleusercontent.com"
secret-key = "r478-RtEmvAcDWlLQk1CZatQ"
api-key = "AIzaSyAQsoEaUmg96-TxxNCTJhyu5HEOLBzxcCw"
[lyft]
key = "KkS0DgSPuJ84"
secret = "SANDBOX-8LxipL9BYDJrcAZSgqr8yODjQRDXQQ_T"
token = "UyjcHl7fC6LxRWgZ8I6-_LJ0_j6YcWNg9ct2xEXMdX2iRiGrMrjrbJmxtPlNPGvN"
[lyft-prod]
key = "KkS0DgSPuJ84"
secret = "8LxipL9BYDJrcAZSgqr8yODjQRDXQQ_T"
token = "Xa8n7M8TQ62iRpElan0gaPZwaPzUIa85G-epIesWJysJgOQU5zRDLdqD1ygZk8-Y"
user-uuid = "11a49fa4-fbc7-4fe9-87fe-52a5bc3b71f8"
[bxe]
url = "https://api-pve.bcbs.com/BXDirectConnect/V30"
key = "dacg7jtsmb6ajr3z553jbczg"
secret = "vFhNeWE8JdJpbDZQtcm6AHjX"
[blue365]
url = "https://api-cloud.bcbs.com/blue365deals-stg/v1/validatePrefix/"
key = "jcn5xjxvarc96rtjxp25dctj"
secret = "6XdEusG2w2PWWXsfXVyweQnY"

82
config.prd.toml Normal file
View File

@@ -0,0 +1,82 @@
[app]
name = "nemt"
debug = true
[app.docs]
swagger-path = "/opt/app/nemt-portal-api/static/swagger-ui"
yaml-path = "/opt/app/nemt-portal-api/docs/swagger"
[db]
host = "db01.cj5318jcaupw.us-east-2.rds.amazonaws.com"
port = 3306
name = "nemt_clean"
user = "nemt-user"
pass = "OL&!n#p6J8Lu"
max-life-minutes = 5
max-idle-conns = 5
max-open-conns = 100
[http]
port = 5100
prefix = "/v1"
[http.auth]
app-key = "8a266a40-ed2e-4be2-bdfc-459a507bf02e"
certificate-path = "/opt/app/static/cert/nemt-portal-api.key"
frontend-urls = [
"http://localhost:3100"
]
[aws]
s3-bucket = "static.nemt-portal-api.com.br/prod"
[cache]
server = "internal-REDIS-INT-ELB01-661255167.us-east-2.elb.amazonaws.com"
port = 6379
db = 0
pass = "3rdaP3KL2x%V"
prefix = "portal-api-prod"
default-expiration = "5m"
[log]
log-to-file = false
path = "nemt-portal-api.log"
[twilio]
account = "AC3106c1aeb2c74b7e45adc1ba0ff8c6e2"
token = "36ba77236be5eb5848b3746e4400f4e2"
sender = "+17084261667"
twiml-sid = "APc33ccb8af94ecf3d61c6bfd9a7f69749"
[email]
server = "email-smtp.us-east-1.amazonaws.com"
port = 587
user = "AKIAIP2QTIHICY5I5BBA"
pass = "AkInsFK64iCbrAftVnVGFVVJOcMIG/pv8k1aFZwAQ5lF"
sender = "no-reply@chmhub.com"
[google-shortener]
client-id = "1059812138553-t7jents4d3a7uqpb9ms9nf2luqkqplrt.apps.googleusercontent.com"
secret-key = "r478-RtEmvAcDWlLQk1CZatQ"
api-key = "AIzaSyAQsoEaUmg96-TxxNCTJhyu5HEOLBzxcCw"
[lyft]
key = "KkS0DgSPuJ84"
secret = "SANDBOX-8LxipL9BYDJrcAZSgqr8yODjQRDXQQ_T"
token = "UyjcHl7fC6LxRWgZ8I6-_LJ0_j6YcWNg9ct2xEXMdX2iRiGrMrjrbJmxtPlNPGvN"
[lyft-prod]
key = "KkS0DgSPuJ84"
secret = "8LxipL9BYDJrcAZSgqr8yODjQRDXQQ_T"
token = "Xa8n7M8TQ62iRpElan0gaPZwaPzUIa85G-epIesWJysJgOQU5zRDLdqD1ygZk8-Y"
user-uuid = "11a49fa4-fbc7-4fe9-87fe-52a5bc3b71f8"
[bxe]
url = "https://api-pve.bcbs.com/BXDirectConnect/V30"
key = "dacg7jtsmb6ajr3z553jbczg"
secret = "vFhNeWE8JdJpbDZQtcm6AHjX"
[blue365]
url = "https://api-cloud.bcbs.com/blue365deals-stg/v1/validatePrefix/"
key = "jcn5xjxvarc96rtjxp25dctj"
secret = "6XdEusG2w2PWWXsfXVyweQnY"

82
config.stg.toml Normal file
View File

@@ -0,0 +1,82 @@
[app]
name = "nemt"
debug = true
[app.docs]
swagger-path = "/opt/app/nemt-portal-api/static/swagger-ui"
yaml-path = "/opt/app/nemt-portal-api/docs/swagger"
[db]
host = "dbdev01.cj5318jcaupw.us-east-2.rds.amazonaws.com"
port = 3306
name = "nemt"
user = "nemt-user"
pass = "4umQ3ENNzt"
max-life-minutes = 5
max-idle-conns = 5
max-open-conns = 100
[http]
port = 5100
prefix = "/v1"
[http.auth]
app-key = "8a266a40-ed2e-4be2-bdfc-459a507bf02e"
certificate-path = "/opt/app/static/cert/nemt-portal-api.key"
frontend-urls = [
"http://localhost:3100"
]
[aws]
s3-bucket = "static.nemt-portal-api.com.br/staging"
[cache]
server = "internal-REDISDEV-INT-ELB01-905785815.us-east-2.elb.amazonaws.com"
port = 6379
db = 0
pass = "3rdaP3KL2x%V"
prefix = "portal-api-test"
default-expiration = "5m"
[log]
log-to-file = false
path = "nemt-portal-api.log"
[twilio]
account = "AC3106c1aeb2c74b7e45adc1ba0ff8c6e2"
token = "36ba77236be5eb5848b3746e4400f4e2"
sender = "+17084261667"
twiml-sid = "APc33ccb8af94ecf3d61c6bfd9a7f69749"
[email]
server = "email-smtp.us-east-1.amazonaws.com"
port = 587
user = "AKIAIP2QTIHICY5I5BBA"
pass = "AkInsFK64iCbrAftVnVGFVVJOcMIG/pv8k1aFZwAQ5lF"
sender = "no-reply@chmhub.com"
[google-shortener]
client-id = "1059812138553-t7jents4d3a7uqpb9ms9nf2luqkqplrt.apps.googleusercontent.com"
secret-key = "r478-RtEmvAcDWlLQk1CZatQ"
api-key = "AIzaSyAQsoEaUmg96-TxxNCTJhyu5HEOLBzxcCw"
[lyft]
key = "KkS0DgSPuJ84"
secret = "SANDBOX-8LxipL9BYDJrcAZSgqr8yODjQRDXQQ_T"
token = "UyjcHl7fC6LxRWgZ8I6-_LJ0_j6YcWNg9ct2xEXMdX2iRiGrMrjrbJmxtPlNPGvN"
[lyft-prod]
key = "KkS0DgSPuJ84"
secret = "8LxipL9BYDJrcAZSgqr8yODjQRDXQQ_T"
token = "Xa8n7M8TQ62iRpElan0gaPZwaPzUIa85G-epIesWJysJgOQU5zRDLdqD1ygZk8-Y"
user-uuid = "11a49fa4-fbc7-4fe9-87fe-52a5bc3b71f8"
[bxe]
url = "https://api-pve.bcbs.com/BXDirectConnect/V30"
key = "dacg7jtsmb6ajr3z553jbczg"
secret = "vFhNeWE8JdJpbDZQtcm6AHjX"
[blue365]
url = "https://api-cloud.bcbs.com/blue365deals-stg/v1/validatePrefix/"
key = "jcn5xjxvarc96rtjxp25dctj"
secret = "6XdEusG2w2PWWXsfXVyweQnY"

11
data/data.go Normal file
View File

@@ -0,0 +1,11 @@
package data
import (
"bitbucket.org/nemt/nemt-portal-api/data/datamysql"
"bitbucket.org/nemt/nemt-portal-api/domain/contract"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
)
func Connect(cfg *config.Config) (contract.DataManager, error) {
return datamysql.Instance(cfg)
}

133
data/datamysql/datamysql.go Normal file
View File

@@ -0,0 +1,133 @@
package datamysql
import (
"database/sql"
"fmt"
"sync"
"time"
"bitbucket.org/nemt/nemt-portal-api/domain/contract"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
"github.com/go-sql-driver/mysql"
)
var (
instance *Conn
once sync.Once
connErr error
)
// Conn is the MySQL connection manager
type Conn struct {
db *sql.DB
users *userRepo
rides *rideRepo
visit *visitRepo
provider *providerRepo
notification *notificationRepo
profile *profileRepo
organization *organizationRepo
}
// Begin starts a transaction
func (c *Conn) Begin() (contract.TransactionManager, error) {
tx, err := c.db.Begin()
if err != nil {
return nil, errors.Wrap(err)
}
return newTransaction(tx), nil
}
// Close closes the db connection
func (c *Conn) Close() (err error) {
return c.db.Close()
}
// Users returns the users set
func (c *Conn) Users() contract.UserRepo {
return c.users
}
// Rides returns the rides set
func (c *Conn) Rides() contract.RideRepo {
return c.rides
}
// Visits returns the rides set
func (c *Conn) Visits() contract.VisitRepo {
return c.visit
}
// Provider returns the rides set
func (c *Conn) Provider() contract.ProviderRepo {
return c.provider
}
// Provider returns the rides set
func (c *Conn) Profile() contract.ProfileRepo {
return c.profile
}
// Provider returns the rides set
func (c *Conn) Notification() contract.NotificationRepo {
return c.notification
}
// Provider returns the rides set
func (c *Conn) Organization() contract.OrganizationRepo {
return c.organization
}
// Instance returns an instance of a DataManager
func Instance(cfg *config.Config) (contract.DataManager, error) {
once.Do(func() {
db, err := sql.Open("mysql", getMySQLConfig(cfg).FormatDSN())
if err != nil {
connErr = errors.Wrap(err)
return
}
err = db.Ping()
if err != nil {
connErr = errors.Wrap(err)
return
}
connMaxLifetime := time.Duration(cfg.DB.MaxLifeInMinutes) * time.Minute
db.SetConnMaxLifetime(connMaxLifetime)
db.SetMaxIdleConns(cfg.DB.MaxIdleConns)
db.SetMaxOpenConns(cfg.DB.MaxOpenConns)
instance = new(Conn)
instance.db = db
instance.users = newUserRepo(db)
instance.rides = newRideRepo(db)
instance.visit = newVisitRepo(db)
instance.provider = newProviderRepo(db)
instance.notification = newNotificationRepo(db)
instance.profile = newProfileRepo(db)
instance.organization = newOrganizationRepo(db)
})
return instance, connErr
}
// getMySQLConfig returns the configuration for MySQL driver
func getMySQLConfig(cfg *config.Config) *mysql.Config {
loc, _ := time.LoadLocation("UTC")
return &mysql.Config{
Net: "tcp",
Addr: fmt.Sprintf("%s:%d", cfg.DB.Host, cfg.DB.Port),
DBName: cfg.DB.Name,
User: cfg.DB.User,
Passwd: cfg.DB.Pass,
ParseTime: true,
Strict: true,
Loc: loc,
}
}

View File

@@ -0,0 +1,140 @@
package datamysql
import (
"database/sql"
"fmt"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
uuid "github.com/satori/go.uuid"
)
// visitRepo maps methods to database
type notificationRepo struct {
conn executor
}
func newNotificationRepo(conn executor) *notificationRepo {
return &notificationRepo{
conn: conn,
}
}
func (c *notificationRepo) Create(notification entity.Notification) (entity.Notification, error) {
const (
statusQuery = `SELECT a.contact_type_id, b.ride_id, c.user_id, d.user_id created_user_id FROM tab_contact_type a, tab_ride b, tab_user c, tab_user d WHERE a.key = ? AND b.ride_uuid = ? AND c.user_uuid = ? AND d.user_uuid = ?;`
query = `INSERT INTO tab_notification(notification_uuid, ride_id, user_id, contact_type_id, contact, message, created_user_id, readed, notificaton_type) VALUES(?, ?, ?, ?, ?, ?, ?, 0, ?);`
)
retVal := notification
UUID, _ := uuid.NewV4()
retVal.UUID = UUID.String()
row := c.conn.QueryRow(statusQuery, retVal.Type, retVal.Ride.UUID, retVal.User.UUID, retVal.CreatedUser.UUID)
if err := row.Scan(&retVal.TypeID, &retVal.Ride.ID, &retVal.User.ID, &retVal.CreatedUser.ID); err != nil {
fmt.Println("Error to get base data: ", err.Error())
return retVal, err
}
results, err := c.conn.Exec(query, retVal.UUID, retVal.Ride.ID, retVal.User.ID, retVal.TypeID, retVal.Subject, retVal.Message, retVal.CreatedUser.ID, retVal.MessageType)
if err != nil {
return retVal, err
}
retVal.ID, err = results.LastInsertId()
if err != nil {
return retVal, err
}
return c.GetByID(retVal.ID)
}
func (c *notificationRepo) getQuery() string {
return `SELECT
a.notification_id,
a.notification_uuid,
a.ride_id,
a.user_id,
c.user_uuid,
c.name user_name,
CASE WHEN b.key = 'sms' THEN e.phone_number WHEN b.key = 'email' THEN e.email WHEN b.key = 'app' THEN c.user_uuid END to_address,
CASE WHEN b.key = 'sms' THEN f.phone_number WHEN b.key = 'email' THEN f.email WHEN b.key = 'app' THEN d.user_uuid END from_address,
a.contact_type_id,
b.key contact_type_key,
a.contact,
a.message,
a.create_at,
a.readed,
d.user_id created_user_id,
d.user_uuid created_user_uuid,
d.name created_user_name,
a.notificaton_type
FROM
tab_notification a
INNER JOIN tab_contact_type b
ON a.contact_type_id = b.contact_type_id
INNER JOIN tab_user c
ON a.user_id = c.user_id
INNER JOIN tab_user d
ON a.created_user_id = d.user_id
INNER JOIN tab_login e
ON c.user_id = e.user_id
INNER JOIN tab_login f
ON d.user_id = f.user_id`
}
func (c *notificationRepo) GetLastNotificationFromPhoneNumber(notificationType string, phoneNumber string, status string) (entity.Notification, error) {
const (
whereClause = ` WHERE
a.notificaton_type = ?
AND e.phone_number = ?
AND b.key = ?
ORDER BY a.notification_id DESC
LIMIT 1;`
)
finalQuery := c.getQuery() + whereClause
return c.parseEntity(c.conn.QueryRow(finalQuery, notificationType, phoneNumber, status))
}
func (c *notificationRepo) GetByUserUUIDAndReadStatus(userUUID string, status string, isRead bool) ([]entity.Notification, error) {
return c.parseSet(c.conn.Query(c.getQuery()+" WHERE a.readed = ? AND b.key = ? AND c.user_uuid = ?; ", isRead, status, userUUID))
}
func (c *notificationRepo) GetByUserUUID(userUUID string, status string) ([]entity.Notification, error) {
return c.parseSet(c.conn.Query(c.getQuery()+" WHERE b.key = ? AND c.user_uuid = ?; ", status, userUUID))
}
func (c *notificationRepo) ReadStatus(notificationUUID string, isRead bool) error {
const query = "UPDATE tab_notification SET readed = ? WHERE notification_uuid = ?"
_, err := c.conn.Exec(query, isRead, notificationUUID)
return err
}
func (c *notificationRepo) GetByID(ID int64) (entity.Notification, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE a.notification_id = ?; ", ID))
}
// parseSet parses a result set result to an entity array
func (c *notificationRepo) parseSet(rows *sql.Rows, err error) ([]entity.Notification, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Notification, 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 *notificationRepo) parseEntity(row scanner) (retVal entity.Notification, err error) {
err = row.Scan(
&retVal.ID, &retVal.UUID, &retVal.Ride.ID, &retVal.User.ID, &retVal.User.UUID, &retVal.User.Name, &retVal.To, &retVal.From, &retVal.TypeID, &retVal.Type, &retVal.Subject, &retVal.Message, &retVal.Created, &retVal.Read, &retVal.CreatedUser.ID, &retVal.CreatedUser.UUID, &retVal.CreatedUser.Name, &retVal.MessageType)
return retVal, errors.Wrap(err)
}

View File

@@ -0,0 +1,482 @@
package datamysql
import (
"database/sql"
"fmt"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
uuid "github.com/satori/go.uuid"
)
// rideRepo maps methods to database
type organizationRepo struct {
conn executor
}
func newOrganizationRepo(conn executor) *organizationRepo {
return &organizationRepo{
conn: conn,
}
}
func (c *organizationRepo) getQuery() string {
const (
query = `SELECT
a.organization_id,
a.organization_uuid,
b.organization_type_id,
b.organization_type,
b.organization_type_key,
a.organization_name,
a.organization_description,
a.organization_reference_id,
a.organization_parent_id,
(a.main_organization = b'1') main_organization,
a.create_at,
a.update_at,
(a.active = b'1') active,
(a.suspended = b'1') suspended,
(a.blocked = b'1') blocked,
c.user_id created_user_id,
c.user_uuid created_user_uuid,
c.name created_user_name,
d.user_id updated_user_id,
d.user_uuid updated_user_uuid,
d.name updated_user_name
FROM
tab_organization a
INNER JOIN tab_organization_type b
ON a.organization_type_id = b.organization_type_id
INNER JOIN tab_user c
ON c.user_id = a.created_user
INNER JOIN tab_user d
ON d.user_id = a.updated_user `
)
return query
}
func (c *organizationRepo) getAddressQuery() string {
const query = `SELECT
a.organization_address_id,
a.organization_address_uuid,
a.internal_id,
a.name,
a.address,
a.desc,
a.lat,
a.long,
a.created,
a.created_user_id,
c.user_uuid created_user_uuid,
c.name created_user_name,
a.updated,
a.updated_user_id,
d.user_uuid updated_user_uuid,
d.name updated_user_name,
(a.active = b'1') active
FROM tab_organization_address a
INNER JOIN tab_organization b
ON b.organization_id = a.organization_id
INNER JOIN tab_user c
ON c.user_id = a.created_user_id
INNER JOIN tab_user d
ON d.user_id = a.updated_user_id `
return query
}
func (c *organizationRepo) getContactQuery() string {
const (
query = `SELECT
a.organization_contact_id,
a.organization_contact_uuid,
b.contact_type_id,
b.key contact_type_key,
b.name contact_type_name,
a.contact,
a.contact_name,
a.contact_desc,
a.created,
a.created_user_id,
d.user_uuid created_user_uuid,
d.name created_user_name,
a.updated,
a.updated_user_id,
e.user_uuid updated_user_uuid,
e.name updated_user_name,
(a.active = b'1') active
FROM tab_organization_contact a
INNER JOIN tab_contact_type b
ON a.contact_type_id = b.contact_type_id
INNER JOIN tab_organization c
ON c.organization_id = a.organization_id
INNER JOIN tab_user d
ON d.user_id = a.created_user_id
INNER JOIN tab_user e
ON e.user_id = a.updated_user_id `
)
return query
}
func (c *organizationRepo) getTypeQuery() string {
const (
query = `SELECT
organization_type_id,
organization_type,
organization_type_key,
description,
create_at,
update_at
FROM
tab_organization_type `
)
return query
}
// parseSet parses a result set result to an entity array
func (c *organizationRepo) parseSet(rows *sql.Rows, err error) ([]entity.Organization, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Organization, 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 *organizationRepo) parseEntity(row scanner) (retVal entity.Organization, err error) {
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)
return retVal, errors.Wrap(err)
}
// parseSet parses a result set result to an entity array
func (c *organizationRepo) parseContactSet(rows *sql.Rows, err error) ([]entity.OrganizationContact, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.OrganizationContact, 0)
for rows.Next() {
entity, err := c.parseContactEntity(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 *organizationRepo) parseContactEntity(row scanner) (retVal entity.OrganizationContact, err error) {
err = row.Scan(
&retVal.ID, &retVal.UUID, &retVal.Type.ID, &retVal.Type.Key, &retVal.Type.Value, &retVal.Contact, &retVal.Name, &retVal.Description, &retVal.Created, &retVal.CreatedUser.ID, &retVal.CreatedUser.UUID, &retVal.CreatedUser.Name, &retVal.Updated, &retVal.UpdatedUser.ID, &retVal.UpdatedUser.UUID, &retVal.UpdatedUser.Name, &retVal.Active)
return retVal, errors.Wrap(err)
}
// parseSet parses a result set result to an entity array
func (c *organizationRepo) parseAddressSet(rows *sql.Rows, err error) ([]entity.OrganizationAddress, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.OrganizationAddress, 0)
for rows.Next() {
entity, err := c.parseAddressEntity(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 *organizationRepo) parseAddressEntity(row scanner) (retVal entity.OrganizationAddress, err error) {
err = row.Scan(
&retVal.ID, &retVal.UUID, &retVal.InternalID, &retVal.Name, &retVal.Address, &retVal.Description, &retVal.Latitude, &retVal.Longitude, &retVal.Created, &retVal.CreatedUser.ID, &retVal.CreatedUser.UUID, &retVal.CreatedUser.Name, &retVal.Updated, &retVal.UpdatedUser.ID, &retVal.UpdatedUser.UUID, &retVal.UpdatedUser.Name, &retVal.Active)
return retVal, errors.Wrap(err)
}
// parseSet parses a result set result to an entity array
func (c *organizationRepo) parseTypeSet(rows *sql.Rows, err error) ([]entity.OrganizationType, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.OrganizationType, 0)
for rows.Next() {
entity, err := c.parseTypeEntity(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 *organizationRepo) parseTypeEntity(row scanner) (retVal entity.OrganizationType, err error) {
err = row.Scan(
&retVal.ID, &retVal.Name, &retVal.Key, &retVal.Description, &retVal.Created, &retVal.Updated)
return retVal, errors.Wrap(err)
}
func (c *organizationRepo) GetAllTypes() ([]entity.OrganizationType, error) {
return c.parseTypeSet(c.conn.Query(c.getTypeQuery()))
}
func (c *organizationRepo) GetTypeByKey(key string) (entity.OrganizationType, error) {
return c.parseTypeEntity(c.conn.QueryRow(c.getTypeQuery()+" WHERE organization_type_key=?", key))
}
func (c *organizationRepo) GetByType(organizationTypeKey string) ([]entity.Organization, error) {
if organizationTypeKey == "" {
return c.parseSet(c.conn.Query(c.getQuery()))
} else {
return c.parseSet(c.conn.Query(c.getQuery()+" WHERE b.organization_type_key = ? ", organizationTypeKey))
}
}
func (c *organizationRepo) GetByName(name string, searchType string) ([]entity.Organization, error) {
finalQuery := c.getQuery() + " WHERE a.organization_name LIKE ?"
switch searchType {
case "parent":
finalQuery += " AND a.organization_parent_id > 0; "
case "child":
finalQuery += " AND a.organization_parent_id = 0; "
}
name = "%" + name + "%"
fmt.Println(finalQuery)
return c.parseSet(c.conn.Query(finalQuery, name))
}
func (c *organizationRepo) GetByUUID(organizationUUID string) (entity.Organization, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE a.organization_uuid = ? ", organizationUUID))
}
func (c *organizationRepo) GetByID(organizationID int64) (entity.Organization, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE a.organization_id = ? ", organizationID))
}
func (c *organizationRepo) GetChildsByID(organizationID int64) ([]entity.Organization, error) {
return c.parseSet(c.conn.Query(c.getQuery()+" WHERE a.organization_parent_id = ? ", organizationID))
}
func (c *organizationRepo) GetContactsByOrganizationUUID(organizationUUID string) ([]entity.OrganizationContact, error) {
return c.parseContactSet(c.conn.Query(c.getContactQuery()+" WHERE a.active = 1 AND c.organization_uuid = ? ", organizationUUID))
}
func (c *organizationRepo) GetContactsByOrganizationID(organizationID int64) ([]entity.OrganizationContact, error) {
return c.parseContactSet(c.conn.Query(c.getContactQuery()+" WHERE a.active = 1 AND c.organization_id = ? ", organizationID))
}
func (c *organizationRepo) GetContactsByUUID(contactUUID string) (entity.OrganizationContact, error) {
return c.parseContactEntity(c.conn.QueryRow(c.getContactQuery()+" WHERE a.organization_contact_uuid = ? ", contactUUID))
}
func (c *organizationRepo) GetAddressByOrganizationUUID(organizationUUID string) ([]entity.OrganizationAddress, error) {
return c.parseAddressSet(c.conn.Query(c.getAddressQuery()+" WHERE a.active = 1 AND b.organization_uuid = ? ", organizationUUID))
}
func (c *organizationRepo) GetAddressByOrganizationID(organizationID int64) ([]entity.OrganizationAddress, error) {
return c.parseAddressSet(c.conn.Query(c.getAddressQuery()+" WHERE a.active = 1 AND b.organization_id = ? ", organizationID))
}
func (c *organizationRepo) GetAddressByUUID(contactUUID string) (entity.OrganizationAddress, error) {
return c.parseAddressEntity(c.conn.QueryRow(c.getAddressQuery()+" WHERE a.organization_address_uuid = ? ", contactUUID))
}
func (c *organizationRepo) SetParentOrganization(organizationID int64, parentOrganizationID int64) error {
const (
query = `UPDATE tab_organization SET organization_parent_id = ? WHERE organization_id = ?;`
)
_, err := c.conn.Exec(query, parentOrganizationID, organizationID)
if err != nil {
return err
} else {
return nil
}
}
func (c *organizationRepo) InactivateOrganizationAddress(address entity.OrganizationAddress) error {
const (
query = "UPDATE tab_organization_address SET active = 0, updated = CURRENT_TIMESTAMP, updated_user_id = ? WHERE organization_id = ? and organization_address_uuid = ?"
)
if address.Organization == nil {
return errors.NewNotFoundError()
}
organization, err := c.GetByUUID(address.Organization.UUID)
if err != nil {
return err
}
_, err = c.conn.Exec(query, address.UpdatedUser.ID, organization.ID, address.UUID)
if err != nil {
return err
} else {
return nil
}
}
func (c *organizationRepo) SetOrganizationAddress(address entity.OrganizationAddress) (entity.OrganizationAddress, error) {
const (
query = "INSERT INTO tab_organization_address(organization_address_uuid, organization_id, internal_id, `name`, address, `desc`, lat, `long`, created_user_id, updated_user_id) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
)
if address.Organization == nil {
return entity.OrganizationAddress{}, errors.NewNotFoundError()
}
organization, err := c.GetByUUID(address.Organization.UUID)
if err != nil {
return entity.OrganizationAddress{}, err
}
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)
if err != nil {
return entity.OrganizationAddress{}, err
}
address.ID, err = result.LastInsertId()
if err != nil {
return address, err
}
return address, nil
}
func (c *organizationRepo) InactivateOrganizationContact(contact entity.OrganizationContact) error {
const (
query = "UPDATE tab_organization_contact SET active = 0, updated = CURRENT_TIMESTAMP, updated_user_id = ? WHERE organization_id = ? and organization_contact_uuid = ?"
)
if contact.Organization == nil {
return errors.NewNotFoundError()
}
organization, err := c.GetByUUID(contact.Organization.UUID)
if err != nil {
return err
}
_, err = c.conn.Exec(query, contact.UpdatedUser.ID, organization.ID, contact.UUID)
if err != nil {
return err
} else {
return nil
}
}
func (c *organizationRepo) SetOrganizationContact(contact entity.OrganizationContact) (entity.OrganizationContact, error) {
const (
selectQuery = "SELECT a.contact_type_id, a.name, a.key FROM tab_contact_type a WHERE a.key = ?"
query = "INSERT INTO tab_organization_contact(organization_contact_uuid, organization_id, contact_type_id, contact, contact_name, contact_desc, created_user_id, updated_user_id) VALUES(?, ?, ?, ?, ?, ?, ?, ?);"
)
if contact.Organization == nil {
return entity.OrganizationContact{}, errors.NewNotFoundError()
}
organization, err := c.GetByUUID(contact.Organization.UUID)
if err != nil {
return entity.OrganizationContact{}, err
}
row := c.conn.QueryRow(selectQuery, contact.Type.Key)
err = row.Scan(&contact.Type.ID, &contact.Type.Value, &contact.Type.Key)
if err != nil {
return entity.OrganizationContact{}, err
}
UUID, _ := uuid.NewV4()
result, err := c.conn.Exec(query, UUID.String(), organization.ID, contact.Type.ID, contact.Contact, contact.Name, contact.Description, contact.CreatedUser.ID, contact.UpdatedUser.ID)
if err != nil {
return entity.OrganizationContact{}, err
}
contact.ID, err = result.LastInsertId()
if err != nil {
return contact, err
}
return contact, nil
}
func (c *organizationRepo) AddOrganization(organization entity.Organization) (entity.Organization, error) {
const (
queryOrgType = "SELECT a.organization_type_id FROM tab_organization_type a WHERE a.organization_type_key = ?;"
queryParentOrg = "SELECT a.organization_id FROM tab_organization a WHERE a.organization_uuid = ?;"
query = "INSERT INTO tab_organization(organization_uuid, organization_type_id, organization_name, organization_description, organization_reference_id, organization_parent_id, main_organization, created_user, updated_user) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?);"
)
row := c.conn.QueryRow(queryOrgType, organization.Type.Key)
err := row.Scan(&organization.Type.ID)
if err != nil {
return entity.Organization{}, err
}
if organization.Parent != nil && organization.Parent.UUID != "" {
row := c.conn.QueryRow(queryParentOrg, organization.Parent.UUID)
err := row.Scan(&organization.Parent.ID)
if err != nil {
return entity.Organization{}, err
}
organization.ParentID = organization.Parent.ID
}
UUID, _ := uuid.NewV4()
organization.UUID = UUID.String()
result, err := c.conn.Exec(query, organization.UUID, organization.Type.ID, organization.Name, organization.Description, organization.ReferenceID, organization.ParentID, false, organization.Author.ID, organization.LastEditor.ID)
if err != nil {
return entity.Organization{}, err
}
ID, err := result.LastInsertId()
if err != nil {
return entity.Organization{}, err
}
organization.ID = ID
if len(organization.Addresses) > 0 {
for i, a := range organization.Addresses {
a.Organization = &organization
address, err := c.SetOrganizationAddress(a)
if err != nil {
fmt.Println("Error to save addresses")
return entity.Organization{}, err
}
organization.Addresses[i] = address
}
}
if len(organization.Contacts) > 0 {
for i, ct := range organization.Contacts {
ct.Organization = &organization
contact, err := c.SetOrganizationContact(ct)
if err != nil {
fmt.Println("Error to save contacts")
return entity.Organization{}, err
}
organization.Contacts[i] = contact
}
}
return organization, nil
}

77
data/datamysql/profile.go Normal file
View File

@@ -0,0 +1,77 @@
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 profileRepo struct {
conn executor
}
func newProfileRepo(conn executor) *profileRepo {
return &profileRepo{
conn: conn,
}
}
func (c *profileRepo) getQuery() string {
const (
query = `SELECT
a.profile_id,
a.name,
a.key,
a.description,
a.create_time,
a.update_time,
(a.active = b'1') active,
(a.visible = b'1') visible
FROM
tab_profile a `
)
return query
}
// parseSet parses a result set result to an entity array
func (c *profileRepo) parseSet(rows *sql.Rows, err error) ([]entity.Profile, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Profile, 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 *profileRepo) parseEntity(row scanner) (retVal entity.Profile, err error) {
err = row.Scan(
&retVal.ID, &retVal.Name, &retVal.Key, &retVal.Description, &retVal.Created, &retVal.Updated, &retVal.Active, &retVal.Visible)
return retVal, errors.Wrap(err)
}
func (c *profileRepo) GetAll() ([]entity.Profile, error) {
return c.parseSet(c.conn.Query(c.getQuery()))
}
func (c *profileRepo) GetByKey(key string) (entity.Profile, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+"WHERE a.active = 1 AND a.key = ?", key))
}
func (c *profileRepo) GetVisibles(visible bool) ([]entity.Profile, error) {
return c.parseSet(c.conn.Query(c.getQuery()+"WHERE a.active = 1 AND a.visible = ?", visible))
}
func (c *profileRepo) GetByOrganizationType(organizationTypeID int64) ([]entity.Profile, error) {
return c.parseSet(c.conn.Query(c.getQuery()+" INNER JOIN tab_organization_type_profile b ON a.profile_id = b.profile_id WHERE a.active = 1 AND a.visible = 1 AND b.organization_type_id = ?", organizationTypeID))
}

421
data/datamysql/provider.go Normal file
View File

@@ -0,0 +1,421 @@
package datamysql
import (
"database/sql"
"fmt"
"strconv"
"time"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
"github.com/go-sql-driver/mysql"
uuid "github.com/satori/go.uuid"
)
// rideRepo maps methods to database
type providerRepo struct {
conn executor
}
func newProviderRepo(conn executor) *providerRepo {
return &providerRepo{
conn: conn,
}
}
func (c *providerRepo) getProfileQuery(user entity.User) (query string, where string, err error) {
if len(user.Profiles) > 0 {
for _, p := range user.Profiles {
switch p.Key {
case "AD", "BCBSIAD", "BDCAD", "PLANAD":
return
case "SP", "SPT":
switch p.Organization.Type.Key {
case "techsupport", "bcbsi", "bcbsa", "plan":
return
case "provider":
query = ` INNER JOIN viw_organization_provider c
ON a.provider_id = c.provider_id `
where = fmt.Sprintf(` AND (c.organization_uuid = '%s' OR c.parent_organization_uuid = '%s') `, p.Organization.UUID, p.Organization.UUID)
return
}
}
}
if query == "" && where == "" {
return "", "", fmt.Errorf("Invalid Query")
} else {
return
}
} else {
return "", "", fmt.Errorf("User has no profile to search")
}
}
func (c *providerRepo) getSelectQueryBaseKey() string {
return `SELECT
a.provider_key_id,
a.provider_id,
a.internal_id,
a.internal_id_suffix,
a.location_seq_num,
a.plan_code,
a.product_id,
a.treatment_category_code,
a.active,
a.enabled,
a.create_at,
a.update_at,
a.created_user
FROM tab_provider_key a `
}
func (c *providerRepo) getSelectQueryBase() string {
return `SELECT DISTINCT
a.provider_id,
a.provider_uuid,
a.provider_internal_id,
a.provider_internal_id_suffix,
a.provider_muk_id,
a.organization_name,
a.gender,
a.accept_new_patients,
a.provider_name,
a.first_name,
a.last_name,
a.middle_name,
a.provider_title,
a.street_name1,
a.street_name2,
a.city_name,
a.state,
a.zipcode,
a.country,
a.latitude,
a.longitude,
a.phone_number,
a.create_at,
a.update_at,
a.active,
a.enabled,
a.created_user,
(3959 * acos (
cos ( radians(?) )
* cos( radians( a.latitude ) )
* cos( radians( a.longitude ) - radians(?) )
+ sin ( radians(?) )
* sin( radians( a.latitude ) )
)) AS distance_in_miles
FROM
tab_provider a
INNER JOIN tab_provider_key b
ON a.provider_id = b.provider_id `
}
func (c *providerRepo) GetAll(user entity.User) ([]entity.Provider, error) {
lat := 41.886406
long := -87.624225
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getSelectQueryBase() + query + " WHERE 1 = 1 " + where
providers, err := c.parseSet(c.conn.Query(query, lat, long, lat))
if err != nil {
return nil, err
}
return c.getKeys("", "", providers)
}
func (c *providerRepo) GetByMukID(mukID 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_muk_id = ? " + where
return c.parseEntity(c.conn.QueryRow(query, lat, long, lat, mukID))
}
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 "
params := make([]interface{}, 0)
if lat == 0 && long == 0 {
lat = 41.886406
long = -87.624225
}
params = append(params, lat, long, lat)
if query != "" && (mukID == "" && internalID == "") {
filter += " AND (a.provider_name LIKE ? OR a.street_name1 LIKE ? OR a.street_name2 LIKE ? OR a.zipcode LIKE ?) "
// MATCH(a.provider_internal_id, a.provider_internal_id_suffix, a.provider_muk_id, a.provider_name, a.street_name1, a.street_name2, a.city_name, a.state, a.zipcode, a.country, a.phone_number) AGAINST (?)
query = "%" + query + "%"
params = append(params, query, query, query, query)
}
if planCode != "" {
filter += " AND b.plan_code = ? "
params = append(params, planCode)
}
if productID != "" {
filter += " AND b.product_id = ? "
params = append(params, productID)
}
if mukID != "" {
filter += " AND a.provider_muk_id = ? "
params = append(params, mukID)
}
if internalID != "" {
filter += " AND a.provider_internal_id = ? "
params = append(params, internalID)
}
final := " HAVING distance_in_miles < ? "
params = append(params, distance)
if sort == "name" {
final += " ORDER BY a.provider_name ASC "
} else if sort == "distance" {
final += " ORDER BY distance_in_miles ASC "
}
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getSelectQueryBase() + query + filter + where + final
providers, err := c.parseSet(c.conn.Query(query, params...))
if err != nil {
return nil, err
}
if len(providers) > 0 {
return c.getKeys(planCode, productID, providers)
} else {
return providers, nil
}
}
func (c *providerRepo) getKeys(planCode string, productID string, providers []entity.Provider) ([]entity.Provider, error) {
var params []interface{}
var queryParams = " WHERE a.provider_id IN ("
for _, p := range providers {
queryParams += "?,"
params = append(params, p.ProviderID)
}
queryParams = queryParams[0 : len(queryParams)-1]
queryParams += ") "
if planCode != "" {
queryParams += " AND a.plan_code = ? "
params = append(params, planCode)
}
if productID != "" {
queryParams += " AND a.product_id = ? "
params = append(params, productID)
}
keys, err := c.parseKeySet(c.conn.Query(c.getSelectQueryBaseKey()+queryParams, params...))
if err != nil {
return nil, err
}
sortedResults := make(map[string][]entity.ProviderKey)
for _, k := range keys {
sortedKey := fmt.Sprintf("provider%v", k.Provider.ProviderID)
sortedResults[sortedKey] = append(sortedResults[sortedKey], k)
}
for i := range providers {
sortedKey := fmt.Sprintf("provider%v", providers[i].ProviderID)
providers[i].Keys = sortedResults[sortedKey]
}
return providers, nil
}
// parseSet parses a result set result to an entity array
func (c *providerRepo) parseKeySet(rows *sql.Rows, err error) ([]entity.ProviderKey, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.ProviderKey, 0)
for rows.Next() {
entity, err := c.parseKeyEntity(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 *providerRepo) parseKeyEntity(row scanner) (retVal entity.ProviderKey, err error) {
err = row.Scan(
&retVal.ProviderKeyID, &retVal.Provider.ProviderID, &retVal.InternalID, &retVal.InternalSuffixID, &retVal.LocationSeqNumber, &retVal.PlanCode, &retVal.ProductID, &retVal.TreatmentCategoryCode, &retVal.Active, &retVal.Enabled, &retVal.CreateDate, &retVal.UpdateDate, &retVal.CreatedUser.ID)
return retVal, errors.Wrap(err)
}
// parseSet parses a result set result to an entity array
func (c *providerRepo) parseSet(rows *sql.Rows, err error) ([]entity.Provider, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Provider, 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 *providerRepo) parseEntity(row scanner) (retVal entity.Provider, err error) {
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)
return retVal, errors.Wrap(err)
}
func (c *providerRepo) Save(providers []entity.ProviderResponse, user entity.User) ([]entity.Provider, error) {
var savedProviders = make([]entity.Provider, 0)
for _, p := range providers {
provider, err := c.saveProvider(p, user)
if err != nil {
if driverErr, ok := err.(*mysql.MySQLError); ok {
if driverErr.Number != 1062 {
return nil, err
}
} else {
return nil, err
}
} else {
savedProviders = append(savedProviders, provider)
}
}
return savedProviders, nil
}
func (c *providerRepo) saveProvider(provider entity.ProviderResponse, user entity.User) (entity.Provider, error) {
const (
query = `INSERT INTO tab_provider(provider_uuid,provider_internal_id,provider_internal_id_suffix,provider_muk_id,organization_name,gender,accept_new_patients,provider_name,first_name,last_name,middle_name,provider_title,street_name1,street_name2,city_name,state,zipcode,country,latitude,longitude,phone_number,created_user)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);`
)
UUID, _ := uuid.NewV4()
lat, _ := strconv.ParseFloat(provider.Latitude, 64)
long, _ := strconv.ParseFloat(provider.Longitude, 64)
p := entity.Provider{
ProviderUUID: UUID.String(),
InternalID: provider.FivePartKeyGroups[0].ProviderNum,
InternalSuffixID: provider.FivePartKeyGroups[0].ProviderNumSuffix,
MukID: provider.MukID,
OrganizatioName: provider.OrgName,
Gender: provider.Gender,
AcceptNewPatients: provider.AcceptNewPatients,
Name: provider.ProviderName,
FirstName: provider.FirstName,
MiddleName: provider.MiddleName,
LastName: provider.LastName,
Title: provider.ProviderTitle,
Address: entity.ProviderAddress{
StreetAddress1: provider.StreetName1,
StreetAddress2: provider.StreetName2,
CityName: provider.CityName,
State: provider.State,
ZipCode: provider.ZipCode,
Country: provider.Country,
Latitude: lat,
Longitude: long,
PhoneNumber: provider.PhoneNumber,
},
CreateDate: time.Now(),
UpdateDate: time.Now(),
Active: true,
Enabled: true,
}
result, err := c.conn.Exec(query, p.ProviderUUID, p.InternalID, p.InternalSuffixID, p.MukID, p.OrganizatioName, p.Gender, p.AcceptNewPatients, p.Name, p.FirstName, p.LastName, p.MiddleName, p.Title, p.Address.StreetAddress1, p.Address.StreetAddress2, p.Address.CityName, p.Address.State, p.Address.ZipCode, p.Address.Country, p.Address.Latitude, p.Address.Longitude, p.Address.PhoneNumber, 1)
if err != nil {
if driverErr, ok := err.(*mysql.MySQLError); ok {
if driverErr.Number != 1062 {
return entity.Provider{}, err
} else {
tempProvider, err := c.GetByMukID(p.MukID, user)
if err != nil {
return entity.Provider{}, err
}
p.ProviderID = tempProvider.ProviderID
}
}
} else {
p.ProviderID, err = result.LastInsertId()
if err != nil {
return entity.Provider{}, err
}
}
var providerKeys []entity.ProviderKey
for _, fk := range provider.FivePartKeyGroups {
key, err := c.saveKeys(p.ProviderID, fk)
if err != nil {
return p, err
}
providerKeys = append(providerKeys, key)
}
p.Keys = providerKeys
return p, nil
}
func (c *providerRepo) saveKeys(ProviderID int64, fk entity.PartKeyGroup) (entity.ProviderKey, error) {
const (
query = `INSERT INTO tab_provider_key (provider_id, internal_id, internal_id_suffix, location_seq_num, plan_code, product_id, treatment_category_code, created_user)
VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE provider_id = ?, internal_id = ?, internal_id_suffix = ?, location_seq_num = ?, plan_code = ?, product_id = ?, treatment_category_code = ?, created_user = ?;`
)
key := entity.ProviderKey{
InternalID: fk.ProviderNum,
InternalSuffixID: fk.ProviderNumSuffix,
TreatmentCategoryCode: fk.TreatmentCategoryCode,
ProductID: fk.ProductID,
PlanCode: fk.PlanCode,
LocationSeqNumber: fk.LocationSeqNum,
Provider: entity.Provider{
ProviderID: ProviderID,
},
}
result, err := c.conn.Exec(query, key.Provider.ProviderID, key.InternalID, key.InternalSuffixID, key.LocationSeqNumber, key.PlanCode, key.ProductID, key.TreatmentCategoryCode, 1, key.Provider.ProviderID, key.InternalID, key.InternalSuffixID, key.LocationSeqNumber, key.PlanCode, key.ProductID, key.TreatmentCategoryCode, 1)
if err != nil {
return key, err
}
key.ProviderKeyID, err = result.LastInsertId()
if err != nil {
return key, err
}
return key, nil
}

826
data/datamysql/ride.go Normal file
View File

@@ -0,0 +1,826 @@
package datamysql
import (
"database/sql"
"fmt"
"time"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
"github.com/go-sql-driver/mysql"
uuid "github.com/satori/go.uuid"
)
// rideRepo maps methods to database
type rideRepo struct {
conn executor
}
func newRideRepo(conn executor) *rideRepo {
return &rideRepo{
conn: conn,
}
}
func (c *rideRepo) getQuery() string {
const query = `SELECT
a.ride_id,
a.ride_uuid,
b.user_id,
b.user_uuid,
b.name,
b.member,
c.ride_status_id,
c.ride_status,
c.key ride_status_key,
d.ride_type_id,
d.value ride_type,
d.key ride_type_key,
a.notes,
e.first_name,
e.last_name,
e.image_url,
e.phone_number,
e.internal_user_id,
IFNULL(f.name, '') driver_name,
IFNULL(f.phone_number, '') driver_phone_number,
IFNULL(f.image_url, '') driver_image_url,
IFNULL(f.rating, '') driver_rating,
IFNULL(g.color, '') vehicle_color,
IFNULL(g.image_url, '') vehicle_image_url,
IFNULL(g.license_plate, '') vehicle_license_plate,
IFNULL(g.license_plate_state, '') vehicle_license_state,
IFNULL(g.make, '') vehicle_make,
IFNULL(g.model, '') vehicle_model,
IFNULL(g.year, 0) vehicle_year,
h.origin_name,
h.origin_address,
h.origin_lat,
h.origin_lng,
h.destination_name,
h.destination_address,
h.destination_lat,
h.destination_lng,
IFNULL(h.route_kml, '') route_kml,
IFNULL(h.distance, 0) distance,
IFNULL(h.duration, 0) duration,
IFNULL(h.eta, 0) eta,
a.pickup_time,
a.visit_date,
a.visit_time,
a.ride_internal_id,
a.visit_id,
i.visit_uuid,
IFNULL(i.pickup_id, '') visit_pickup_id,
IFNULL(i.pickup_address_id, 0) pickup_address_id,
IFNULL(i.address_id, 0) address_id,
IFNULL(i.provider_id, 0) provider_id,
IFNULL(o.provider_uuid, '') provider_uuid,
IFNULL(o.provider_internal_id, '') provider_internal_id,
IFNULL(o.provider_muk_id, '') provider_muk_id,
IFNULL(o.provider_name, '') provider_name,
-- i.pickup_name visit_pickup_name,
-- i.pickup_address visit_pickup_address,
-- i.pickup_lat visit_pickup_lat,
-- i.pickup_lng visit_pickup_lng,
-- IFNULL(i.destination_id, '') visit_destination_id,
-- i.destination_name visit_destination_name,
-- i.destination_address visit_destination_address,
-- i.destination_lat visit_destination_lat,
-- i.destination_lng visit_destination_lng,
IFNULL(i.visit_external_id, '') visit_external_id,
i.created_user_id,
j.user_uuid created_user_uuid,
j.name created_name,
IFNULL(k.phone_number, '') created_user_phone_number,
IFNULL(k.email, '') created_user_email,
IFNULL(l.phone_number, '') user_phone_number,
IFNULL(l.email, '') user_email,
a.create_date,
a.update_date,
m.trip_type_id,
m.trip_type_key,
m.trip_type,
n.trip_type_id visit_trip_type_id,
n.trip_type_key visit_trip_type_key,
n.trip_type visit_trip_type_key,
i.return_date
FROM tab_ride a
INNER JOIN tab_user b
ON a.user_id = b.user_id
INNER JOIN tab_ride_status c
ON c.ride_status_id = a.ride_status_id
INNER JOIN tab_ride_type d
ON d.ride_type_id = a.ride_type_id
INNER JOIN tab_ride_passenger e
ON e.ride_id = a.ride_id
LEFT JOIN tab_ride_driver f
ON f.ride_id = a.ride_id
LEFT JOIN tab_ride_vehicle g
ON g.ride_id = a.ride_id
INNER JOIN tab_ride_route h
ON h.ride_id = a.ride_id
INNER JOIN tab_visit i
ON i.visit_id = a.visit_id
INNER JOIN tab_user j
ON j.user_id = i.created_user_id
INNER JOIN tab_login k
ON k.user_id = j.user_id
INNER JOIN tab_login l
ON l.user_id = a.user_id
INNER JOIN tab_trip_type m
ON m.trip_type_id = a.trip_type_id
INNER JOIN tab_trip_type n
ON n.trip_type_id = i.trip_type_id
INNER JOIN tab_provider o
ON i.provider_id = o.provider_id `
return query
}
func (c *rideRepo) getProfileQuery(user entity.User) (query string, where string, err error) {
if len(user.Profiles) > 0 {
for _, p := range user.Profiles {
switch p.Key {
case "AD", "BCBSIAD", "BDCAD", "PLANAD":
return
case "SP", "SPT":
switch p.Organization.Type.Key {
case "techsupport", "bcbsi", "bcbsa", "plan":
return
case "provider":
query = `INNER JOIN viw_visit_provider o ON a.ride_id = o.ride_id`
where = fmt.Sprintf(` AND (o.organization_uuid = '%s' OR o.parent_organization_uuid = '%s') `, p.Organization.UUID, p.Organization.UUID)
return
}
}
}
if query == "" && where == "" {
return "", "", fmt.Errorf("Invalid Query")
} else {
return
}
} else {
return "", "", fmt.Errorf("User has no profile to search")
}
}
func (c *rideRepo) Update(hook entity.WebhookResponse, user entity.User) (retVal entity.Ride, err error) {
oldRide, err := c.GetByUUID(hook.Ride.UUID, user)
if err != nil {
return retVal, err
}
retVal, err = c.updateHeader(hook.Ride)
if err != nil {
return retVal, err
}
retVal, err = c.updateLocation(hook.Ride)
if err != nil {
return retVal, err
}
// retVal, err = c.updatePassenger(hook.Ride)
// if err != nil {
// return retVal, err
// }
if oldRide.Driver.Name != "" {
retVal, err = c.updateDriver(hook.Ride)
} else {
retVal, err = c.saveDriver(hook.Ride)
}
if err != nil {
return retVal, err
}
if oldRide.Vehicle.LicensePlate != "" {
retVal, err = c.updateVehicle(hook.Ride)
} else {
retVal, err = c.saveVehicle(hook.Ride)
}
if err != nil {
return retVal, err
}
go func() {
err := c.saveHistory(hook)
if err != nil {
fmt.Println("Error to save history: " + err.Error())
}
}()
return retVal, nil
}
func (c *rideRepo) updateVehicle(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = `UPDATE tab_ride_vehicle
SET
color = ?,
image_url = ?,
license_plate = ?,
license_plate_state = ?,
make = ?,
model = ?,
year = ?
WHERE ride_id = ?;`
)
retVal = ride
_, err = c.conn.Exec(query, ride.Vehicle.Color, ride.Vehicle.ImageURL, ride.Vehicle.LicensePlate, ride.Vehicle.LicensePlateState, ride.Vehicle.Make, ride.Vehicle.Model, ride.Vehicle.Year, ride.ID)
if err != nil {
return retVal, err
}
return retVal, nil
}
func (c *rideRepo) updateDriver(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = `UPDATE tab_ride_driver
SET
name = ?,
image_url = ?,
phone_number = ?,
rating = ?
WHERE ride_id = ?;`
)
retVal = ride
_, err = c.conn.Exec(query, ride.Driver.Name, ride.Driver.ImageURL, ride.Driver.PhoneNumber, ride.Driver.Rating, ride.ID)
if err != nil {
return retVal, err
}
return retVal, nil
}
func (c *rideRepo) updatePassenger(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = `UPDATE tab_ride_passenger
SET
first_name = ?,
last_name = ?,
image_url = ?,
phone_number = ?,
internal_user_id = ?
WHERE ride_id = ?;`
)
retVal = ride
_, err = c.conn.Exec(query, ride.Passenger.FirstName, ride.Passenger.LastName, ride.Passenger.ImageURL, ride.Passenger.PhoneNumber, ride.Passenger.InternalID, ride.ID)
if err != nil {
return retVal, err
}
return retVal, nil
}
func (c *rideRepo) updateLocation(ride entity.Ride) (retVal entity.Ride, err error) {
query := `UPDATE tab_ride_route
SET
origin_address = ?,
origin_lat = ?,
origin_lng = ?,
destination_address = ?,
destination_lat = ?,
destination_lng = ?,
route_kml = ?,
distance = ?,
duration = ?,
eta = ?`
where := ` WHERE ride_id = ?;`
retVal = ride
params := make([]interface{}, 0)
params = append(params, ride.Route.Origin.Address, ride.Route.Origin.Latitude, ride.Route.Origin.Longitude, ride.Route.Destination.Address, ride.Route.Destination.Latitude, ride.Route.Destination.Longitude, ride.Route.RouteKML, ride.Route.Distance, ride.Route.Duration, ride.Route.ETA)
if retVal.Route.Origin.Name != "" {
query += " , origin_name = ? "
params = append(params, ride.Route.Origin.Name)
}
if retVal.Route.Destination.Name != "" {
query += " , destination_name = ? "
params = append(params, ride.Route.Destination.Name)
}
params = append(params, ride.ID)
_, err = c.conn.Exec(query+where, params...)
if err != nil {
return retVal, err
}
return retVal, nil
}
func (c *rideRepo) updateHeader(ride entity.Ride) (retVal entity.Ride, err error) {
const (
statusQuery = "SELECT ride_status_id FROM tab_ride_status WHERE `key` = ?"
query = `UPDATE tab_ride
SET
ride_status_id = ?,
ride_type_id = ?,
ride_internal_id = ?,
request_date = ?,
request_ms = ?,
generate_date = ?,
generate_ms = ?,
route_kml = ?,
notes = ?,
primetime_percentage = ?,
pickup_time = ?,
visit_date = ?,
visit_time = ?,
visit_id = ?
WHERE ride_uuid = ?;`
)
row := c.conn.QueryRow(statusQuery, ride.Status.Key)
err = row.Scan(&ride.Status.ID)
if err != nil {
fmt.Println("Error to get status")
return retVal, err
}
retVal = ride
_, err = c.conn.Exec(query, ride.Status.ID, ride.Type.ID, ride.InternalID, ride.RequestDate, ride.RequestMiliseconds, ride.GenerateDate, ride.GenerateMiliseconds, ride.Route.RouteKML, ride.Note, ride.PrimetimePercentage, ride.PickupTime, ride.VisitDate, ride.VisitTime, ride.Visit.ID, ride.UUID)
if err != nil {
return retVal, err
}
return ride, nil
}
func (c *rideRepo) Save(ride entity.Ride) (retVal entity.Ride, err error) {
retVal, err = c.saveHeader(ride)
if err != nil {
fmt.Println("Error to save header")
return retVal, err
}
retVal, err = c.saveLocation(retVal)
if err != nil {
fmt.Println("Error to save location")
return retVal, err
}
retVal, err = c.savePassenger(retVal)
if err != nil {
fmt.Println("Error to save passenger")
return retVal, err
}
retVal, err = c.saveDriver(retVal)
if err != nil {
fmt.Println("Error to save driver")
return retVal, err
}
retVal, err = c.saveVehicle(retVal)
if err != nil {
fmt.Println("Error to save vehicle")
return retVal, err
}
go func() {
hook := entity.WebhookResponse{
Ride: retVal,
}
err = c.saveHistory(hook)
if err != nil {
fmt.Println("Error to save history: ", err.Error())
}
}()
return retVal, err
}
func (c *rideRepo) saveHistory(hook entity.WebhookResponse) error {
rideHistoryID, err := c.saveHistoryHeader(hook)
if err != nil {
fmt.Println("Error to save header history")
return err
}
if err = c.saveLocationHistory(rideHistoryID, hook.Ride.Route); err != nil {
fmt.Println("Error to save location history")
return err
}
if err = c.savePassengerHistory(rideHistoryID, hook.Ride.Passenger); err != nil {
fmt.Println("Error to save passenger history")
return err
}
if err = c.saveDriverHistory(rideHistoryID, hook.Ride.Driver); err != nil {
fmt.Println("Error to save driver history")
return err
}
if err = c.saveVehicleHistory(rideHistoryID, hook.Ride.Vehicle); err != nil {
fmt.Println("Error to save vehicle history")
return err
}
return nil
}
func (c *rideRepo) saveVehicleHistory(rideHistoryID int64, vehicle entity.RideVehicle) error {
const (
query = "INSERT INTO tab_ride_vehicle_history(ride_history_id,color,image_url,license_plate,license_plate_state,make,model,`year`) VALUES(?,?,?,?,?,?,?,?);"
)
if vehicle.Make != "" && vehicle.Model != "" && vehicle.Color != "" && vehicle.Year > 0 {
_, err := c.conn.Exec(query, rideHistoryID, vehicle.Color, vehicle.ImageURL, vehicle.LicensePlate, vehicle.LicensePlateState, vehicle.Make, vehicle.Model, vehicle.Year)
if err != nil {
return err
}
}
return nil
}
func (c *rideRepo) saveDriverHistory(rideHistoryID int64, driver entity.RideDriver) error {
const (
query = "INSERT INTO tab_ride_driver_history(ride_history_id,name,image_url,phone_number,rating) VALUES(?,?,?,?,?);"
)
if driver.Name != "" && driver.PhoneNumber != "" {
_, err := c.conn.Exec(query, rideHistoryID, driver.Name, driver.ImageURL, driver.PhoneNumber, driver.Rating)
if err != nil {
return err
}
}
return nil
}
func (c *rideRepo) savePassengerHistory(rideHistoryID int64, passenger entity.RidePassenger) error {
const (
query = "INSERT INTO tab_ride_passenger_history(ride_history_id,first_name,last_name,image_url,phone_number,internal_user_id) VALUES(?,?,?,?,?,?)"
)
_, err := c.conn.Exec(query, rideHistoryID, passenger.FirstName, passenger.LastName, "", passenger.PhoneNumber, passenger.InternalID)
if err != nil {
return err
}
return nil
}
func (c *rideRepo) saveLocationHistory(rideHistoryID int64, route entity.RideRoute) error {
const (
query = `INSERT INTO tab_ride_route_history(ride_history_id,origin_name,origin_address,origin_lat,origin_lng,destination_name,destination_address,destination_lat,destination_lng,route_kml,distance,duration,eta)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?);`
)
if route.Origin.Latitude != 0 && route.Origin.Longitude != 0 && route.Destination.Latitude != 0 && route.Destination.Longitude != 0 {
_, err := c.conn.Exec(query, rideHistoryID, route.Origin.Name, route.Origin.Address, route.Origin.Latitude, route.Origin.Longitude, route.Destination.Name, route.Destination.Address, route.Destination.Latitude, route.Destination.Longitude, route.RouteKML, route.Distance, route.Duration, route.ETA)
if err != nil {
return err
}
}
return nil
}
func (c *rideRepo) saveHistoryHeader(hook entity.WebhookResponse) (int64, error) {
const (
query = `INSERT INTO tab_ride_history(ride_history_uuid,ride_id,event_id,href,occurred_at,event_type,ride_internal_id,ride_status_id,ride_type_id,request_date,request_ms,generate_date,generate_ms,route_kml,notes, primetime_percentage, pickup_time, visit_date, visit_time, visit_id)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);`
)
UUID, _ := uuid.NewV4()
sUUID := UUID.String()
if hook.OccurredAt.IsZero() {
hook.OccurredAt = time.Now()
}
results, err := c.conn.Exec(query, sUUID, hook.Ride.ID, hook.EventID, hook.HREF, hook.OccurredAt, hook.EventType, hook.Ride.InternalID, hook.Ride.Status.ID, hook.Ride.Type.ID, hook.Ride.RequestDate, hook.Ride.RequestMiliseconds, hook.Ride.GenerateDate, hook.Ride.GenerateMiliseconds, hook.Ride.Route.RouteKML, hook.Ride.Note, hook.Ride.PrimetimePercentage, hook.Ride.PickupTime, hook.Ride.VisitDate, hook.Ride.VisitTime, hook.Ride.Visit.ID)
if err != nil {
return 0, err
}
return results.LastInsertId()
}
func (c *rideRepo) saveHeader(ride entity.Ride) (retVal entity.Ride, err error) {
const (
dataQuery = `SELECT
a.user_id user_id,
a.name,
a.member,
b.ride_status_id,
b.ride_status,
c.ride_type_id,
c.value ride_type,
d.user_id created_user_id,
d.name created_name,
IFNULL(d.member, '') created_member,
e.trip_type_id,
e.trip_type_key,
e.trip_type
FROM tab_user a,
tab_ride_status b,
tab_ride_type c,
tab_user d,
tab_trip_type e
WHERE
a.user_uuid = ?
AND b.key = ?
AND c.key = ?
AND d.user_uuid = ?
AND e.trip_type_key = ?;`
query = `INSERT INTO tab_ride(ride_uuid, user_id, ride_status_id, ride_type_id, ride_internal_id, request_date, request_ms, generate_date, generate_ms, notes, primetime_percentage, pickup_time, visit_date, visit_time, visit_id, created_user_id, trip_type_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`
)
retVal = ride
UUID, _ := uuid.NewV4()
retVal.UUID = UUID.String()
if retVal.Status.Key == "" {
retVal.Status.Key = "accepted"
}
if retVal.Type.Key == "" {
retVal.Type.Key = "lyft"
}
row := c.conn.QueryRow(dataQuery, retVal.User.UUID, retVal.Status.Key, retVal.Type.Key, retVal.CreatedUser.UUID, retVal.TripType.Key)
if err = row.Scan(&retVal.User.ID, &retVal.User.Name, &retVal.User.Member, &retVal.Status.ID, &retVal.Status.Value, &retVal.Type.ID, &retVal.Type.Value, &retVal.CreatedUser.ID, &retVal.CreatedUser.Name, &retVal.CreatedUser.Member, &retVal.TripType.ID, &retVal.TripType.Key, &retVal.TripType.Value); err != nil {
fmt.Println("Error to get base data: ", err.Error())
return retVal, err
}
results, err := c.conn.Exec(query, retVal.UUID, retVal.User.ID, retVal.Status.ID, retVal.Type.ID, retVal.InternalID, retVal.RequestDate, retVal.RequestMiliseconds, retVal.GenerateDate, retVal.GenerateMiliseconds, retVal.Note, retVal.PrimetimePercentage, retVal.PickupTime, retVal.VisitDate, retVal.VisitTime, retVal.Visit.ID, retVal.CreatedUser.ID, retVal.TripType.ID)
if err != nil {
fmt.Println("Error: ", err.Error())
return retVal, err
}
var ID int64
ID, err = results.LastInsertId()
if err != nil {
fmt.Println("Error Getting the ID: ", err.Error())
return retVal, err
}
retVal.ID = ID
return retVal, nil
}
func (c *rideRepo) saveLocation(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = `INSERT INTO tab_ride_route(ride_id,origin_name,origin_address,origin_lat,origin_lng,destination_name,destination_address,destination_lat,destination_lng,route_kml,distance,duration,eta)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?);`
)
retVal = ride
results, err := c.conn.Exec(query, retVal.ID, retVal.Route.Origin.Name, retVal.Route.Origin.Address, retVal.Route.Origin.Latitude, retVal.Route.Origin.Longitude, retVal.Route.Destination.Name, retVal.Route.Destination.Address, retVal.Route.Destination.Latitude, retVal.Route.Destination.Longitude, retVal.Route.RouteKML, retVal.Route.Distance, retVal.Route.Duration, retVal.Route.ETA)
if err != nil {
return retVal, err
}
var ID int64
ID, err = results.LastInsertId()
if err != nil {
fmt.Println("Error Getting the ID: ", err.Error())
return retVal, err
}
retVal.Route.ID = ID
return retVal, nil
}
func (c *rideRepo) savePassenger(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = `INSERT INTO tab_ride_passenger(ride_id,first_name,last_name,image_url,phone_number,internal_user_id)
VALUES(?,?,?,?,?,?);`
)
retVal = ride
results, err := c.conn.Exec(query, retVal.ID, ride.Passenger.FirstName, ride.Passenger.LastName, ride.Passenger.ImageURL, ride.Passenger.PhoneNumber, ride.Passenger.InternalID)
if err != nil {
return retVal, err
}
var ID int64
ID, err = results.LastInsertId()
if err != nil {
fmt.Println("Error Getting the ID: ", err.Error())
return retVal, err
}
retVal.Passenger.ID = ID
return retVal, nil
}
func (c *rideRepo) saveDriver(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = "INSERT INTO tab_ride_driver(ride_id,`name`,image_url,phone_number,rating) VALUES(?,?,?,?,?);"
)
retVal = ride
if retVal.Driver.Name != "" && retVal.Driver.PhoneNumber != "" {
results, err := c.conn.Exec(query, retVal.ID, ride.Driver.Name, ride.Driver.ImageURL, ride.Driver.PhoneNumber, ride.Driver.Rating)
if err != nil {
return retVal, err
}
var ID int64
ID, err = results.LastInsertId()
if err != nil {
fmt.Println("Error Getting the ID: ", err.Error())
return retVal, err
}
retVal.Driver.ID = ID
}
return retVal, nil
}
func (c *rideRepo) saveVehicle(ride entity.Ride) (retVal entity.Ride, err error) {
const (
query = "INSERT INTO tab_ride_vehicle(ride_id,color,image_url,license_plate,license_plate_state,make,model,`year`) VALUES(?,?,?,?,?,?,?,?);"
)
retVal = ride
if retVal.Vehicle.Color != "" && retVal.Vehicle.LicensePlate != "" && retVal.Vehicle.Make != "" && retVal.Vehicle.Model != "" && retVal.Vehicle.Year > 0 {
results, err := c.conn.Exec(query, retVal.ID, ride.Vehicle.Color, ride.Vehicle.ImageURL, ride.Vehicle.LicensePlate, ride.Vehicle.LicensePlateState, ride.Vehicle.Make, ride.Vehicle.Model, ride.Vehicle.Year)
if err != nil {
return retVal, err
}
var ID int64
ID, err = results.LastInsertId()
if err != nil {
fmt.Println("Error Getting the ID: ", err.Error())
return retVal, err
}
retVal.Vehicle.ID = ID
}
return retVal, nil
}
func (c *rideRepo) GetByUUID(uuid string, user entity.User) (entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Ride{}, err
}
query = c.getQuery() + query + " WHERE a.ride_uuid = ? " + where
return c.parseEntity(c.conn.QueryRow(query, uuid))
}
func (c *rideRepo) GetByID(id int64, user entity.User) (entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Ride{}, err
}
query = c.getQuery() + query + " WHERE a.ride_id = ? " + where
return c.parseEntity(c.conn.QueryRow(query, id))
}
func (c *rideRepo) GetByUUIDAndUserUUID(UUID string, userUUID string) (entity.Ride, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE a.ride_uuid = ? AND b.user_uuid = ?", UUID, userUUID))
}
func (c *rideRepo) GetLastRideByPhoneNumber(phoneNumber string) (entity.Ride, error) {
query := c.getQuery() + ` WHERE c.ride_status IN ('accepted', 'arrived', 'scheduled', 'pending')
AND l.phone_number = ?
ORDER BY a.create_date DESC
LIMIT 1;`
return c.parseEntity(c.conn.QueryRow(query, phoneNumber))
}
func (c *rideRepo) GetLastRideByDriversNumber(phoneNumber string) (entity.Ride, error) {
query := c.getQuery() + ` WHERE c.ride_status IN ('accepted', 'arrived', 'scheduled', 'pending')
AND IFNULL(f.phone_number, '') = ?
ORDER BY a.create_date DESC
LIMIT 1;`
return c.parseEntity(c.conn.QueryRow(query, phoneNumber))
}
func (c *rideRepo) GetByInternalID(internalID string) (entity.Ride, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE a.ride_internal_id = ?", internalID))
}
func (c *rideRepo) GetByInternalPassengerID(internalPassengerID string) (entity.Ride, error) {
return c.parseEntity(c.conn.QueryRow(c.getQuery()+" WHERE e.internal_user_id = ?", internalPassengerID))
}
func (c *rideRepo) GetByUserID(userID int64, user entity.User) ([]entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getQuery() + query + " WHERE b.user_id = ? " + where
return c.parseSet(c.conn.Query(query, userID))
}
func (c *rideRepo) GetByUserUUID(userUUID string, user entity.User) ([]entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getQuery() + query + " WHERE b.user_uuid = ? " + where
return c.parseSet(c.conn.Query(query, userUUID))
}
func (c *rideRepo) GetByVisitUUID(visitUUID string, user entity.User) ([]entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getQuery() + query + " WHERE b.user_id = ? " + where
return c.parseSet(c.conn.Query(query, visitUUID))
}
func (c *rideRepo) GetByVisitUUIDAndTripType(visitUUID string, tripTypeKey string, user entity.User) (entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Ride{}, err
}
query = c.getQuery() + query + " WHERE i.visit_uuid = ? AND m.trip_type_key = ? " + where
return c.parseEntity(c.conn.QueryRow(query, visitUUID, tripTypeKey))
}
func (c *rideRepo) parseSet(rows *sql.Rows, err error) ([]entity.Ride, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Ride, 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 *rideRepo) parseEntity(row scanner) (r entity.Ride, err error) {
var returnDate mysql.NullTime
err = row.Scan(&r.ID, &r.UUID, &r.User.ID, &r.User.UUID, &r.User.Name, &r.User.Member, &r.Status.ID, &r.Status.Value, &r.Status.Key, &r.Type.ID, &r.Type.Value, &r.Type.Key, &r.Note, &r.Passenger.FirstName, &r.Passenger.LastName, &r.Passenger.ImageURL, &r.Passenger.PhoneNumber, &r.Passenger.InternalID, &r.Driver.Name, &r.Driver.PhoneNumber, &r.Driver.ImageURL, &r.Driver.Rating, &r.Vehicle.Color, &r.Vehicle.ImageURL, &r.Vehicle.LicensePlate, &r.Vehicle.LicensePlateState, &r.Vehicle.Make, &r.Vehicle.Model, &r.Vehicle.Year, &r.Route.Origin.Name, &r.Route.Origin.Address, &r.Route.Origin.Latitude, &r.Route.Origin.Longitude, &r.Route.Destination.Name, &r.Route.Destination.Address, &r.Route.Destination.Latitude, &r.Route.Destination.Longitude, &r.Route.RouteKML, &r.Route.Distance, &r.Route.Duration, &r.Route.ETA, &r.PickupTime, &r.VisitDate, &r.VisitTime, &r.InternalID, &r.Visit.ID, &r.Visit.UUID, &r.Visit.Pickup.ID, &r.Visit.PickupAddressID, &r.Visit.DestinationAddressID, &r.Visit.Provider.ProviderID, &r.Visit.Provider.ProviderUUID, &r.Visit.Provider.InternalID, &r.Visit.Provider.MukID, &r.Visit.Provider.Name, &r.Visit.ExternalID, &r.Visit.CreatedUser.ID, &r.Visit.CreatedUser.UUID, &r.Visit.CreatedUser.Name, &r.Visit.CreatedUser.PhoneNumber, &r.Visit.CreatedUser.Email, &r.User.PhoneNumber, &r.User.Email, &r.Created, &r.Updated, &r.TripType.ID, &r.TripType.Key, &r.TripType.Value, &r.Visit.TripType.ID, &r.Visit.TripType.Key, &r.Visit.TripType.Value, &returnDate)
if err != nil {
return r, errors.Wrap(err)
}
r.CreatedUser = r.Visit.CreatedUser
if returnDate.Valid {
r.Visit.ReturnDate = &returnDate.Time
}
return r, nil
}
func (c *rideRepo) UpdateStatus(rideUUID string, status string) error {
const (
statusQuery = "SELECT ride_status_id FROM tab_ride_status WHERE `key` = ?"
query = "UPDATE tab_ride SET ride_status_id = ? WHERE ride_uuid = ?"
)
var rideStatusID int64
row := c.conn.QueryRow(statusQuery, status)
err := row.Scan(&rideStatusID)
if err != nil {
return err
}
_, err = c.conn.Exec(query, rideStatusID, rideUUID)
if err != nil {
return err
}
return nil
}
func (c *rideRepo) GetAll(user entity.User) ([]entity.Ride, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getQuery() + query + " WHERE 1 = 1 AND b.active = 1 " + where
return c.parseSet(c.conn.Query(query))
}

View File

@@ -0,0 +1,87 @@
package datamysql
import (
"database/sql"
"bitbucket.org/nemt/nemt-portal-api/domain/contract"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
type transaction struct {
tx *sql.Tx
users *userRepo
rides *rideRepo
visits *visitRepo
provider *providerRepo
notification *notificationRepo
profile *profileRepo
organization *organizationRepo
}
func newTransaction(tx *sql.Tx) *transaction {
t := new(transaction)
t.tx = tx
t.users = newUserRepo(tx)
t.rides = newRideRepo(tx)
t.visits = newVisitRepo(tx)
t.provider = newProviderRepo(tx)
return t
}
// Users returns the users set
func (t transaction) Users() contract.UserRepo {
return t.users
}
// Rides returns the rides set
func (t transaction) Rides() contract.RideRepo {
return t.rides
}
// Rides returns the rides set
func (t transaction) Visits() contract.VisitRepo {
return t.visits
}
// Provider returns the rides set
func (t transaction) Provider() contract.ProviderRepo {
return t.provider
}
// Provider returns the rides set
func (t transaction) Profile() contract.ProfileRepo {
return t.profile
}
// Provider returns the rides set
func (t transaction) Notification() contract.NotificationRepo {
return t.notification
}
// Provider returns the rides set
func (t transaction) Organization() contract.OrganizationRepo {
return t.organization
}
func (t *transaction) Commit() error {
err := t.tx.Commit()
if err != nil {
return errors.Wrap(err)
}
return nil
}
func (t *transaction) Rollback() error {
err := t.tx.Rollback()
if err != nil {
return errors.Wrap(err)
}
return nil
}

825
data/datamysql/user.go Normal file
View File

@@ -0,0 +1,825 @@
package datamysql
import (
"database/sql"
"fmt"
"time"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
"github.com/go-sql-driver/mysql"
uuid "github.com/satori/go.uuid"
)
// userRepo maps methods to database
type userRepo struct {
conn executor
}
func newUserRepo(conn executor) *userRepo {
return &userRepo{
conn: conn,
}
}
func (c *userRepo) GetByUUID(uuid string, profile string) (entity.User, error) {
params := make([]interface{}, 0)
params = append(params, uuid)
finalQuery := c.getQuery() + " AND a.user_uuid = ? "
if profile == "US" {
finalQuery += " AND e.key = ? "
params = append(params, profile)
}
user, err := c.parseSet(c.conn.Query(finalQuery, params...))
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) GetContacts(userID int64) ([]entity.ContactInfo, error) {
const (
query = `
SELECT
a.contact_id,
a.contact,
a.user_id,
b.contact_type_id,
b.key contact_type_key,
b.name contact_type_name
FROM tab_contact a
INNER JOIN tab_contact_type b
ON a.contact_type_id = b.contact_type_id
WHERE a.user_id = ?;
`
)
rows, err := c.conn.Query(query, userID)
if err != nil {
return nil, err
}
retVal := make([]entity.ContactInfo, 0)
for rows.Next() {
contact := entity.ContactInfo{}
err = rows.Scan(&contact.ID, &contact.Value, &contact.UserID, &contact.Type.ID, &contact.Type.Key, &contact.Type.Value)
if err != nil {
return nil, err
}
retVal = append(retVal, contact)
}
return retVal, nil
}
func (c *userRepo) GetUsersByProfile(profile string) ([]entity.User, error) {
query := c.getQuery()
if profile == "" {
query += "AND e.key <> 'US' "
return c.parseSet(c.conn.Query(query))
} else {
return c.parseSet(c.conn.Query(query+"AND e.key = ? AND a.active = 1 ", profile))
}
}
func (c *userRepo) parseSet(rows *sql.Rows, err error) ([]entity.User, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.User, 0)
var lastUser entity.User
for rows.Next() {
entity, err := c.parseEntity(rows)
if err != nil {
return nil, errors.Wrap(err)
}
if entity.UUID == lastUser.UUID {
lastUser.Profiles = append(lastUser.Profiles, entity.Profiles...)
} else {
if lastUser.UUID != "" {
result = append(result, lastUser)
}
lastUser = entity
}
}
result = append(result, lastUser)
return result, nil
}
func (c *userRepo) GetContactType() (retVal []entity.ContactType, err error) {
const (
query = `
SELECT
a.contact_type_id,
a.key,
a.name
FROM tab_contact_type a
WHERE a.visible = 1 `
)
rows, err := c.conn.Query(query)
if err != nil {
return nil, err
}
retVal = make([]entity.ContactType, 0)
for rows.Next() {
var contactType entity.ContactType
err = rows.Scan(&contactType.ID, &contactType.Key, &contactType.Value)
if err != nil {
return nil, err
}
retVal = append(retVal, contactType)
}
return retVal, nil
}
// parseEntity parses a result to an entity
func (c *userRepo) parseEntity(row scanner) (retVal entity.User, err error) {
var profile entity.Profile
var birthDate mysql.NullTime
var homeAddress entity.Address
var workAddress entity.Address
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,
&workAddress.ID, &workAddress.UUID, &workAddress.AddressType.ID, &workAddress.AddressType.Key, &workAddress.AddressType.Name, &workAddress.Name, &workAddress.Address, &workAddress.Latitude, &workAddress.Longitude)
if err != nil {
if err != sql.ErrNoRows {
return retVal, errors.Wrap(err)
}
}
if birthDate.Valid {
retVal.BirthDate = birthDate.Time
}
retVal.Profiles = append(retVal.Profiles, profile)
if homeAddress.ID > 0 {
retVal.Addresses = append(retVal.Addresses, homeAddress)
}
if workAddress.ID > 0 {
retVal.Addresses = append(retVal.Addresses, workAddress)
}
return retVal, errors.Wrap(err)
}
func (c *userRepo) FullLogin(loginType string, key string, pass string, profile string) (user entity.User, err error) {
return c.login(loginType, key, pass, profile)
}
//Login return a user based on email and password with the default `User` profile
func (c *userRepo) Login(email string, pass string) (user entity.User, err error) {
return c.FullLogin("email", email, pass, "US")
}
func (c *userRepo) getQuery() string {
const (
query = `SELECT
a.user_id,
a.user_uuid,
a.name,
IFNULL(a.member, '') member,
a.birth_date,
b.login_id,
b.login_uuid,
IFNULL(b.email, '') email,
IFNULL(b.phone_number, '') phone_number,
b.key login_key,
IFNULL(a.gender, 'U') gender,
(IFNULL(a.active, b'0') = b'1') active,
a.create_time,
a.update_time,
e.profile_id,
e.name profile_name,
e.key profile_key,
(IFNULL(c.active, b'0') = b'1') profile_active,
(IFNULL(c.blocked, b'0') = b'1') profile_blocked,
(IFNULL(c.suspended, b'0') = b'1') profile_suspended,
c.create_date profile_createat,
c.update_date profile_updateat,
IFNULL(f.organization_id, 0) organization_id,
IFNULL(f.organization_uuid, '') organization_uuid,
IFNULL(f.organization_type_id, 0) organization_type_id,
IFNULL(g.organization_type, '') organization_type,
IFNULL(g.organization_type_key, '') organization_type_key,
IFNULL(g.description, '') organization_type_desc,
IFNULL(f.organization_name, '') organization_name,
IFNULL(f.organization_description, '') organization_desc,
IFNULL(f.organization_reference_id, 0) organization_reference_id,
IFNULL(f.organization_parent_id, 0) organization_parent_id,
(IFNULL(f.main_organization, b'0') = b'1') main_organization,
IFNULL(h.address_id, 0) home_address_id,
IFNULL(h.address_uuid, '') home_address_uuid,
IFNULL(h.address_type_id, 0) home_address_type_id,
IFNULL(h.address_type_key, '') home_address_type_key,
IFNULL(h.address_type_name, '') home_address_type_name,
IFNULL(h.name, '') home_name,
IFNULL(h.address, '') home_address,
IFNULL(h.lat, 0) home_lat,
IFNULL(h.long, 0) home_long,
IFNULL(i.address_id, 0) work_address_id,
IFNULL(i.address_uuid, '') work_address_uuid,
IFNULL(i.address_type_id, 0) work_address_type_id,
IFNULL(i.address_type_key, '') work_address_type_key,
IFNULL(i.address_type_name, '') work_address_type_name,
IFNULL(i.name, '') work_name,
IFNULL(i.address, '') work_address,
IFNULL(i.lat, 0) work_lat,
IFNULL(i.long, 0) work_long
FROM
tab_user a
INNER JOIN
tab_login b ON a.user_id = b.user_id
INNER JOIN
tab_profile_login c ON c.login_id = b.login_id
INNER JOIN
tab_profile e ON e.profile_id = c.profile_id
LEFT JOIN
tab_organization f ON f.organization_id = IFNULL(c.organization_id, 0)
LEFT JOIN
tab_organization_type g ON IFNULL(g.organization_type_id, 0) = IFNULL(f.organization_type_id, 0)
LEFT JOIN
viw_address_home h ON a.user_id = h.user_id
LEFT JOIN
viw_address_work i ON a.user_id = i.user_id
WHERE
a.active = b.active
AND b.active = c.active
AND c.active = e.active `
)
return query
}
func (c *userRepo) login(loginType string, key string, pass string, profile string) (user entity.User, err error) {
if loginType == "" {
return user, errors.NewNullArgumentError("loginType")
}
if loginType != "phone_number" && loginType != "email" {
return user, errors.NewValidationError("loginType", "invalid")
}
query := fmt.Sprintf(c.getQuery()+`
AND a.active = 1
AND b.%s = ?
AND b.password = sha2(?, 512) `, loginType)
users, err := c.parseSet(c.conn.Query(query, key, pass))
if err != nil {
return user, errors.Wrap(err)
}
return users[0], nil
}
func (c *userRepo) Create(user entity.User) (retVal entity.User, err error) {
retVal = user
if retVal.Member != "" {
retVal, err = c.getUserByMember(retVal)
if err != nil {
return retVal, err
}
}
if retVal.ID == 0 || retVal.Member == "" {
userID, guid, err := c.createUser(user)
if err != nil {
return retVal, err
}
retVal.UUID = guid
retVal.ID = userID
}
retVal, err = c.getUserLogin(retVal)
if err != nil {
return retVal, err
}
if retVal.LoginID == 0 {
loginID, loginGUID, err := c.createLogin(retVal)
if err != nil {
return retVal, err
}
retVal.LoginUUID = loginGUID
retVal.LoginID = loginID
}
for _, p := range user.Profiles {
companyProfileID, err := c.getCompanyProfile(p.Key)
if err != nil {
return retVal, err
}
if len(user.Organizations) > 0 {
for _, o := range user.Organizations {
err = c.addProfileToUser(retVal.LoginID, companyProfileID, o)
if err != nil {
return retVal, err
}
}
} else {
err = c.addProfileToUser(retVal.LoginID, companyProfileID, entity.Organization{})
if err != nil {
return retVal, err
}
}
}
if retVal.Email != "" {
contact := entity.ContactInfo{
Type: entity.ContactType{Key: "email"},
Value: retVal.Email,
UserID: retVal.ID,
}
contact, err = c.addContactInfo(contact)
if err != nil {
return retVal, err
}
}
if retVal.PhoneNumber != "" {
contact := entity.ContactInfo{
Type: entity.ContactType{Key: "phone"},
Value: retVal.PhoneNumber,
UserID: retVal.ID,
}
contact, err = c.addContactInfo(contact)
if err != nil {
return retVal, err
}
}
return c.GetByUUID(retVal.UUID, "")
}
func (c *userRepo) SaveContact(contact entity.ContactInfo) (entity.ContactInfo, error) {
return c.addContactInfo(contact)
}
func (c *userRepo) RemoveContact(contact entity.ContactInfo) (entity.ContactInfo, error) {
const (
query = `INSERT INTO tab_contact(contact_type_id, user_id, contact)
SELECT a.contact_type_id, ? user_id, ? contact
FROM
tab_contact_type a
LEFT JOIN tab_contact b
ON a.contact_type_id = b.contact_type_id
AND b.user_id = ?
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 != nil {
return contact, err
}
retVal := contact
retVal.ID, err = result.LastInsertId()
if err != nil {
return contact, err
}
return retVal, nil
}
func (c *userRepo) addContactInfo(contact entity.ContactInfo) (entity.ContactInfo, error) {
const (
query = `INSERT INTO tab_contact(contact_type_id, user_id, contact)
SELECT a.contact_type_id, ? user_id, ? contact
FROM
tab_contact_type a
LEFT JOIN tab_contact b
ON a.contact_type_id = b.contact_type_id
AND b.user_id = ?
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 != nil {
return contact, err
}
retVal := contact
retVal.ID, err = result.LastInsertId()
if err != nil {
return contact, err
}
return retVal, nil
}
func (c *userRepo) getUserByLoginAndProfile(loginID int64) (user entity.User, err error) {
finalQuery := c.getQuery() + " AND a.active = 1 AND b.login_Id = ? "
users, err := c.parseSet(c.conn.Query(finalQuery, loginID))
if err != nil {
return user, errors.Wrap(err)
}
return users[0], nil
}
func (c *userRepo) addProfileToUser(loginID int64, profileID int64, organization entity.Organization) error {
const query = "INSERT INTO tab_profile_login(profile_id, login_id, active, blocked, suspended, organization_id) VALUES(?, ?, 1, 0, 0, ?) ON DUPLICATE KEY UPDATE profile_id = ?, login_id = ?, organization_id = ?;"
const checkQuery = "SELECT COUNT(1) has_profile FROM tab_profile_login a WHERE a.login_id = ? AND a.profile_id = ? AND IFNULL(a.organization_id, 0) = ?;"
var total int64
row := c.conn.QueryRow(checkQuery, loginID, profileID, organization.ID)
err := row.Scan(&total)
if err != nil && err != sql.ErrNoRows {
return err
}
if total < 1 {
_, err := c.conn.Exec(query, profileID, loginID, organization.ID, profileID, loginID, toNullInt64(organization.ID))
if err != nil {
return err
}
}
return nil
}
func (c *userRepo) getUserByMember(u entity.User) (user entity.User, err error) {
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))
if err != nil {
return user, errors.Wrap(err)
}
if users[0].ID != 0 {
user = users[0]
}
return user, nil
}
func (c *userRepo) getCompanyProfile(profile string) (int64, error) {
const (
query = "SELECT a.profile_id FROM tab_profile a WHERE a.key = ?;"
)
var companyProfileID int64
row := c.conn.QueryRow(query, profile)
err := row.Scan(&companyProfileID)
if err != nil {
return 0, err
}
return companyProfileID, nil
}
func (c *userRepo) getUserLogin(u entity.User) (user entity.User, err error) {
const (
query = "SELECT login_id, login_uuid, user_id, IFNULL(phone_number, '') phone_number, IFNULL(email, '') email, `key`, `password` FROM tab_login WHERE user_id = ?"
)
row := c.conn.QueryRow(query, user.Member)
err = row.Scan(&user.LoginID, &user.LoginUUID, &user.ID, &user.PhoneNumber, &user.Email, &user.LoginKey, &user.Pass)
if err != nil {
if err == sql.ErrNoRows {
return u, nil
} else {
return user, err
}
}
return user, nil
}
func (c *userRepo) createLogin(user entity.User) (int64, string, error) {
const (
query = "INSERT INTO tab_login (login_uuid, user_id, phone_number, email, `key`, `password`) VALUES(?, ?, ?, ?, ?, sha2(?, 512)) ON DUPLICATE KEY UPDATE login_uuid = ?, user_id = ?, phone_number = ?, email = ?, `key` = ?, `password` = sha2(?, 512);"
)
guid, _ := uuid.NewV4()
key, _ := uuid.NewV4()
result, err := c.conn.Exec(query, guid.String(), user.ID, toNullString(user.PhoneNumber), toNullString(user.Email), key.String(), user.Pass, guid.String(), user.ID, user.PhoneNumber, user.Email, key.String(), user.Pass)
if err != nil {
return 0, "", err
}
loginID, err := result.LastInsertId()
if err != nil {
return 0, "", err
}
return loginID, guid.String(), nil
}
func (c *userRepo) createUser(user entity.User) (int64, string, error) {
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 = ?;"
)
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))
if err != nil {
return 0, "", err
}
userID, err := result.LastInsertId()
if err != nil {
return 0, "", err
}
return userID, guid.String(), nil
}
func (c *userRepo) RemoveAddress(addressUUID string) error {
const (
query = "UPDATE tab_address SET active = 0 WHERE address_uuid = ?"
)
_, err := c.conn.Exec(query, addressUUID)
return err
}
func (c *userRepo) SaveAddress(address entity.Address) (entity.Address, error) {
const (
query = "INSERT INTO tab_address(address_uuid,address_type_id,address_origin_id,user_id,internal_id,`name`,address,lat,`long`,created_user_id) VALUES (?,?,?,?,?,?,?,?,?,?);"
)
address, err := c.getAddressSecondaryData(address)
if err != nil {
return address, err
}
uuid, _ := uuid.NewV4()
address.UUID = uuid.String()
result, err := c.conn.Exec(query, address.UUID, address.AddressType.ID, address.Origin.ID, address.User.ID, address.InternalID, address.Name, address.Address, address.Latitude, address.Longitude, address.CreatedUser.ID)
if err != nil {
return address, err
}
addressID, err := result.LastInsertId()
if err != nil {
return address, err
}
return c.getAddressByID(addressID)
}
func (c *userRepo) getAddressByUserID(userID int64) ([]entity.Address, error) {
const (
query = `SELECT
a.address_id,
a.address_uuid,
a.address_type_id,
d.key address_type_key,
d.name address_type_name,
a.address_origin_id,
e.key address_origin_key,
e.name address_origin_name,
b.user_id,
b.user_uuid,
b.name user_name,
a.internal_id,
a.name,
a.address,
a.lat,
a.long,
c.user_id created_user_id,
c.user_uuid created_user_uuid,
c.name created_user_name
FROM
tab_address a
INNER JOIN tab_user b
ON a.user_id = b.user_id
INNER JOIN tab_user c
ON a.created_user_id = c.user_id
INNER JOIN tab_address_type d
ON a.address_type_id = d.address_type_id
INNER JOIN tab_address_origin e
ON a.address_origin_id = e.address_origin_id
WHERE
a.user_id = ? and a.active = 1;`
)
var addresses []entity.Address
rows, err := c.conn.Query(query, userID)
if err != nil {
return nil, err
}
for rows.Next() {
var address entity.Address
err := rows.Scan(&address.ID, &address.UUID, &address.AddressType.ID, &address.AddressType.Key, &address.AddressType.Name,
&address.Origin.ID, &address.Origin.Key, &address.Origin.Name, &address.User.ID, &address.User.UUID, &address.User.Name,
&address.InternalID, &address.Name, &address.Address, &address.Latitude, &address.Longitude, &address.CreatedUser.ID,
&address.CreatedUser.UUID, &address.CreatedUser.Name)
if err != nil {
return nil, err
}
addresses = append(addresses, address)
}
return addresses, nil
}
func (c *userRepo) getAddressByID(addressID int64) (entity.Address, error) {
const (
query = `SELECT
a.address_id,
a.address_uuid,
a.address_type_id,
d.key address_type_key,
d.name address_type_name,
a.address_origin_id,
e.key address_origin_key,
e.name address_origin_name,
b.user_id,
b.user_uuid,
b.name user_name,
a.internal_id,
a.name,
a.address,
a.lat,
a.long,
c.user_id created_user_id,
c.user_uuid created_user_uuid,
c.name created_user_name
FROM
tab_address a
INNER JOIN tab_user b
ON a.user_id = b.user_id
INNER JOIN tab_user c
ON a.created_user_id = c.user_id
INNER JOIN tab_address_type d
ON a.address_type_id = d.address_type_id
INNER JOIN tab_address_origin e
ON a.address_origin_id = e.address_origin_id
WHERE
a.address_id = ?;`
)
var address entity.Address
row := c.conn.QueryRow(query, addressID)
err := row.Scan(&address.ID, &address.UUID, &address.AddressType.ID, &address.AddressType.Key, &address.AddressType.Name,
&address.Origin.ID, &address.Origin.Key, &address.Origin.Name, &address.User.ID, &address.User.UUID, &address.User.Name,
&address.InternalID, &address.Name, &address.Address, &address.Latitude, &address.Longitude, &address.CreatedUser.ID,
&address.CreatedUser.UUID, &address.CreatedUser.Name)
if err != nil {
return entity.Address{}, err
}
return address, nil
}
func (c *userRepo) GetAddressByUUID(addressUUID string) (entity.Address, error) {
const (
query = `SELECT
a.address_id,
a.address_uuid,
a.address_type_id,
d.key address_type_key,
d.name address_type_name,
a.address_origin_id,
e.key address_origin_key,
e.name address_origin_name,
b.user_id,
b.user_uuid,
b.name user_name,
a.internal_id,
a.name,
a.address,
a.lat,
a.long,
c.user_id created_user_id,
c.user_uuid created_user_uuid,
c.name created_user_name
FROM
tab_address a
INNER JOIN tab_user b
ON a.user_id = b.user_id
INNER JOIN tab_user c
ON a.created_user_id = c.user_id
INNER JOIN tab_address_type d
ON a.address_type_id = d.address_type_id
INNER JOIN tab_address_origin e
ON a.address_origin_id = e.address_origin_id
WHERE
a.address_uuid = ?;`
)
var address entity.Address
row := c.conn.QueryRow(query, addressUUID)
err := row.Scan(&address.ID, &address.UUID, &address.AddressType.ID, &address.AddressType.Key, &address.AddressType.Name,
&address.Origin.ID, &address.Origin.Key, &address.Origin.Name, &address.User.ID, &address.User.UUID, &address.User.Name,
&address.InternalID, &address.Name, &address.Address, &address.Latitude, &address.Longitude, &address.CreatedUser.ID,
&address.CreatedUser.UUID, &address.CreatedUser.Name)
if err != nil {
return entity.Address{}, err
}
return address, nil
}
func (c *userRepo) getAddressSecondaryData(address entity.Address) (entity.Address, error) {
const (
query = `SELECT
a.user_id,
a.user_uuid,
a.name user_name,
b.user_id created_user_id,
b.user_uuid created_user_uuid,
b.name created_user_name,
c.address_type_id,
c.key address_type_key,
c.name address_type_name,
d.address_origin_id,
d.key address_origin_key,
d.name address_origin_name
FROM
tab_user a,
tab_user b,
tab_address_type c,
tab_address_origin d
WHERE
a.user_uuid = ?
AND b.user_uuid = ?
AND c.key = ?
AND d.key = ?;`
)
row := c.conn.QueryRow(query, address.User.UUID, address.CreatedUser.UUID, address.AddressType.Key, address.Origin.Key)
err := row.Scan(&address.User.ID, &address.User.UUID, &address.User.Name, &address.CreatedUser.ID, &address.CreatedUser.UUID, &address.CreatedUser.Name, &address.AddressType.ID, &address.AddressType.Key, &address.AddressType.Name, &address.Origin.ID, &address.Origin.Key, &address.Origin.Name)
if err != nil {
return address, err
}
return address, nil
}
// GetAll returns a list of all active cards
func (c *userRepo) GetAll() (list []entity.User, err error) {
return c.parseSet(c.conn.Query(c.getQuery() + " WHERE a.active = 1 "))
}
// GetByID returns a single card data by its ID
func (c *userRepo) GetByID(userID int64) (retVal entity.User, err error) {
user, err := c.parseSet(c.conn.Query(c.getQuery()+" AND a.user_id = ? ", userID))
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 retVal, nil
}
}
func toNullString(s string) sql.NullString {
return sql.NullString{String: s, Valid: s != ""}
}
func toNullInt64(i int64) sql.NullInt64 {
return sql.NullInt64{Int64: i, Valid: i > 0}
}
func toNullTime(date time.Time) mysql.NullTime {
return mysql.NullTime{Time: date, Valid: !date.IsZero()}
}

15
data/datamysql/utils.go Normal file
View File

@@ -0,0 +1,15 @@
package datamysql
import (
"database/sql"
)
type scanner interface {
Scan(dest ...interface{}) error
}
type executor interface {
Exec(query string, args ...interface{}) (sql.Result, error)
QueryRow(query string, args ...interface{}) *sql.Row
Query(query string, args ...interface{}) (*sql.Rows, error)
}

210
data/datamysql/visit.go Normal file
View File

@@ -0,0 +1,210 @@
package datamysql
import (
"database/sql"
"fmt"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
"github.com/go-sql-driver/mysql"
uuid "github.com/satori/go.uuid"
)
// visitRepo maps methods to database
type visitRepo struct {
conn executor
}
func newVisitRepo(conn executor) *visitRepo {
return &visitRepo{
conn: conn,
}
}
func (c *visitRepo) getProfileQuery(user entity.User) (query string, where string, err error) {
if len(user.Profiles) > 0 {
for _, p := range user.Profiles {
switch p.Key {
case "AD", "BCBSIAD", "BDCAD", "PLANAD":
return
case "SP", "SPT":
switch p.Organization.Type.Key {
case "techsupport", "bcbsi", "bcbsa", "plan":
return
case "provider":
query = ` INNER JOIN viw_visit_provider f
ON f.visit_id = a.visit_id `
where = fmt.Sprintf(` AND (f.organization_uuid = '%s' OR f.parent_organization_uuid = '%s') `, p.Organization.UUID, p.Organization.UUID)
return
}
}
}
if query == "" && where == "" {
return "", "", fmt.Errorf("Invalid Query")
} else {
return
}
} else {
return "", "", fmt.Errorf("User has no profile to search")
}
}
func (c *visitRepo) getQuery() string {
return `SELECT
a.visit_id,
a.visit_uuid,
a.visit_status_id,
b.visit_status_key,
b.visit_status,
a.user_id,
c.user_uuid,
c.name user_name,
c.member user_member,
c.birth_date user_birth_date,
c.gender user_gender,
a.visit_datetime,
a.pickup_datetime,
IFNULL(a.notes, '') notes,
a.created_user_id,
d.user_uuid created_user_uuid,
d.name created_user_name,
a.created_date,
a.updated_date,
IFNULL(a.visit_duration, 0) visit_duration,
a.visit_external_id,
e.trip_type_id,
e.trip_type_key,
e.trip_type,
IFNULL(a.pickup_id, '') visit_pickup_id,
IFNULL(a.pickup_address_id, 0) pickup_address_id,
IFNULL(a.address_id, 0) address_id,
IFNULL(a.provider_id, 0) provider_id,
IFNULL(f.provider_uuid, '') provider_uuid,
IFNULL(f.provider_internal_id, '') provider_internal_id,
IFNULL(f.provider_muk_id, '') provider_muk_id,
IFNULL(f.provider_name, '') provider_name
FROM
tab_visit a
INNER JOIN tab_visit_status b
ON a.visit_status_id = b.visit_status_id
INNER JOIN tab_user c
ON c.user_id = a.user_id
INNER JOIN tab_user d
ON d.user_id = a.created_user_id
INNER JOIN tab_trip_type e
ON e.trip_type_id = a.trip_type_id
INNER JOIN tab_provider f
ON f.provider_id = a.provider_id `
}
func (c *visitRepo) GetAll(user entity.User) ([]entity.Visit, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return nil, err
}
query = c.getQuery() + query + " WHERE 1 = 1 and c.active = 1 " + where
return c.parseSet(c.conn.Query(query))
}
func (c *visitRepo) GetByUUID(visitUUID string, user entity.User) (entity.Visit, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Visit{}, err
}
query = c.getQuery() + query + " WHERE a.visit_uuid = ? " + where
return c.parseEntity(c.conn.QueryRow(query, visitUUID))
}
func (c *visitRepo) GetByID(visitID int64, user entity.User) (entity.Visit, error) {
query, where, err := c.getProfileQuery(user)
if err != nil {
return entity.Visit{}, err
}
query = c.getQuery() + query + " WHERE a.visit_id = ? " + where
return c.parseEntity(c.conn.QueryRow(query, visitID))
}
// parseSet parses a result set result to an entity array
func (c *visitRepo) parseSet(rows *sql.Rows, err error) ([]entity.Visit, error) {
if err != nil {
return nil, errors.Wrap(err)
}
result := make([]entity.Visit, 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 *visitRepo) parseEntity(row scanner) (retVal entity.Visit, err error) {
var birthDate mysql.NullTime
var gender sql.NullString
err = row.Scan(
&retVal.ID, &retVal.UUID, &retVal.Status.ID, &retVal.Status.Key, &retVal.Status.Value, &retVal.User.ID, &retVal.User.UUID, &retVal.User.Name, &retVal.User.Member, &birthDate, &gender, &retVal.VisitDatetime, &retVal.PickupDatetime, &retVal.Notes, &retVal.CreatedUser.ID, &retVal.CreatedUser.UUID, &retVal.CreatedUser.Name, &retVal.Created, &retVal.Updated, &retVal.VisitDuration, &retVal.ExternalID, &retVal.TripType.ID, &retVal.TripType.Key, &retVal.TripType.Value, &retVal.Pickup.ID, &retVal.PickupAddressID, &retVal.DestinationAddressID, &retVal.Provider.ProviderID, &retVal.Provider.ProviderUUID, &retVal.Provider.InternalID, &retVal.Provider.MukID, &retVal.Provider.Name)
if birthDate.Valid {
retVal.User.BirthDate = birthDate.Time
}
if gender.Valid {
retVal.User.Gender = gender.String
} else {
retVal.User.Gender = "U"
}
return retVal, errors.Wrap(err)
}
func (c *visitRepo) Create(visit entity.Visit) (entity.Visit, error) {
const (
statusQuery = `SELECT a.visit_status_id, a.visit_status_key, a.visit_status, b.user_id, b.name user_name, c.user_id create_user_id, c.name create_user_name, d.trip_type_id, d.trip_type_key, d.trip_type FROM tab_visit_status a, tab_user b, tab_user c, tab_trip_type d WHERE a.visit_status_key = ? AND b.user_uuid = ? AND c.user_uuid = ? AND d.trip_type_key = ?;`
query = `INSERT INTO tab_visit(visit_uuid, visit_status_id, user_id, visit_datetime, pickup_datetime, notes, created_user_id, visit_duration, visit_external_id, return_date, trip_type_id, pickup_id, pickup_address_id, address_id, provider_id)
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`
)
retVal := visit
returnDate := mysql.NullTime{
Valid: (retVal.ReturnDate != nil),
}
if retVal.ReturnDate != nil {
returnDate.Time = *retVal.ReturnDate
}
UUID, _ := uuid.NewV4()
retVal.UUID = UUID.String()
if retVal.Status.Key == "" {
retVal.Status.Key = "accepted"
}
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 {
fmt.Println("Error to get base data: ", err.Error())
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)
if err != nil {
return retVal, err
}
retVal.ID, err = results.LastInsertId()
if err != nil {
return retVal, err
}
fmt.Println("Visit ID: ", retVal.ID)
return retVal, nil
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
# Definitions
## Steps
- `build`: compilation and project preparation step
- `run`: execution step
## Environments
- `loc`: local
- `dev`: development
- `stg`: staging
- `prd`: production

View File

@@ -0,0 +1,21 @@
# Environments
## Definitions
- Local (`loc`)
Your local machine.
- Development (`dev`)
Useful for us to test the implementation without messing with
the partners experience.
- Staging (`stg`)
Used to simulate production and as homologation version.
Works as the last step before production.
- Production (`prd`)
Production server.

64
docs/wiki/03 - Folders.md Normal file
View File

@@ -0,0 +1,64 @@
# Folders
## Reason
The goals for a common project's folder structure is to mantain the organization
and to promote a common language between the programmers, decreasing the new
members' learning curve.
## Definitions
### Structure
- `domain`:
- `service`:
contains the business logic and persistence, i.e. validating values based on business
rules
- `contract`:
contains the interfaces for the whole app; useful for mocking dependencies on
the tests and also decoupling the packages from each other, making the code independent
from external technologies, e.g. databases
- `entity`:
represents the values our domain understands
- `infra`:
contains utilities that will be used across the whole app
- `data`:
contains the connection with the database or any other way to do the persistence
- `data*`:
an "implementation"
- `application`:
represents our application as a whole
- `applicationservice`:
contains the application logic, i.e. parses and validates the data received, calls
many domain's services, parses the output data and sends it
- `entitymapping`:
contains the functions that parses the application's view model to the domain's
entities, and vice-versa
- `viewmodel`:
the data that will be sent and received from the app; it differs from the entity
because it does not represent the values of our app, but rather the values the
front-end server will understand
- `server`:
contains the definitions for the web server
- `router`:
defines the routes and its handlers; contains no logic, only calls the application
package
- `serverconfig`:
defines the middlewares and the server's configurations
- `static`:
not required; mostly used for static files, such as large texts, email templates,
static values, etc, or temporary files (commonly in `static/temp`)

View File

@@ -0,0 +1,31 @@
# Dockerfile
## Definitions
There are two `Dockerfile`s, one for each step of execution set in
the [definitions document][definitions-doc].
## Containers
- Build
Defined in `Dockerfile.build`
Has installed every program that is needed to build the code.
Gets the source, install the dependencies and makes the final binary
of our app.
The reason for us to have a container just for the building process is
that it demands lots of programs and dependencies to set up the Go
environment and build everything, which aren't needed in the server for
our app to run. Without it, the container for the running process would
be huge, full of useless binaries and softwares.
- Run
Defined in `Dockerfile.run`
This is the container that will run in the servers. Contains nothing,
but our app and what it need to make it run.
[definitions-doc]: https://bitbucket.org/nemt/nemt-portal-api/blob/master/docs/wiki/01%20-%20Definitions.md

View File

@@ -0,0 +1,67 @@
# Makefile
## Reason
Great to simplify and standardize commons and repetitive tasks.
## Definitions
Following the patterns of the [definitions document][definitions-doc], every task related to
the compilation os preparation of the server for execution will `build` as part of the name,
while tasks related to the execution itself will be call `run`.
## Common instructions
### Build
- `create-build-container`: creates the container for building, using `Dockerfile.build`
- `build`: build the server inside the container and gets the binary
- `build-loc`: calls `build` using local (`loc`) environment
- `build-dev`: calls `build` using development (`dev`) environment
- `build-stg`: calls `build` using staging (`stg`) environment
- `build-prd`: calls `build` using production (`prd`) environment
### Run
- `create-run-container`: creates the container for execution, using `Dockerfile.run`
- `run`: executes the app inside the container
- `run-loc`: calls `run` using local (`loc`) environment
- `run-dev`: calls `run` using development (`dev`) environment
- `run-stg`: calls `run` using staging (`stg`) environment
- `run-prd`: calls `run` using production (`prd`) environment
- `run-host`: executes the app without a container, directly on the local host
### Environment
- `set-loc`: defines the environment as "local" (`loc`)
- `set-dev`: defines the environment as "development" (`dev`)
- `set-stg`: defines the environment as "staging" (`stg`)
- `set-prd`: defines the environment as "production" (`prd`)
### Database
- `migrate`: executes the full migration of the database
### Tests
- `test`: executes the whole battery of tests
### Others
- `clean`: remove binaries and compiled files
[definitions-doc]: https://bitbucket.org/nemt/nemt-portal-api/blob/master/docs/wiki/01%20-%20Definitions.md

15
domain/constants.go Normal file
View File

@@ -0,0 +1,15 @@
package domain
type errorString string
func (err errorString) Error() string {
return string(err)
}
// ErrCacheMiss indicates a cache miss when fetching an item from CacheManager.
const ErrCacheMiss = errorString("cache miss: key not found")
// Used to log errors with communication and operation of cache implementation
const LogProblemGettingFromCache = "Getting from cache is not working correctly: %v"
const LogProblemPuttingToCache = "Putting to cache is not working correctly: %v"
const LogProblemExpiringCache = "Expiring cache key is not working correctly: %v"

19
domain/contract/cache.go Normal file
View File

@@ -0,0 +1,19 @@
package contract
import "time"
// CacheManager defines the main caching interface
// - Get methods can return domain.ErrCacheMiss
type CacheManager interface {
GetItem(key string) ([]byte, error)
SetItem(key string, data []byte) error
GetString(key string) (string, error)
SetString(key string, data string) error
GetStruct(key string, data interface{}) error
SetStruct(key string, data interface{}) error
GetExpiration(key string) (time.Duration, error)
SetExpiration(key string, expiration time.Duration) error
}

16
domain/contract/data.go Normal file
View File

@@ -0,0 +1,16 @@
package contract
// DataManager holds the methods that manipulates the main data.
type DataManager interface {
repoManager
Begin() (TransactionManager, error)
Close() error
}
// TransactionManager holds the methods that manipulates the main
// data, from within a transaction.
type TransactionManager interface {
repoManager
Rollback() error
Commit() error
}

104
domain/contract/repo.go Normal file
View File

@@ -0,0 +1,104 @@
package contract
import (
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
type repoManager interface {
Users() UserRepo
Rides() RideRepo
Visits() VisitRepo
Provider() ProviderRepo
Notification() NotificationRepo
Profile() ProfileRepo
Organization() OrganizationRepo
}
// UserRepo defines the data set for users
type UserRepo interface {
GetAll() (list []entity.User, err error)
GetByID(userID int64) (retVal entity.User, err error)
GetByUUID(uuid string, profile string) (entity.User, error)
Login(email string, pass string) (entity.User, error)
FullLogin(loginType string, key string, pass string, profile string) (entity.User, error)
Create(user entity.User) (entity.User, error)
GetUsersByProfile(profile string) ([]entity.User, error)
SaveAddress(address entity.Address) (entity.Address, error)
GetAddressByUUID(addressUUID string) (entity.Address, error)
GetContactType() (retVal []entity.ContactType, err error)
RemoveAddress(addressUUID string) error
}
// RideRepo defines the data set for Rides
type RideRepo interface {
Save(ride entity.Ride) (entity.Ride, error)
GetAll(user entity.User) ([]entity.Ride, error)
GetByID(id int64, user entity.User) (entity.Ride, error)
GetByUUID(uuid string, user entity.User) (entity.Ride, error)
GetByInternalID(internalID string) (entity.Ride, error)
GetByUserID(userID int64, user entity.User) ([]entity.Ride, error)
GetByUserUUID(userUUID string, user entity.User) ([]entity.Ride, error)
GetByUUIDAndUserUUID(UUID string, userUUID string) (entity.Ride, error)
UpdateStatus(rideUUID string, status string) error
Update(hook entity.WebhookResponse, user entity.User) (entity.Ride, error)
GetLastRideByPhoneNumber(phoneNumber string) (entity.Ride, error)
GetLastRideByDriversNumber(phoneNumber string) (entity.Ride, error)
GetByInternalPassengerID(internalPassengerID string) (entity.Ride, error)
GetByVisitUUID(visitUUID string, user entity.User) ([]entity.Ride, error)
GetByVisitUUIDAndTripType(visitUUID string, tripTypeKey string, user entity.User) (entity.Ride, error)
}
// ProviderRepo defines the data set for Provider
type ProviderRepo interface {
Save(providers []entity.ProviderResponse, 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)
GetByMukID(mukID string, user entity.User) (entity.Provider, error)
}
// NotificationRepo defines the data set for Notification
type NotificationRepo interface {
Create(notification entity.Notification) (entity.Notification, error)
GetByUserUUIDAndReadStatus(userUUID string, status string, isRead bool) ([]entity.Notification, error)
GetByUserUUID(userUUID string, status string) ([]entity.Notification, error)
ReadStatus(notificationUUID string, readed bool) error
GetLastNotificationFromPhoneNumber(notificationType string, phoneNumber string, status string) (entity.Notification, error)
}
// ProviderRepo defines the data set for Rides
type OrganizationRepo interface {
GetAllTypes() ([]entity.OrganizationType, error)
GetByType(organizationTypeKey string) ([]entity.Organization, error)
GetByUUID(organizationUUID string) (entity.Organization, error)
GetContactsByOrganizationUUID(organizationUUID string) ([]entity.OrganizationContact, error)
GetContactsByOrganizationID(organizationID int64) ([]entity.OrganizationContact, error)
GetContactsByUUID(contactUUID string) (entity.OrganizationContact, error)
GetAddressByOrganizationUUID(organizationUUID string) ([]entity.OrganizationAddress, error)
GetAddressByOrganizationID(organizationID int64) ([]entity.OrganizationAddress, error)
GetAddressByUUID(contactUUID string) (entity.OrganizationAddress, error)
GetByID(organizationID int64) (entity.Organization, error)
GetChildsByID(organizationID int64) ([]entity.Organization, error)
GetByName(name string, searchType string) ([]entity.Organization, error)
SetParentOrganization(organizationID int64, parentOrganizationID int64) error
InactivateOrganizationAddress(address entity.OrganizationAddress) error
SetOrganizationAddress(address entity.OrganizationAddress) (entity.OrganizationAddress, error)
InactivateOrganizationContact(contact entity.OrganizationContact) error
SetOrganizationContact(contact entity.OrganizationContact) (entity.OrganizationContact, error)
AddOrganization(organization entity.Organization) (entity.Organization, error)
GetTypeByKey(key string) (entity.OrganizationType, error)
}
// VisitRepo defines the data set for Rides
type VisitRepo interface {
Create(visit entity.Visit) (entity.Visit, error)
GetAll(user entity.User) ([]entity.Visit, error)
GetByUUID(visitUUID string, user entity.User) (entity.Visit, error)
GetByID(visitID int64, user entity.User) (entity.Visit, error)
}
type ProfileRepo interface {
GetAll() ([]entity.Profile, error)
GetByKey(key string) (entity.Profile, error)
GetVisibles(visible bool) ([]entity.Profile, error)
GetByOrganizationType(organizationTypeID int64) ([]entity.Profile, error)
}

12
domain/contract/tnc.go Normal file
View File

@@ -0,0 +1,12 @@
package contract
type tncManager interface {
TNC() TNCManager
}
//TNCManager defines the integration with any TNC
type TNCManager interface {
GetETA(lag float64, log float64, params map[string]interface{}) (interface{}, error)
GetDrivers(lag float64, log float64) (interface{}, error)
GetTypes(lag float64, log float64, params map[string]interface{}) (interface{}, error)
}

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

@@ -0,0 +1,21 @@
package entity
type Address struct {
ID int64
UUID string
InternalID string
Name string
Address string
AddressType Params
Latitude float64
Longitude float64
Origin Params
User User
CreatedUser User
}
type Params struct {
ID int64
Key string
Name string
}

View File

@@ -0,0 +1,252 @@
package entity
type Interchange struct {
ISA ISA
Division Division
}
type ISA struct {
ISA01 string
ISA02 string
ISA03 string
ISA04 string
ISA05 string
ISA06 string
ISA07 string
ISA08 string
ISA09 string
ISA10 string
ISA11 string
ISA12 string
ISA13 string
ISA14 string
ISA15 string
ISA16 string
}
type Division struct {
GS GS
HealthCareEligibilityBenefitResponse HealthCareEligibilityBenefitResponse
}
type GS struct {
GS01 string
GS02 string
GS03 string
GS04 string
GS05 string
GS06 string
GS07 string
GS08 string
}
type HealthCareEligibilityBenefitResponse struct {
ST0010 ST0010
BHT0020 BHT0020
LoopHL0030 LoopHL0030
}
type ST0010 struct {
ST01 string
ST02 string
ST03 string
}
type BHT0020 struct {
BHT01 string
BHT02 string
BHT03 string
BHT04 string
BHT05 string
}
type LoopHL0030 struct {
HL0030 HL0030
LoopNM10060 LoopNM10060
LoopHL0460 LoopHL0460
}
type HL0030 struct {
HL01 string
HL02 string
HL03 string
HL04 string
}
type LoopNM10060 struct {
NM10060 NM10060
}
type NM10060 struct {
NM101 string
NM102 string
NM103 string
NM104 string
NM105 string
NM106 string
NM107 string
NM108 string
NM109 string
}
type LoopHL0460 struct {
HL0460 HL0460
LoopNM10490 LoopNM10490
LoopHL0890 LoopHL0890
}
type HL0460 struct {
HL01 string
HL02 string
HL03 string
HL04 string
}
type LoopNM10490 struct {
NM10490 NM10490
}
type NM10490 struct {
NM101 string
NM102 string
NM103 string
NM104 string
NM105 string
NM106 string
NM107 string
NM108 string
NM109 string
}
type LoopHL0890 struct {
HL0890 HL0890
TRN0900 TRN0900
LoopNM10920 LoopNM10920
}
type HL0890 struct {
HL01 string
HL02 string
HL03 string
HL04 string
}
type TRN0900 struct {
TRN01 string
TRN02 string
TRN03 string
}
type LoopNM10920 struct {
NM10920 NM10920
REF0930 REF0930
N30950 N30950
N40960 N40960
DMG1000 DMG1000
DTP1030 DTP1030
LoopEB1050 []LoopEB1050
}
type NM10920 struct {
NM101 string
NM102 string
NM103 string
NM104 string
NM105 string
NM106 string
NM107 string
NM108 string
NM109 string
}
type REF0930 struct {
REF01 string
REF02 string
REF03 string
}
type N30950 struct {
N301 string
}
type N40960 struct {
N401 string
N402 string
N403 string
}
type DMG1000 struct {
DMG01 string
DMG02 string
DMG03 string
}
type DTP1030 struct {
DTP01 string
DTP02 string
DTP03 string
}
type LoopEB1050 struct {
EB1050 EB1050
REF1070 REF1070
MSG1180 MSG1180
LoopIII1190 LoopIII1190
LS1260 LS1260
LoopNM11270 LoopNM11270
}
type EB1050 struct {
EB01 string
EB02 string
EB03 string
EB04 string
EB05 string
EB06 string
EB07 string
EB08 string
EB09 string
EB10 string
EB11 string
EB12 string
}
type REF1070 struct {
REF01 string
REF02 string
REF03 string
}
type MSG1180 struct {
MSG01 string
}
type LS1260 struct {
LS01 string
}
type LoopIII1190 struct {
III1190 III1190
}
type III1190 struct {
III01 string
III02 string
}
type LoopNM11270 struct {
NM11270 NM11270
PER1310 PER1310
}
type NM11270 struct {
NM101 string
NM102 string
NM103 string
}
type PER1310 struct {
PER01 string
PER02 string
PER03 string
}

View File

@@ -0,0 +1,20 @@
package entity
import "time"
type Notification struct {
ID int64 `json:"-"`
UUID string `json:"uuid"`
From string `json:"to"`
To string `json:"to"`
Type string `json:"type"`
TypeID int64 `json:"type_id"`
Subject string `json:"subject"`
Message string `json:"message"`
MessageType string `json:"message_type"`
Ride Ride `json:"ride"`
User User `json:"user"`
CreatedUser User `json:"created_user"`
Created time.Time `json:"create_at"`
Read bool `json:"read"`
}

View File

@@ -0,0 +1,68 @@
package entity
import (
"time"
)
type OrganizationType struct {
ID int64 `json:"-"`
Name string `json:"name"`
Key string `json:"key"`
Description string `json:"desc"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
}
type Organization struct {
ID int64 `json:"-"`
UUID string `json:"id"`
Type OrganizationType `json:"type"`
Name string `json:"name"`
Description string `json:"desc"`
ReferenceID int64 `json:"-"`
ParentID int64 `json:"-"`
Main bool `json:"main"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Active bool `json:"active"`
Blocked bool `json:"blocked"`
Suspended bool `json:"suspended"`
Author User `json:"author"`
LastEditor User `json:"last_editor"`
Contacts []OrganizationContact `json:"contacts"`
Addresses []OrganizationAddress `json:"addresses"`
ChildOrgs []Organization `json:"childs"`
Parent *Organization `json:"parent"`
}
type OrganizationContact struct {
ID int64 `json:"-"`
UUID string `json:"id"`
Organization *Organization `json:"organization"`
Type ContactType `json:"type"`
Contact string `json:"contact"`
Name string `json:"name"`
Description string `json:"desc"`
Created time.Time `json:"created"`
CreatedUser User `json:"author"`
Updated time.Time `json:"updated"`
UpdatedUser User `json:"last_editor"`
Active bool `json:"active"`
}
type OrganizationAddress struct {
ID int64 `json:"-"`
UUID string `json:"id"`
Organization *Organization `json:"organization"`
InternalID string `json:"internal_id"`
Name string `json:"name"`
Address string `json:"address"`
Description string `json:"desc"`
Latitude float64 `json:"lat"`
Longitude float64 `json:"long"`
Created time.Time `json:"created"`
CreatedUser User `json:"author"`
Updated time.Time `json:"updated"`
UpdatedUser User `json:"last_editor"`
Active bool `json:"active"`
}

17
domain/entity/profile.go Normal file
View File

@@ -0,0 +1,17 @@
package entity
import "time"
type Profile struct {
ID int64 `json:"-"`
Name string `json:"name"`
Key string `json:"key"`
Description string `json:"desc"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Active bool `json:"active"`
Blocked bool `json:"blocked"`
Suspended bool `json:"suspended"`
Visible bool `json:"visible"`
Organization Organization `json:"organization"`
}

126
domain/entity/provider.go Normal file
View File

@@ -0,0 +1,126 @@
package entity
import (
"time"
)
type Provider struct {
ProviderID int64 `json:"-"`
ProviderUUID string `json:"provider_uuid"`
InternalID string `json:"internal_id"`
InternalSuffixID string `json:"internal_suffix_id"`
MukID string `json:"muk_id"`
OrganizatioName string `json:"org_name"`
Gender string `json:"gender"`
AcceptNewPatients string `json:"accept_new_patients"`
Name string `json:"name"`
FirstName string `json:"first"`
MiddleName string `json:"middle"`
LastName string `json:"last"`
Title string `json:"title"`
Active bool `json:"active"`
Enabled bool `json:"enabled"`
CreateDate time.Time `json:"create_at"`
UpdateDate time.Time `json:"update_at"`
CreatedUser User `json:"created_user"`
Keys []ProviderKey `json:"keys"`
Address ProviderAddress `json:"address"`
Distance float64 `json:"distance"`
}
type ProviderKey struct {
ProviderKeyID int64 `json:"-"`
Provider Provider `json:"provider"`
InternalID string `json:"internal_id"`
InternalSuffixID string `json:"internal_suffix_id"`
LocationSeqNumber string `json:"location_seq_number"`
PlanCode string `json:"plan_code"`
ProductID string `json:"product_id"`
TreatmentCategoryCode string `json:"treatment_category_code"`
Active bool `json:"active"`
Enabled bool `json:"enabled"`
CreateDate time.Time `json:"create_at"`
UpdateDate time.Time `json:"update_at"`
CreatedUser User `json:"created_user"`
}
type ProviderAddress struct {
StreetAddress1 string `json:"street_address_1"`
StreetAddress2 string `json:"street_address_2"`
CityName string `json:"city"`
State string `json:"state"`
ZipCode string `json:"zipcode"`
Country string `json:"country"`
Latitude float64 `json:"lat"`
Longitude float64 `json:"long"`
PhoneNumber string `json:"phone_number"`
}
type ProviderResponse struct {
MukID string `json:"mukId"`
FivePartKeyGroups []PartKeyGroup `json:"fivePartKeyGroups"`
OrgName string `json:"orgName"`
Gender string `json:"gender"`
AcceptNewPatients string `json:"acceptNewPatients"`
ProviderName string `json:"providerName"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
MiddleName string `json:"middleName"`
ProviderTitle string `json:"providerTitle"`
StreetName1 string `json:"streetName_1"`
StreetName2 string `json:"streetName_2"`
CityName string `json:"cityName"`
State string `json:"state"`
ZipCode string `json:"zipCode"`
Country string `json:"country"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
PhoneNumber string `json:"phoneNumber"`
ProviderEntityName string `json:"providerEntityName"`
ProviderEntityCode string `json:"providerEntityCode"`
ProviderTypeCode []ProviderTypeCode `json:"providerTypeCode"`
Distance string `json:"distance"`
AvailabilityOfCost string `json:"availabilityOfCost"`
TDDPhoneNumber string `json:"tddPhoneNumber"`
ExtendedOfficeHours string `json:"extendedOfficeHours"`
ProviderCountyCode string `json:"providerCountyCode"`
ProviderCountyName string `json:"providerCountyName"`
HospitalAffiliationNames []HospitalAffiliationNames `json:"hospitalAffiliationNames"`
ProviderAffiliationNumber string `json:"providerAffiliationNumber"`
ProviderAffiliationName string `json:"providerAffiliationName"`
LanguagesSpoken []Languages `json:"languagesSpoken"`
OfficeLanguagesSpoken []Languages `json:"officeLanguagesSpoken"`
MedSchool string `json:"medSchool"`
MedSchoolYear string `json:"medSchoolYear"`
Internship string `json:"internship"`
Residence string `json:"residency"`
Specialty1 string `json:"specialty1"`
Specialty2 string `json:"specialty2"`
Specialty3 string `json:"specialty3"`
Specialty4 string `json:"specialty4"`
Certification1 string `json:"certification1"`
Certification2 string `json:"certification2"`
Certification3 string `json:"certification3"`
Certification4 string `json:"certification4"`
}
type HospitalAffiliationNames struct {
HospAffProvOrgName string `json:"hospAffProvOrgName"`
}
type Languages struct {
Code string `json:"code"`
}
type ProviderTypeCode struct {
Code string `json:"code"`
}
type PartKeyGroup struct {
ProviderNum string `json:"providerNum"`
ProviderNumSuffix string `json:"providerNumSuffix"`
LocationSeqNum string `json:"locationSeqNum"`
PlanCode string `json:"planCode"`
ProductID string `json:"productId"`
TreatmentCategoryCode string `json:"treatmentCategoryCode"`
}

116
domain/entity/ride.go Normal file
View File

@@ -0,0 +1,116 @@
package entity
import (
"time"
)
//WebhookResponse has the data and events from the webhook
type WebhookResponse struct {
EventID string `json:"event_id,omitempty"`
HREF string `json:"href,omitempty"`
OccurredAt time.Time `json:"occurred_at,omitempty"`
EventType string `json:"event_type,omitempty"`
Ride Ride `json:"event,omitempty"`
}
// Ride entity data
type Ride struct {
ID int64 `db:"ride_id" json:"-"`
UUID string `db:"ride_uuid" json:"ride_uuid"`
User User `db:"user" json:"user"`
Status RideStatus `db:"status" json:"status"`
Type RideType `db:"type" json:"type"`
InternalID string `db:"internal_id" json:"internal_id"`
RequestDate *time.Time `db:"request_date" json:"request_date"`
RequestMiliseconds *int64 `db:"request_ms" json:"request_ms"`
GenerateDate *time.Time `db:"generate_date" json:"generate_date"`
GenerateMiliseconds *int64 `db:"generate_ms" json:"generate_ms"`
Note string `db:"notes" json:"notes"`
PrimetimePercentage string `db:"primetime_percentage" json:"primetime_percentage"`
Passenger RidePassenger `db:"passenger" json:"passenger"`
Driver RideDriver `db:"driver" json:"driver"`
Vehicle RideVehicle `db:"vehicle" json:"vehicle"`
Route RideRoute `db:"route" json:"route"`
VisitDate *time.Time `db:"visit_date" json:"visit_date"`
VisitTime *time.Time `db:"visit_time" json:"visit_time"`
PickupTime *time.Time `db:"pickup_time" json:"pickup_time"`
Created time.Time `db:"create_at" json:"create_at"`
Updated time.Time `db:"update_at" json:"update_at"`
Visit Visit `db:"visit" json:"visit"`
CreatedUser User `db:"created_user" json:"created_user"`
TripType TripType `db:"trip_type" json:"trip_type"`
}
// RidePassenger entity data
type RidePassenger struct {
ID int64 `db:"ride_passenger_id" json:"-"`
FirstName string `db:"first_name" json:"first_name"`
LastName string `db:"last_name" json:"last_name"`
ImageURL *string `db:"image_url" json:"image_url"`
PhoneNumber string `db:"phone_number" json:"phone_number"`
InternalID *string `db:"internal_id" json:"internal_id"`
}
// RideStatus entity data
type RideStatus struct {
ID int64 `db:"ride_status_id" json:"-"`
Key string `db:"key" json:"key"`
Value string `db:"value" json:"value"`
}
// RideStatus entity data
type TripType struct {
ID int64 `db:"trip_type_id" json:"-"`
Key string `db:"trip_type_key" json:"key"`
Value string `db:"trip_type" json:"value"`
}
// RideType entity data
type RideType struct {
ID int64 `db:"ride_type_id" json:"-"`
Key string `db:"key" json:"key"`
Value string `db:"value" json:"value"`
}
// RideRoute entity data
type RideRoute struct {
ID int64 `db:"ride_route_id" json:"-"`
Origin Location `db:"origin" json:"origin"`
Destination Location `db:"destination" json:"destination"`
RouteKML *string `db:"route_kml" json:"route_kml"`
Distance float64 `db:"distance" json:"distance"`
Duration int64 `db:"duration" json:"duration"`
ETA int64 `db:"eta" json:"eta"`
Created time.Time `db:"create_at" json:"create_at"`
Updated time.Time `db:"update_at" json:"update_at"`
}
// Location entity data
type Location struct {
ID string `db:"id" json:"id"`
Name string `db:"name" json:"name"`
Address string `db:"address" json:"address"`
Latitude float64 `db:"lat" json:"lat"`
Longitude float64 `db:"lng" json:"lng"`
}
// RideDriver entity data
type RideDriver struct {
ID int64 `db:"ride_driver_id" json:"-"`
Name string `db:"name" json:"name"`
ImageURL *string `db:"image_url" json:"image_url"`
PhoneNumber string `db:"phone_number" json:"phone_number"`
Rating *string `db:"rating" json:"rating"`
}
// RideVehicle entity data
type RideVehicle struct {
ID int64 `db:"ride_vehicle_id" json:"-"`
Color string `db:"color" json:"color"`
ImageURL string `db:"image_url" json:"image_url"`
LicensePlate string `db:"license_plate" json:"license_plate"`
LicensePlateState string `db:"license_plate_state" json:"license_plate_state"`
Make string `db:"make" json:"make"`
Model string `db:"model" json:"model"`
Year int64 `db:"year" json:"year"`
}

55
domain/entity/user.go Normal file
View File

@@ -0,0 +1,55 @@
package entity
import (
"strings"
"time"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
// User entity data
type User struct {
ID int64 `db:"user_id" json:"-"`
UUID string `db:"user_uuid" json:"uuid"`
Name string `db:"name" json:"name"`
Member string `db:"member" json:"member"`
BirthDate time.Time `db:"birth_date" json:"birthdate"`
LoginID int64 `db:"login_id" json:"-"`
LoginUUID string `db:"login_uuid" json:"loginuuid"`
Email string `db:"email" json:"email"`
PhoneNumber string `db:"phone_number" json:"phonenumber"`
Pass string `db:"password" json:"pass"`
LoginKey string `db:"login_key" json:"loginkey"`
Gender string `db:"gender" json:"gender"`
Active bool `db:"active" json:"active"`
Created time.Time `db:"createat" json:"createat"`
Updated time.Time `db:"updateat" json:"updateat"`
Contacts []ContactInfo `db:"contacts" json:"contacts"`
Rides []Ride `db:"rides" json:"rides"`
Addresses []Address `db:"addresses" json:"addresses"`
Profiles []Profile `json:"profiles,omitempty"`
Types []OrganizationType `json:"types,omitempty"`
Organizations []Organization `json:"organizations,omitempty"`
}
type ContactInfo struct {
ID int64 `db:"contact_id" json:"contact_id"`
Type ContactType `db:"contact_type" json:"contact_type"`
UserID int64 `db:"user_id" json:"-"`
Value string `db:"value" json:"value"`
}
type ContactType struct {
ID int64 `db:"contact_type_id" json:"contact_type_id"`
Key string `db:"contact_type_key" json:"contact_type_key"`
Value string `db:"contact_type_value" json:"contact_type_value"`
}
// Validate validates the user entity state
func (entity *User) Validate() error {
if strings.TrimSpace(entity.Name) == "" {
return errors.NewValidationError("name", "Nome do usuário é obrigatório")
}
return nil
}

35
domain/entity/visit.go Normal file
View File

@@ -0,0 +1,35 @@
package entity
import (
"time"
)
// VisitStatus entity data
type VisitStatus struct {
ID int64 `db:"visit_status_id" json:"-"`
Key string `db:"key" json:"key"`
Value string `db:"value" json:"value"`
}
// Visit entity data
type Visit struct {
ID int64 `db:"visit_id" json:"-"`
UUID string `db:"visit_uuid" json:"-"`
Status VisitStatus `db:"visit_status" json:"-"`
User User `db:"user" json:"-"`
VisitDuration int64 `db:"visit_duration" json:"-"`
VisitDatetime time.Time `db:"visit_datetime" json:"-"`
PickupDatetime time.Time `db:"pickup_datetime" json:"-"`
Notes *string `db:"notes" json:"-"`
PickupAddressID int64 `db:"pickup_address_id" json:"-"`
DestinationAddressID int64 `db:"destination_address_id" json:"-"`
Pickup Location `db:"pickup" json:"-"`
Provider Provider `db:"provider" json:"-"`
CreatedUser User `db:"created_user" json:"-"`
Created time.Time `db:"created_date" json:"-"`
Updated time.Time `db:"updated_date" json:"-"`
ReturnDate *time.Time `db:"return_date" json:"-"`
TripType TripType `db:"trip_type" json:"-"`
ExternalID string `db:"visit_external_id" json:"-"`
Rides []Ride `db:"rides" json:"-"`
}

View File

@@ -0,0 +1,36 @@
package service
import "bitbucket.org/nemt/nemt-portal-api/domain/entity"
// userService is the domain service for user operations
type notificationService struct {
svc *Service
}
// newUserService returns an instance of userService
func newNotificationService(svc *Service) *notificationService {
return &notificationService{
svc: svc,
}
}
// Save the ride for a expected user
func (s *notificationService) Create(notification entity.Notification) (entity.Notification, error) {
return s.svc.db.Notification().Create(notification)
}
func (c *notificationService) GetByUserUUIDAndReadStatus(userUUID string, status string, isRead bool) ([]entity.Notification, error) {
return c.svc.db.Notification().GetByUserUUIDAndReadStatus(userUUID, status, isRead)
}
func (c *notificationService) GetByUserUUID(userUUID string, status string) ([]entity.Notification, error) {
return c.svc.db.Notification().GetByUserUUID(userUUID, status)
}
func (c *notificationService) ReadStatus(notificationUUID string, isRead bool) error {
return c.svc.db.Notification().ReadStatus(notificationUUID, isRead)
}
func (c *notificationService) GetLastNotificationFromPhoneNumber(notificationType string, phoneNumber string, status string) (entity.Notification, error) {
return c.svc.db.Notification().GetLastNotificationFromPhoneNumber(notificationType, phoneNumber, status)
}

View File

@@ -0,0 +1,113 @@
package service
import (
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
// userService is the domain service for user operations
type organizationService struct {
svc *Service
}
// newUserService returns an instance of userService
func newOrganizationService(svc *Service) *organizationService {
return &organizationService{
svc: svc,
}
}
func (s *organizationService) GetAllTypes() ([]entity.OrganizationType, error) {
return s.svc.db.Organization().GetAllTypes()
}
func (s *organizationService) GetByType(organizationTypeKey string) ([]entity.Organization, error) {
return s.svc.db.Organization().GetByType(organizationTypeKey)
}
func (s *organizationService) GetByName(name string, searchType string) ([]entity.Organization, error) {
return s.svc.db.Organization().GetByName(name, searchType)
}
func (s *organizationService) GetByUUID(organizationUUID string) (entity.Organization, error) {
organization, err := s.svc.db.Organization().GetByUUID(organizationUUID)
if err != nil {
return organization, err
}
organization.Contacts, err = s.GetContactsByOrganizationID(organization.ID)
if err != nil {
return organization, err
}
organization.Addresses, err = s.GetAddressByOrganizationID(organization.ID)
if err != nil {
return organization, err
}
organization.ChildOrgs, err = s.svc.db.Organization().GetChildsByID(organization.ID)
if err != nil {
return organization, err
}
if organization.ParentID > 0 {
parent, err := s.svc.db.Organization().GetByID(organization.ParentID)
if err != nil {
return organization, err
}
organization.Parent = &parent
}
return organization, nil
}
func (s *organizationService) SetParentOrganization(organizationID int64, parentOrganizationID int64) error {
return s.svc.db.Organization().SetParentOrganization(organizationID, parentOrganizationID)
}
func (s *organizationService) GetContactsByOrganizationUUID(organizationUUID string) ([]entity.OrganizationContact, error) {
return s.svc.db.Organization().GetContactsByOrganizationUUID(organizationUUID)
}
func (s *organizationService) GetContactsByOrganizationID(organizationID int64) ([]entity.OrganizationContact, error) {
return s.svc.db.Organization().GetContactsByOrganizationID(organizationID)
}
func (s *organizationService) GetContactsByUUID(contactUUID string) (entity.OrganizationContact, error) {
return s.svc.db.Organization().GetContactsByUUID(contactUUID)
}
func (s *organizationService) GetAddressByOrganizationUUID(organizationUUID string) ([]entity.OrganizationAddress, error) {
return s.svc.db.Organization().GetAddressByOrganizationUUID(organizationUUID)
}
func (s *organizationService) GetAddressByOrganizationID(organizationID int64) ([]entity.OrganizationAddress, error) {
return s.svc.db.Organization().GetAddressByOrganizationID(organizationID)
}
func (s *organizationService) GetAddressByUUID(contactUUID string) (entity.OrganizationAddress, error) {
return s.svc.db.Organization().GetAddressByUUID(contactUUID)
}
func (s *organizationService) InactivateOrganizationAddress(address entity.OrganizationAddress) error {
return s.svc.db.Organization().InactivateOrganizationAddress(address)
}
func (s *organizationService) SetOrganizationAddress(address entity.OrganizationAddress) (entity.OrganizationAddress, error) {
return s.svc.db.Organization().SetOrganizationAddress(address)
}
func (s *organizationService) InactivateOrganizationContact(contact entity.OrganizationContact) error {
return s.svc.db.Organization().InactivateOrganizationContact(contact)
}
func (s *organizationService) SetOrganizationContact(contact entity.OrganizationContact) (entity.OrganizationContact, error) {
return s.svc.db.Organization().SetOrganizationContact(contact)
}
func (s *organizationService) AddOrganization(organization entity.Organization) (entity.Organization, error) {
return s.svc.db.Organization().AddOrganization(organization)
}
func (s *organizationService) GetTypeByKey(key string) (entity.OrganizationType, error) {
return s.svc.db.Organization().GetTypeByKey(key)
}

33
domain/service/profile.go Normal file
View File

@@ -0,0 +1,33 @@
package service
import (
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
// userService is the domain service for user operations
type profileService struct {
svc *Service
}
// newUserService returns an instance of userService
func newProfileService(svc *Service) *profileService {
return &profileService{
svc: svc,
}
}
func (s *profileService) GetAll() ([]entity.Profile, error) {
return s.svc.db.Profile().GetAll()
}
func (s *profileService) GetByKey(key string) (entity.Profile, error) {
return s.svc.db.Profile().GetByKey(key)
}
func (s *profileService) GetVisibles(visible bool) ([]entity.Profile, error) {
return s.svc.db.Profile().GetVisibles(visible)
}
func (s *profileService) GetByOrganizationType(organizationTypeID int64) ([]entity.Profile, error) {
return s.svc.db.Profile().GetByOrganizationType(organizationTypeID)
}

View File

@@ -0,0 +1,46 @@
package service
import (
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
// userService is the domain service for user operations
type providerService struct {
svc *Service
}
// newUserService returns an instance of userService
func newProviderService(svc *Service) *providerService {
return &providerService{
svc: svc,
}
}
// Save the ride for a expected user
func (s *providerService) Save(providers []entity.ProviderResponse, user entity.User) ([]entity.Provider, error) {
tx, err := s.svc.db.Begin()
if err != nil {
return nil, err
}
newProviders, err := tx.Provider().Save(providers, user)
if err != nil {
tx.Rollback()
return nil, err
}
tx.Commit()
return newProviders, nil
}
func (s *providerService) GetAll(user entity.User) ([]entity.Provider, error) {
return s.svc.db.Provider().GetAll(user)
}
func (s *providerService) 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) {
return s.svc.db.Provider().Get(query, lat, long, distance, planCode, productID, mukID, internalID, sort, user)
}
func (s *providerService) GetByMukID(mukID string, user entity.User) (entity.Provider, error) {
return s.svc.db.Provider().GetByMukID(mukID, user)
}

103
domain/service/ride.go Normal file
View File

@@ -0,0 +1,103 @@
package service
import (
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
// userService is the domain service for user operations
type rideService struct {
svc *Service
}
// newUserService returns an instance of userService
func newRideService(svc *Service) *rideService {
return &rideService{
svc: svc,
}
}
// Save the ride for a expected user
func (s *rideService) Save(ride entity.Ride) (entity.Ride, error) {
ride, err := s.svc.db.Rides().Save(ride)
if err != nil {
return ride, err
}
user, err := s.svc.db.Users().GetByID(ride.CreatedUser.ID)
if err != nil {
return ride, err
}
return s.GetByUUID(ride.UUID, user)
}
func (s *rideService) Update(hook entity.WebhookResponse) (entity.Ride, error) {
user, err := s.svc.db.Users().GetByID(hook.Ride.CreatedUser.ID)
if err != nil {
return entity.Ride{}, err
}
ride, err := s.svc.db.Rides().Update(hook, user)
if err != nil {
return ride, err
}
return s.GetByUUID(ride.UUID, user)
}
// GetAll return all rides
func (s *rideService) GetAll(user entity.User) ([]entity.Ride, error) {
return s.svc.db.Rides().GetAll(user)
}
func (s *rideService) GetByID(id int64, user entity.User) (entity.Ride, error) {
return s.svc.db.Rides().GetByID(id, user)
}
// GetByUUID return a specific ride
func (s *rideService) GetByUUID(uuid string, user entity.User) (entity.Ride, error) {
return s.svc.db.Rides().GetByUUID(uuid, user)
}
// GetByUUID return a specific ride
func (s *rideService) GetByUUIDAndUserUUID(UUID string, userUUID string) (entity.Ride, error) {
return s.svc.db.Rides().GetByUUIDAndUserUUID(UUID, userUUID)
}
// GetByUUID return a specific ride
func (s *rideService) GetByInternalID(internalID string) (entity.Ride, error) {
return s.svc.db.Rides().GetByInternalID(internalID)
}
// GetByUserID return a list of rides
func (s *rideService) GetByUserID(userID int64, user entity.User) ([]entity.Ride, error) {
return s.svc.db.Rides().GetByUserID(userID, user)
}
func (s *rideService) GetByUserUUID(userUUID string, user entity.User) ([]entity.Ride, error) {
return s.svc.db.Rides().GetByUserUUID(userUUID, user)
}
func (s *rideService) UpdateStatus(rideUUID string, status string) error {
return s.svc.db.Rides().UpdateStatus(rideUUID, status)
}
func (s *rideService) GetLastRideByPhoneNumber(phoneNumber string) (entity.Ride, error) {
return s.svc.db.Rides().GetLastRideByPhoneNumber(phoneNumber)
}
func (s *rideService) GetLastRideByDriversNumber(phoneNumber string) (entity.Ride, error) {
return s.svc.db.Rides().GetLastRideByDriversNumber(phoneNumber)
}
func (s *rideService) GetByInternalPassengerID(internalPassengerID string) (entity.Ride, error) {
return s.svc.db.Rides().GetByInternalPassengerID(internalPassengerID)
}
func (s *rideService) GetByVisitUUID(visitUUID string, user entity.User) ([]entity.Ride, error) {
return s.svc.db.Rides().GetByVisitUUID(visitUUID, user)
}
func (s *rideService) GetByVisitUUIDAndTripType(visitUUID string, tripTypeKey string, user entity.User) (entity.Ride, error) {
return s.svc.db.Rides().GetByVisitUUIDAndTripType(visitUUID, tripTypeKey, user)
}

45
domain/service/service.go Normal file
View File

@@ -0,0 +1,45 @@
package service
import (
"sync"
"bitbucket.org/nemt/nemt-portal-api/domain/contract"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/infra/logger"
)
var (
instance *Service
once sync.Once
)
// Service holds the domain service repositories
type Service struct {
db contract.DataManager
cache contract.CacheManager
tnc contract.TNCManager
Users *userService
Rides *rideService
Visits *visitService
Provider *providerService
Notification *notificationService
Profile *profileService
Organization *organizationService
}
// New returns a new domain Service instance
func New(db contract.DataManager, cache contract.CacheManager, cfg *config.Config, log *logger.Logger) (*Service, error) {
once.Do(func() {
instance = &Service{db: db, cache: cache}
instance.Users = newUserService(instance)
instance.Rides = newRideService(instance)
instance.Visits = newVisitService(instance)
instance.Provider = newProviderService(instance)
instance.Notification = newNotificationService(instance)
instance.Profile = newProfileService(instance)
instance.Organization = newOrganizationService(instance)
})
return instance, nil
}

28
domain/service/tnc.go Normal file
View File

@@ -0,0 +1,28 @@
package service
// tncService is the domain service for transportation network operations
type tncService struct {
svc *Service
}
// newTncService returns an instance of tncService
func newTncService(svc *Service) *tncService {
return &tncService{
svc: svc,
}
}
//GetETA will return the list of ETA's for the current location
func (s *tncService) GetETA(lag float64, log float64, params map[string]interface{}) (interface{}, error) {
return s.svc.tnc.GetETA(lag, log, params)
}
//GetDrivers return the drivers for the current location
func (s *tncService) GetDrivers(lag float64, log float64) (interface{}, error) {
return s.svc.tnc.GetDrivers(lag, log)
}
//GetTypes will return the available types of ride for the current location
func (s *tncService) GetTypes(lag float64, log float64, params map[string]interface{}) (interface{}, error) {
return s.svc.tnc.GetTypes(lag, log, params)
}

92
domain/service/user.go Normal file
View File

@@ -0,0 +1,92 @@
package service
import (
"fmt"
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
)
// userService is the domain service for user operations
type userService struct {
svc *Service
}
// newUserService returns an instance of userService
func newUserService(svc *Service) *userService {
return &userService{
svc: svc,
}
}
// GetAll returns a list of users
func (s *userService) GetAll() (list []entity.User, err error) {
return s.svc.db.Users().GetAll()
}
// GetByID returns a specific user by its ID
func (s *userService) GetByID(userID int64) (entity.User, error) {
return s.svc.db.Users().GetByID(userID)
}
// GetByID returns a specific user by its ID
func (s *userService) GetByUUID(uuid string, profile string) (entity.User, error) {
return s.svc.db.Users().GetByUUID(uuid, profile)
}
// Login returns a specific user by email and pass
func (s *userService) Login(email string, pass string) (entity.User, error) {
return s.svc.db.Users().Login(email, pass)
}
// Login returns a specific user by email and pass
func (s *userService) FullLogin(loginType string, key string, pass string, profile string) (entity.User, error) {
return s.svc.db.Users().FullLogin(loginType, key, pass, profile)
}
// Login returns a specific user by email and pass
func (s *userService) Create(user entity.User) (entity.User, error) {
return s.svc.db.Users().Create(user)
}
func (s *userService) CreateBulk(users []entity.User) ([]entity.User, error) {
tx, err := s.svc.db.Begin()
if err != nil {
return nil, err
}
for i, _ := range users {
users[i], err = tx.Users().Create(users[i])
if err != nil {
fmt.Println(fmt.Sprintf("Email %s got error: %s", users[i].Email, err.Error()))
tx.Rollback()
return nil, err
}
fmt.Println(fmt.Sprintf("Email %s created", users[i].Email))
}
tx.Commit()
return users, nil
}
// GetUsersByProfile returns a list of users by profile
func (s *userService) GetUsersByProfile(profile string) ([]entity.User, error) {
return s.svc.db.Users().GetUsersByProfile(profile)
}
func (s *userService) RemoveAddress(addressUUID string) error {
return s.svc.db.Users().RemoveAddress(addressUUID)
}
// SaveAddress returns a list of users by profile
func (s *userService) SaveAddress(address entity.Address) (entity.Address, error) {
return s.svc.db.Users().SaveAddress(address)
}
// GetAddressByUUID returns a list of users by profile
func (s *userService) GetAddressByUUID(addressUUID string) (entity.Address, error) {
return s.svc.db.Users().GetAddressByUUID(addressUUID)
}
func (s *userService) GetContactType() (retVal []entity.ContactType, err error) {
return s.svc.db.Users().GetContactType()
}

81
domain/service/visit.go Normal file
View File

@@ -0,0 +1,81 @@
package service
import (
"bitbucket.org/nemt/nemt-portal-api/domain/entity"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
// userService is the domain service for user operations
type visitService struct {
svc *Service
}
// newUserService returns an instance of userService
func newVisitService(svc *Service) *visitService {
return &visitService{
svc: svc,
}
}
// Save the ride for a expected user
func (s *visitService) Create(visit entity.Visit) (entity.Visit, error) {
return s.svc.db.Visits().Create(visit)
}
// Save the ride for a expected user
func (s *visitService) GetAll(user entity.User) ([]entity.Visit, error) {
visit, err := s.svc.db.Visits().GetAll(user)
if err != nil {
return nil, err
}
rides, err := s.svc.db.Rides().GetAll(user)
if err != nil {
return nil, err
}
ridesByVisit := make(map[int64][]entity.Ride)
for _, r := range rides {
rides := ridesByVisit[r.Visit.ID]
rides = append(rides, r)
ridesByVisit[r.Visit.ID] = rides
}
for i, v := range visit {
visit[i].Rides = ridesByVisit[v.ID]
}
return visit, nil
}
// Save the ride for a expected user
func (s *visitService) GetByUUID(visitUUID string, user entity.User) (entity.Visit, error) {
visit, err := s.svc.db.Visits().GetByUUID(visitUUID, user)
if err != nil {
return entity.Visit{}, errors.Wrap(err)
}
rides, err := s.svc.db.Rides().GetByVisitUUID(visitUUID, user)
if err != nil {
return entity.Visit{}, errors.Wrap(err)
}
visit.Rides = rides
return visit, nil
}
// Save the ride for a expected user
func (s *visitService) GetByID(visitID int64, user entity.User) (entity.Visit, error) {
visit, err := s.svc.db.Visits().GetByID(visitID, user)
if err != nil {
return entity.Visit{}, errors.Wrap(err)
}
rides, err := s.svc.db.Rides().GetByVisitUUID(visit.UUID, user)
if err != nil {
return entity.Visit{}, errors.Wrap(err)
}
visit.Rides = rides
return visit, nil
}

35
ecs.dev.json Normal file
View File

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

35
ecs.prd.json Normal file
View File

@@ -0,0 +1,35 @@
{
"containerDefinitions": [
{
"name": "portal-api-prod",
"image": "105690980714.dkr.ecr.us-east-2.amazonaws.com/nemt-portal-api:prod",
"cpu": 128,
"memory": 128,
"essential": true,
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "portal-api",
"awslogs-region": "us-east-2",
"awslogs-stream-prefix": "prod"
}
},
"portMappings": [
{
"containerPort": 5100
}
],
"environment": [
{
"name": "SERVICE_5100_NAME",
"value": "portal-api"
},
{
"name": "SERVICE_5100_TAGS",
"value": "api"
}
]
}
],
"family": "portal-api-prod"
}

35
ecs.stg.json Normal file
View File

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

44
glide.yaml Normal file
View File

@@ -0,0 +1,44 @@
package: bitbucket.org/nemt/nemt-portal-api
import:
- package: github.com/Sirupsen/logrus
version: ~1.0.2
- package: github.com/dgrijalva/jwt-go
version: ~3.0.0
- package: github.com/go-sql-driver/mysql
version: ~1.3.0
- package: github.com/labstack/echo
version: ~3.2.1
subpackages:
- middleware
- package: github.com/labstack/gommon
version: ~0.2.2
subpackages:
- log
- package: github.com/spf13/viper
- package: gopkg.in/redis.v5
version: ~5.2.9
- package: github.com/didip/tollbooth
- package: github.com/lyft/lyft-go-sdk
subpackages:
- lyft
- package: github.com/pquerna/ffjson
- package: github.com/graarh/golang-socketio
- package: github.com/gorilla/websocket
- package: github.com/justwatchcom/goat
- package: googlemaps.github.io/maps
- package: gopkg.in/gomail.v2
version: ~2.0.0
- package: github.com/srajelli/ses-go
- package: github.com/aws/aws-sdk-go
version: ~1.12.66
- package: google.golang.org/api
subpackages:
- urlshortener/v1
- package: golang.org/x/oauth2
subpackages:
- google
- package: github.com/ttacon/libphonenumber
version: ~1.0.0
- package: github.com/ttacon/builder
- package: github.com/casbin/casbin
version: ~1.5.0

153
infra/auth/auth.go Normal file
View File

@@ -0,0 +1,153 @@
package auth
import (
"crypto/rsa"
"fmt"
"io/ioutil"
"time"
"github.com/pquerna/ffjson/ffjson"
"strings"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
jwt "github.com/dgrijalva/jwt-go"
"github.com/labstack/echo"
)
const (
// AppKeyHeaderName is the header name for application keys
AppKeyHeaderName = "App"
// AppTokenHeaderName is the header name for application token
AppTokenHeaderName = "Token"
// TokenExpiration is the auth token default expiration time
TokenExpiration = 24 * time.Hour
)
var (
// TokenSigningMethod is the auth token signing algorithm
TokenSigningMethod = jwt.SigningMethodRS256
)
// GetAppKeyFromContext returns the application key from request header
func GetAppKeyFromContext(ctx echo.Context) (appKey string, err error) {
appKey = ctx.Request().Header.Get(AppKeyHeaderName)
if strings.TrimSpace(appKey) == "" {
return "", errors.NewNotAuthorizedError("Application key not found")
}
return appKey, nil
}
// ValidateAppKey validates the presence and validity of App key
func ValidateAppKey(ctx echo.Context, cfg *config.Config) (err error) {
appKey, err := GetAppKeyFromContext(ctx)
if err != nil {
return errors.Wrap(err)
}
if appKey != cfg.HTTP.Auth.AppKey {
return errors.NewNotAuthorizedError("Invalid API Key")
}
return nil
}
// GetCertPrivateKey returns the private key for the token authentication certificate
func GetCertPrivateKey(path string) (pk *rsa.PrivateKey, err error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, errors.Wrap(err)
}
pk, err = jwt.ParseRSAPrivateKeyFromPEM(data)
if err != nil {
return nil, errors.Wrap(err)
}
return pk, nil
}
// GetCertPublicKey returns the public key for the token authentication certificate
func GetCertPublicKey(path string) (pk *rsa.PublicKey, err error) {
privateKey, err := GetCertPrivateKey(path)
if err != nil {
return nil, errors.Wrap(err)
}
return &privateKey.PublicKey, nil
}
// GenerateToken creates a token based on certificate
func GenerateToken(cfg *config.Config, data interface{}) (tokenString string, err error) {
key, _ := GetCertPrivateKey(cfg.HTTP.Auth.CertificatePath)
claims := jwt.MapClaims{
"iat": time.Now().Unix(),
"exp": time.Now().Add(TokenExpiration).Unix(),
"iss": "BDC",
"sub": "NEMT",
"data": data,
}
token := jwt.NewWithClaims(TokenSigningMethod, claims)
tokenString, err = token.SignedString(key)
if err != nil {
return tokenString, errors.Wrap(err)
}
return tokenString, nil
}
func GetTokenDetail(ctx echo.Context, cfg *config.Config) (interface{}, error) {
key, _ := GetCertPublicKey(cfg.HTTP.Auth.CertificatePath)
tokenString := ctx.Request().Header.Get("Token")
tokenString = strings.Replace(tokenString, "Bearer ", "", -1)
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
return key, nil
})
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
return claims["data"], nil
} else {
return nil, err
}
}
func GetUserDetail(ctx echo.Context, cfg *config.Config) (viewmodel.User, error) {
key, _ := GetCertPublicKey(cfg.HTTP.Auth.CertificatePath)
tokenString := ctx.Request().Header.Get("Token")
tokenString = strings.Replace(tokenString, "Bearer ", "", -1)
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
return key, nil
})
if err != nil {
return viewmodel.User{}, err
}
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
byteData, _ := ffjson.Marshal(claims["data"])
user := viewmodel.User{}
err = ffjson.Unmarshal(byteData, &user)
if err != nil {
return viewmodel.User{}, err
} else {
return user, nil
}
} else {
return viewmodel.User{}, err
}
}

109
infra/aws/aws.go Normal file
View File

@@ -0,0 +1,109 @@
package aws
import (
"bytes"
"net/http"
"path"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
"github.com/aws/aws-sdk-go/service/ssm"
)
//AWSUtil return the methods to interact with AWS Services
type AWSUtil struct {
configApp *config.Config
awsConfig *aws.Config
s3Service *s3.S3
ssmService *ssm.SSM
awsSession *session.Session
}
//New return an instance of AWSUtil
func New(configApp *config.Config) *AWSUtil {
cfg := aws.NewConfig().WithRegion("sa-east-1")
cfg.DisableRestProtocolURICleaning = aws.Bool(true)
return &AWSUtil{
configApp: configApp,
awsConfig: cfg,
s3Service: s3.New(session.New(), cfg),
ssmService: ssm.New(session.New(), cfg),
awsSession: session.New(cfg),
}
}
//DownloadFromS3Bucket will return the file on the S3 Bucket
func (a AWSUtil) DownloadFromS3Bucket(filePath string) ([]byte, error) {
downloader := s3manager.NewDownloader(a.awsSession)
b := &aws.WriteAtBuffer{}
_, err := downloader.Download(b, &s3.GetObjectInput{
Bucket: aws.String(a.configApp.Aws.S3Bucket),
Key: aws.String(filePath),
})
if err != nil {
return []byte{}, err
} else {
return b.Bytes(), nil
}
}
//UploadToS3Bucket will upload a file to the S3 Bucket
func (a AWSUtil) UploadToS3Bucket(filePath string, fileName string, buff []byte) error {
fileBytes := bytes.NewReader(buff)
fileType := http.DetectContentType(buff)
fullPath := path.Join(filePath, fileName)
params := &s3.PutObjectInput{
Bucket: aws.String(a.configApp.Aws.S3Bucket),
Key: aws.String(fullPath),
Body: fileBytes,
ContentLength: aws.Int64(int64(len(buff))),
ContentType: aws.String(fileType),
}
_, err := a.s3Service.PutObject(params)
if err != nil {
return err
}
return nil
}
//SsmPutParameter put parameter to SSM
func (a AWSUtil) SsmPutParameter(parameterName string, parameterValue string) error {
params := &ssm.PutParameterInput{
Name: aws.String(parameterName),
Type: aws.String("SecureString"),
Value: aws.String(parameterValue),
}
_, err := a.ssmService.PutParameter(params)
if err != nil {
return err
}
return nil
}
//SsmGetParameter get parameter from SSM
func (a AWSUtil) SsmGetParameter(parameterName string, withDecryption bool) (string, error) {
params := &ssm.GetParameterInput{
Name: aws.String(parameterName),
WithDecryption: aws.Bool(withDecryption),
}
output, err := a.ssmService.GetParameter(params)
if err != nil {
return "", err
}
return (*output.Parameter.Value), nil
}

144
infra/cache/cache.go vendored Normal file
View File

@@ -0,0 +1,144 @@
package cache
import (
"encoding/json"
"fmt"
redis "gopkg.in/redis.v5"
"time"
"sync"
"bitbucket.org/nemt/nemt-portal-api/domain"
"bitbucket.org/nemt/nemt-portal-api/domain/contract"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
var (
instance *RedisCache
once sync.Once
)
// RedisCache implements the CacheManager interface
type RedisCache struct {
cfg *config.Config
redis *redis.Client
}
// Instance returns a CacheManager instance
func Instance(cfg *config.Config) contract.CacheManager {
once.Do(func() {
client := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: "master01",
SentinelAddrs: []string{fmt.Sprintf("%s:%v", cfg.Cache.Server, cfg.Cache.Port)},
Password: cfg.Cache.Pass,
DB: cfg.Cache.DB,
})
instance = &RedisCache{cfg, client}
})
return instance
}
func (r *RedisCache) buildKey(key string) string {
return fmt.Sprintf("%s-%s", r.cfg.Cache.Prefix, key)
}
// GetItem returns an Item from cache
func (r *RedisCache) GetItem(key string) (data []byte, err error) {
val, err := r.redis.Get(r.buildKey(key)).Bytes()
if err == redis.Nil {
return val, domain.ErrCacheMiss
} else if err != nil {
return val, errors.Wrap(err)
}
return val, nil
}
// SetItem sets an item in cache
func (r *RedisCache) SetItem(key string, data []byte) error {
err := r.redis.Set(r.buildKey(key), data, r.cfg.Cache.DefaultExpiration).Err()
if err != nil {
return errors.Wrap(err)
}
return nil
}
// GetString returns an string from cache
func (r *RedisCache) GetString(key string) (data string, err error) {
val, err := r.GetItem(key)
if err == domain.ErrCacheMiss {
return data, domain.ErrCacheMiss
} else if err != nil {
return data, errors.Wrap(err)
}
return string(val), nil
}
// SetString sets an item in cache
func (r *RedisCache) SetString(key string, data string) error {
err := r.SetItem(key, []byte(data))
if err != nil {
return errors.Wrap(err)
}
return nil
}
// GetStruct returns an struct from cache
func (r *RedisCache) GetStruct(key string, data interface{}) (err error) {
val, err := r.GetItem(key)
if err == domain.ErrCacheMiss {
return domain.ErrCacheMiss
} else if err != nil {
return errors.Wrap(err)
}
err = json.Unmarshal(val, &data)
if err != nil {
return errors.Wrap(err)
}
return nil
}
// SetStruct sets an item in cache
func (r *RedisCache) SetStruct(key string, data interface{}) error {
dataString, err := json.Marshal(data)
if err != nil {
return errors.Wrap(err)
}
err = r.SetItem(key, dataString)
if err != nil {
return errors.Wrap(err)
}
return nil
}
// GetExpiration returns the expiration time for a key
func (r *RedisCache) GetExpiration(key string) (expiration time.Duration, err error) {
expiration, err = r.redis.TTL(r.buildKey(key)).Result()
if err != nil {
return expiration, errors.Wrap(err)
}
return expiration, nil
}
// SetExpiration sets the expiration time for a key
func (r *RedisCache) SetExpiration(key string, expiration time.Duration) (err error) {
err = r.redis.Expire(r.buildKey(key), expiration).Err()
if err != nil {
return errors.Wrap(err)
}
return nil
}

249
infra/config/config.go Normal file
View File

@@ -0,0 +1,249 @@
package config
import (
"strings"
"os"
"time"
"github.com/spf13/viper"
)
// Config represents the configuration values for the whole service.
type Config struct {
App AppConfig
DB DBConfig
HTTP HTTPConfig
Log LogConfig
Aws AwsConfig
Cache CacheConfig
Twilio TwilioConfig
Lyft LyftConfig
LyftProd LyftProdConfig
BXE BXEConfig
Blue365 Blue365Config
Email EmailConfig
GoogleShortener GoogleShortenerConfig
}
// AppConfig represents the configuration values about the application.
type AppConfig struct {
Name string
Debug bool
Docs DocsConfig
}
// TwilioConfig represents the configuration values about the twilio.
type TwilioConfig struct {
Account string
Token string
Sender string
TwiMLSID string
}
// LyftConfig represents the configuration values about the lyft.
type LyftConfig struct {
Client string
Secret string
RefreshToken string
}
type LyftProdConfig struct {
Lyft LyftConfig
UserUUID string
}
// BXEConfig represents the configuration values about the BXE.
type BXEConfig struct {
URL string
APIKey string
Secret string
}
// Blue365Config represents the configuration values about the Blue 365.
type Blue365Config struct {
URL string
APIKey string
Secret string
}
// DBConfig represents the configuration values about the DB.
type DBConfig struct {
User string
Pass string
Name string
Host string
Port int
MaxLifeInMinutes int
MaxIdleConns int
MaxOpenConns int
}
// HTTPConfig represents the configuration values about the HTTP server.
type HTTPConfig struct {
Port int
Prefix string
Auth HTTPAuthConfig
}
// HTTPAuthConfig represents the configuration values about the HTTP authentication (JWT and CORS).
type HTTPAuthConfig struct {
AppKey string
CertificatePath string
FrontendURLs []string
}
// LogConfig represents the configuration values about the logging config.
type LogConfig struct {
LogToFile bool
Path string
}
// AwsConfig represents the configuration values about the aws config.
type AwsConfig struct {
S3Bucket string
}
// DocsConfig represents the configuration values about the documentation config.
type DocsConfig struct {
YAMLPath string
SwaggerPath string
}
// CacheConfig represents the configuration values about the documentation config.
type CacheConfig struct {
Server string
Port int
DB int
Pass string
Prefix string
DefaultExpiration time.Duration
}
// CacheConfig represents the configuration values about the documentation config.
type EmailConfig struct {
Server string
Port int
User string
Pass string
Sender string
}
type GoogleShortenerConfig struct {
APIKey string
ClientID string
SecretKey string
}
// Read returns the configuration values,
// based on the configuration files and environment variables.
func Read() (*Config, error) {
setup()
err := viper.ReadInConfig()
if err != nil {
if err == os.ErrNotExist {
viper.SetConfigName("config.local")
err = viper.ReadInConfig()
}
if err != nil {
return nil, err
}
}
return &Config{
App: AppConfig{
Name: viper.GetString("app.name"),
Debug: viper.GetBool("app.debug"),
Docs: DocsConfig{
YAMLPath: viper.GetString("app.docs.yaml-path"),
SwaggerPath: viper.GetString("app.docs.swagger-path"),
},
},
DB: DBConfig{
User: viper.GetString("db.user"),
Pass: viper.GetString("db.pass"),
Name: viper.GetString("db.name"),
Host: viper.GetString("db.host"),
Port: viper.GetInt("db.port"),
MaxLifeInMinutes: viper.GetInt("db.max-life-minutes"),
MaxIdleConns: viper.GetInt("db.max-idle-conns"),
MaxOpenConns: viper.GetInt("db.max-open-conns"),
},
HTTP: HTTPConfig{
Port: viper.GetInt("http.port"),
Prefix: viper.GetString("http.prefix"),
Auth: HTTPAuthConfig{
AppKey: viper.GetString("http.auth.app-key"),
CertificatePath: viper.GetString("http.auth.certificate-path"),
FrontendURLs: viper.GetStringSlice("http.auth.frontend-urls"),
},
},
Log: LogConfig{
LogToFile: viper.GetBool("log.log-to-file"),
Path: viper.GetString("log.path"),
},
Aws: AwsConfig{
S3Bucket: viper.GetString("aws.s3-bucket"),
},
Cache: CacheConfig{
Server: viper.GetString("cache.server"),
Port: viper.GetInt("cache.port"),
DB: viper.GetInt("cache.db"),
Pass: viper.GetString("cache.pass"),
Prefix: viper.GetString("cache.prefix"),
DefaultExpiration: viper.GetDuration("cache.default-expiration"),
},
Lyft: LyftConfig{
Client: viper.GetString("lyft.key"),
Secret: viper.GetString("lyft.secret"),
RefreshToken: viper.GetString("lyft.token"),
},
LyftProd: LyftProdConfig{
Lyft: LyftConfig{
Client: viper.GetString("lyft-prod.key"),
Secret: viper.GetString("lyft-prod.secret"),
RefreshToken: viper.GetString("lyft-prod.token"),
},
UserUUID: viper.GetString("lyft-prod.user-uuid"),
},
Twilio: TwilioConfig{
Account: viper.GetString("twilio.account"),
Token: viper.GetString("twilio.token"),
Sender: viper.GetString("twilio.sender"),
TwiMLSID: viper.GetString("twilio.twiml-sid"),
},
BXE: BXEConfig{
URL: viper.GetString("bxe.url"),
APIKey: viper.GetString("bxe.key"),
Secret: viper.GetString("bxe.secret"),
},
Blue365: Blue365Config{
URL: viper.GetString("blue365.url"),
APIKey: viper.GetString("blue365.key"),
Secret: viper.GetString("blue365.secret"),
},
Email: EmailConfig{
Server: viper.GetString("email.server"),
Port: viper.GetInt("email.port"),
User: viper.GetString("email.user"),
Pass: viper.GetString("email.pass"),
Sender: viper.GetString("email.sender"),
},
GoogleShortener: GoogleShortenerConfig{
APIKey: viper.GetString("google-shortener.api-key"),
ClientID: viper.GetString("google-shortener.client-id"),
SecretKey: viper.GetString("google-shortener.secret-key"),
},
}, nil
}
func setup() {
viper.SetEnvPrefix("api")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
viper.SetConfigName("config")
viper.AddConfigPath(".")
}

Some files were not shown because too many files have changed in this diff Show More