5 Commits

Author SHA1 Message Date
GotPPay
52656e0420 remove debugging response 2018-05-18 17:45:47 +02:00
GotPPay
c6606a98dd custom elig. api error msg ; first check elig. then create user 2018-05-18 10:46:47 +02:00
Senad Uka
2e5444bed8 Upstream sync 2018-05-16 18:30:59 +02:00
Senad Uka
4852a5586c upstream sync 2018-05-11 09:07:54 +02:00
Senad Uka
50a6362b67 upstream sync 2018-05-03 07:55:09 +02:00
31 changed files with 3046 additions and 52 deletions

View File

@@ -149,3 +149,23 @@ func (s *userService) GetContactType() (retVal []viewmodel.ContactType, err erro
return s.mapEntity.User.ToContactTypeModelSlice(entity), nil
}
func (s *userService) SaveContact(contact viewmodel.Contact) (retVal viewmodel.Contact, err error) {
entity := s.mapEntity.User.ToContactEntity(contact)
entity, err = s.svc.Users.SaveContact(entity)
if err != nil {
return retVal, errors.Wrap(err)
}
return s.mapEntity.User.ToContactModel(entity), err
}
func (s *userService) RemoveContact(contact viewmodel.Contact) (retVal viewmodel.Contact, err error) {
entity := s.mapEntity.User.ToContactEntity(contact)
entity, err = s.svc.Users.RemoveContact(entity)
if err != nil {
return retVal, errors.Wrap(err)
}
return s.mapEntity.User.ToContactModel(entity), err
}

View File

@@ -158,8 +158,11 @@ func (mapping *userMapping) ToContactTypeModelSlice(list []entity.ContactType) (
// 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,
ID: item.UUID,
User: mapping.ToUserModel(item.User),
Author: mapping.ToUserModel(item.Author),
Type: mapping.ToContactTypeModel(item.Type),
Value: item.Value,
}
}
@@ -177,8 +180,11 @@ func (mapping *userMapping) ToContactModelSlice(list []entity.ContactInfo) (retV
// 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,
UUID: item.ID,
User: mapping.ToUserEntity(item.User),
Author: mapping.ToUserEntity(item.Author),
Type: mapping.ToContactTypeEntity(item.Type),
Value: item.Value,
}
}

View File

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

View File

@@ -5,7 +5,9 @@ import (
"crypto/md5"
"encoding/hex"
"encoding/xml"
"errors"
"fmt"
"html"
"io/ioutil"
"net/http"
"strings"
@@ -72,14 +74,37 @@ func (s bxeService) GetPayerDetails(subscriberID string) ([]bcbsimodel.EntityRes
return response, nil
}
func (s bxeService) CheckEligibility(eligibility viewmodel.Eligibility) (bcbsimodel.MemberEligibilityResponse, error) {
payer, err := s.GetPayerDetails(eligibility.Subscriber.SubscriberID)
func (s bxeService) Get271(eligibility viewmodel.Eligibility) (bcbsimodel.Interchange271, error) {
resp, err := s.CheckEligibility(eligibility)
if err != nil {
return bcbsimodel.MemberEligibilityResponse{}, err
return bcbsimodel.Interchange271{}, err
}
eligibility.Payer.PayerID = payer[0].ID
eligibility.Payer.PayerName = payer[0].Name
if resp.QueryResult.HIPPA271.T271 != "" {
xmlString := html.UnescapeString(resp.QueryResult.HIPPA271.T271)
xmlReader := strings.NewReader(xmlString)
var f bcbsimodel.Interchange271
err = xml.NewDecoder(xmlReader).Decode(&f)
if err != nil {
fmt.Println("Error to unmarshal: ", err.Error())
return bcbsimodel.Interchange271{}, err
}
return f, nil
} else {
return bcbsimodel.Interchange271{}, errors.New("No 271 response")
}
}
func (s bxeService) CheckEligibility(eligibility viewmodel.Eligibility) (bcbsimodel.MemberEligibilityResponse, error) {
// payer, err := s.GetPayerDetails(eligibility.Subscriber.SubscriberID)
// if err != nil {
// return bcbsimodel.MemberEligibilityResponse{}, err
// }
eligibility.Payer.PayerID = "621"
eligibility.Payer.PayerName = "blue_cross_blue_shield_il"
envelope := bcbsimodel.GetEnvelope(eligibility)
apiKey := s.cfg.BXE.APIKey
@@ -99,14 +124,14 @@ func (s bxeService) CheckEligibility(eligibility viewmodel.Eligibility) (bcbsimo
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error WebService: ", err)
fmt.Println("Error WebService Request: ", err)
return bcbsimodel.MemberEligibilityResponse{}, err
}
defer resp.Body.Close()
bReturn, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error WebService: ", err)
fmt.Println("Error WebService getting byte: ", err)
return bcbsimodel.MemberEligibilityResponse{}, err
}
@@ -118,7 +143,7 @@ func (s bxeService) CheckEligibility(eligibility viewmodel.Eligibility) (bcbsimo
var result bcbsimodel.EnvelopeResponse
err = xml.Unmarshal([]byte(sResponse), &result)
if err != nil {
fmt.Println("Error WebService: ", err)
fmt.Println("Error WebService getting object: ", err)
return bcbsimodel.MemberEligibilityResponse{}, err
}

View File

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

View File

@@ -15,6 +15,7 @@ type WebhookResponse struct {
//RideRequest has the data to dispatch a ride
type RideRequest struct {
UserUUID string `json:"user_uuid,omitempty"`
UserConsent bool `json:"user_consent,omitempty"`
Status string `json:"status,omitempty"`
RideID string `json:"ride_id,omitempty"`
RideType string `json:"ride_type,omitempty"`
@@ -158,4 +159,4 @@ type RideRoute struct {
Duration int64 `json:"duration,omitempty"`
ETA int64 `json:"eta,omitempty"`
Bearing int64 `json:"bearing,omitempty"`
}
}

View File

@@ -26,8 +26,11 @@ type User struct {
}
type Contact struct {
Type ContactType `json:"type,omitempty"`
Value string `json:"contact,omitempty"`
ID string `json:"id,omitempty"`
User User `json:"-"`
Type ContactType `json:"type,omitempty"`
Value string `json:"contact,omitempty"`
Author User `json:"-"`
}
type ContactType struct {

View File

@@ -79,18 +79,23 @@ p, *, *, *, *, *, *, /v1/nemt/organization/type, GET
p, AD, *, *, *, *, *, /v1/nemt/organization/*, GET
p, AD, *, *, *, *, *, /v1/nemt/organization/*, POST
p, AD, *, *, *, *, *, /v1/nemt/organization/*, PUT
p, AD, *, *, *, *, *, /v1/nemt/organization/*, DELETE
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, GET
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, POST
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, PUT
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, DELETE
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, GET
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, POST
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, PUT
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, DELETE
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, GET
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, POST
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, PUT
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, DELETE
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, GET
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, POST
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, PUT
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, DELETE
p, SPT, *, programsupport, *, *, *, /v1/nemt/organization/*, GET
p, SP, *, provider, *, *, *, /v1/nemt/organization, GET
p, SP, *, plan, *, *, *, /v1/nemt/organization, GET
@@ -108,4 +113,3 @@ p, BCBSIAD, *, bcbsi, *, *, *, /v1/nemt/eligibility, POST
p, BDCAD, *, techsupport, *, *, *, /v1/nemt/eligibility, POST
p, PLANAD, *, plan, *, *, *, /v1/nemt/eligibility, POST
p, AD, *, *, *, *, *, /v1/nemt/eligibility, POST
1 p AD * * * * * * *
79 p AD * * * * * /v1/nemt/organization/* GET
80 p AD * * * * * /v1/nemt/organization/* POST
81 p AD * * * * * /v1/nemt/organization/* PUT
82 p AD * * * * * /v1/nemt/organization/* DELETE
83 p SCHDAD * * * [equal*] * /v1/nemt/organization/* GET
84 p SCHDAD * * * [equal*] * /v1/nemt/organization/* POST
85 p SCHDAD * * * [equal*] * /v1/nemt/organization/* PUT
86 p SCHDAD * * * [equal*] * /v1/nemt/organization/* DELETE
87 p PLANAD * * * [equal*] * /v1/nemt/organization/* GET
88 p PLANAD * * * [equal*] * /v1/nemt/organization/* POST
89 p PLANAD * * * [equal*] * /v1/nemt/organization/* PUT
90 p PLANAD * * * [equal*] * /v1/nemt/organization/* DELETE
91 p BDCAD * * * * * /v1/nemt/organization/* GET
92 p BDCAD * * * * * /v1/nemt/organization/* POST
93 p BDCAD * * * * * /v1/nemt/organization/* PUT
94 p BDCAD * * * * * /v1/nemt/organization/* DELETE
95 p BCBSIAD * * * * * /v1/nemt/organization/* GET
96 p BCBSIAD * * * * * /v1/nemt/organization/* POST
97 p BCBSIAD * * * * * /v1/nemt/organization/* PUT
98 p BCBSIAD * * * * * /v1/nemt/organization/* DELETE
99 p SPT * programsupport * * * /v1/nemt/organization/* GET
100 p SP * provider * * * /v1/nemt/organization GET
101 p SP * plan * * * /v1/nemt/organization GET
113 p BDCAD * techsupport * * * /v1/nemt/eligibility POST
114 p PLANAD * plan * * * /v1/nemt/eligibility POST
115 p AD * * * * * /v1/nemt/eligibility POST

View File

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

View File

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

View File

@@ -294,7 +294,7 @@ func (c *organizationRepo) GetAllTypes() ([]entity.OrganizationType, error) {
}
func (c *organizationRepo) GetTypeByKey(key string) (entity.OrganizationType, error) {
return c.parseTypeEntity(c.conn.QueryRow(c.getTypeQuery()+" WHERE b.organization_type_key=?", key))
return c.parseTypeEntity(c.conn.QueryRow(c.getTypeQuery()+" WHERE organization_type_key=? ", key))
}
func (c *organizationRepo) GetByType(organizationTypeKey string, user entity.User) ([]entity.Organization, error) {

View File

@@ -63,7 +63,8 @@ func (c *userRepo) GetContacts(userID int64) ([]entity.ContactInfo, error) {
a.user_id,
b.contact_type_id,
b.key contact_type_key,
b.name contact_type_name
b.name contact_type_name,
a.contact_uuid
FROM tab_contact a
INNER JOIN tab_contact_type b
ON a.contact_type_id = b.contact_type_id
@@ -79,7 +80,7 @@ func (c *userRepo) GetContacts(userID int64) ([]entity.ContactInfo, error) {
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)
err = rows.Scan(&contact.ID, &contact.Value, &contact.User.ID, &contact.Type.ID, &contact.Type.Key, &contact.Type.Value, &contact.UUID)
if err != nil {
return nil, err
}
@@ -354,9 +355,11 @@ func (c *userRepo) Create(user entity.User) (retVal entity.User, err error) {
if retVal.Email != "" {
contact := entity.ContactInfo{
Type: entity.ContactType{Key: "email"},
Value: retVal.Email,
UserID: retVal.ID,
Type: entity.ContactType{Key: "email"},
Value: retVal.Email,
User: entity.User{
ID: retVal.ID,
},
}
contact, err = c.addContactInfo(contact)
@@ -367,9 +370,11 @@ func (c *userRepo) Create(user entity.User) (retVal entity.User, err error) {
if retVal.PhoneNumber != "" {
contact := entity.ContactInfo{
Type: entity.ContactType{Key: "phone"},
Value: retVal.PhoneNumber,
UserID: retVal.ID,
Type: entity.ContactType{Key: "phone"},
Value: retVal.PhoneNumber,
User: entity.User{
ID: retVal.ID,
},
}
contact, err = c.addContactInfo(contact)
@@ -387,19 +392,10 @@ func (c *userRepo) SaveContact(contact entity.ContactInfo) (entity.ContactInfo,
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;`
query = `DELETE FROM tab_contact WHERE contact_uuid = ?;`
)
result, err := c.conn.Exec(query, contact.UserID, contact.Value, contact.UserID, contact.Value, contact.Type.Key)
result, err := c.conn.Exec(query, contact.UUID)
if err != nil {
return contact, err
}
@@ -415,8 +411,8 @@ func (c *userRepo) RemoveContact(contact entity.ContactInfo) (entity.ContactInfo
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
query = `INSERT INTO tab_contact(contact_type_id, user_id, contact, contact_uuid)
SELECT a.contact_type_id, ? user_id, ? contact, ? contact_uuid
FROM
tab_contact_type a
LEFT JOIN tab_contact b
@@ -427,7 +423,13 @@ func (c *userRepo) addContactInfo(contact entity.ContactInfo) (entity.ContactInf
AND b.contact_id IS NULL;`
)
result, err := c.conn.Exec(query, contact.UserID, contact.Value, contact.UserID, contact.Value, contact.Type.Key)
sUUID, err := uuid.NewV4()
if err != nil {
return contact, err
}
contact.UUID = sUUID.String()
result, err := c.conn.Exec(query, contact.User.ID, contact.Value, contact.UUID, contact.User.ID, contact.Value, contact.Type.Key)
if err != nil {
return contact, err
}

View File

@@ -27,6 +27,8 @@ type UserRepo interface {
GetAddressByUUID(addressUUID string) (entity.Address, error)
GetContactType() (retVal []entity.ContactType, err error)
RemoveAddress(addressUUID string) error
SaveContact(contact entity.ContactInfo) (entity.ContactInfo, error)
RemoveContact(contact entity.ContactInfo) (entity.ContactInfo, error)
}
// RideRepo defines the data set for Rides

View File

@@ -34,8 +34,10 @@ type User struct {
type ContactInfo struct {
ID int64 `db:"contact_id" json:"contact_id"`
UUID string `db:"contact_uuid" json:"contact_uuid"`
Type ContactType `db:"contact_type" json:"contact_type"`
UserID int64 `db:"user_id" json:"-"`
User User `db:"user" json:"-"`
Author User `db:"author" json:"-"`
Value string `db:"value" json:"value"`
}

View File

@@ -82,6 +82,26 @@ func (s *userService) SaveAddress(address entity.Address) (entity.Address, error
return s.svc.db.Users().SaveAddress(address)
}
func (s *userService) SaveContact(contact entity.ContactInfo) (entity.ContactInfo, error) {
user, err := s.svc.db.Users().GetByUUID(contact.User.UUID, "")
if err != nil {
return entity.ContactInfo{}, nil
}
contact.User = user
return s.svc.db.Users().SaveContact(contact)
}
func (s *userService) RemoveContact(contact entity.ContactInfo) (entity.ContactInfo, error) {
user, err := s.svc.db.Users().GetByUUID(contact.User.UUID, "")
if err != nil {
return entity.ContactInfo{}, nil
}
contact.User = user
return s.svc.db.Users().RemoveContact(contact)
}
// GetAddressByUUID returns a list of users by profile
func (s *userService) GetAddressByUUID(addressUUID string) (entity.Address, error) {
return s.svc.db.Users().GetAddressByUUID(addressUUID)

1602
returnExample.xml Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,10 @@
package eligibilityroute
import (
"encoding/xml"
"fmt"
"html"
"strings"
"sync"
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
@@ -42,8 +46,22 @@ func (c *controller) handleEligibility(ctx echo.Context) error {
ret, err := c.bcbsi.BXE.CheckEligibility(eligibility)
if err != nil {
fmt.Println("Error Here: ", err.Error())
return routeutils.HandleAPIError(ctx, err)
}
return routeutils.ResponseAPIOK(ctx, ret)
if ret.QueryResult.HIPPA271.T271 != "" {
xmlString := html.UnescapeString(ret.QueryResult.HIPPA271.T271)
xmlReader := strings.NewReader(xmlString)
var f viewmodel.Interchange271
err = xml.NewDecoder(xmlReader).Decode(&f)
if err != nil {
fmt.Println("Error to unmarshal: ", err.Error())
}
return ctx.JSON(200, f)
} else {
return routeutils.ResponseAPIOK(ctx, ret)
}
}

View File

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

View File

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

View File

@@ -15,6 +15,7 @@ import (
"bitbucket.org/nemt/nemt-portal-api/infra/auth"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
"bitbucket.org/nemt/nemt-portal-api/server/validation"
"github.com/labstack/echo"
uuid "github.com/satori/go.uuid"
"google.golang.org/api/googleapi/transport"
@@ -231,6 +232,11 @@ func (c *controller) handle(ctx echo.Context) error {
return routeutils.ResponseAPIValidationError(ctx, "User not found")
}
//Validate ride request
if validationErrors := validation.ValidateRide(&requestRide, &user) ; len(validationErrors) > 0 {
return routeutils.ResponseAPICustomValidationError(ctx, "ride validation failed", validationErrors)
}
createdUser, err := auth.GetUserDetail(ctx, c.cfg)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
@@ -869,4 +875,4 @@ func (c *controller) handleReady(ctx echo.Context) error {
}()
return routeutils.ResponseAPIOK(ctx, nextRide)
}
}

View File

@@ -8,13 +8,18 @@ import (
"time"
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
"bitbucket.org/nemt/nemt-portal-api/application/third/eligibility/bcbsi"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/domain"
"bitbucket.org/nemt/nemt-portal-api/infra/auth"
"bitbucket.org/nemt/nemt-portal-api/infra/cache"
"bitbucket.org/nemt/nemt-portal-api/infra/config"
"bitbucket.org/nemt/nemt-portal-api/server/authorization"
"bitbucket.org/nemt/nemt-portal-api/server/validation"
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
"github.com/labstack/echo"
"golang.org/x/net/context"
"googlemaps.github.io/maps"
)
var (
@@ -23,15 +28,17 @@ var (
)
type controller struct {
svc *applicationservice.Service
cfg *config.Config
svc *applicationservice.Service
cfg *config.Config
bcbsi *bcbsi.Service
}
func controllerInstance(svc *applicationservice.Service, cfg *config.Config) *controller {
once.Do(func() {
instance = &controller{
svc: svc,
cfg: cfg,
svc: svc,
cfg: cfg,
bcbsi: bcbsi.New(cfg),
}
})
return instance
@@ -127,6 +134,62 @@ func (c *controller) handleRemoveAddress(ctx echo.Context) error {
return routeutils.ResponseNoContent(ctx, addressID)
}
func (c *controller) handlePortalContact(ctx echo.Context) error {
userID, err := routeutils.GetAndValidateStringParam(ctx, "user_uuid", "mandatory field")
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
item, err := c.svc.Users.GetByUUID(userID, "")
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
createdUser, err := auth.GetUserDetail(ctx, c.cfg)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if item.ID == "" {
return routeutils.ResponseAPIValidationError(ctx, "User not found")
} else {
var Contact viewmodel.Contact
if err := ctx.Bind(&Contact); err != nil {
return routeutils.HandleAPIError(ctx, err)
}
Contact.User = item
Contact.Author = createdUser
Contact, err = c.svc.Users.SaveContact(Contact)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
// Contact.User, err = c.svc.Users.GetByUUID(userID, "")
// if err != nil {
// return routeutils.HandleAPIError(ctx, err)
// }
return routeutils.ResponseAPIOK(ctx, Contact)
}
}
func (c *controller) handleRemoveContact(ctx echo.Context) error {
contactUUID, err := routeutils.GetAndValidateStringParam(ctx, "contact_uuid", "mandatory field")
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
contact := viewmodel.Contact{
ID: contactUUID,
}
contact, err = c.svc.Users.RemoveContact(contact)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
return routeutils.ResponseNoContent(ctx, contact)
}
func (c *controller) handleMemberAddress(ctx echo.Context) error {
userID, err := routeutils.GetAndValidateStringParam(ctx, "user_uuid", "mandatory field")
if err != nil {
@@ -269,6 +332,7 @@ func (c *controller) handleGetPortal(ctx echo.Context) error {
}
func (c *controller) handleMember(ctx echo.Context) error {
fmt.Println("\n\nHandle member\n\n")
var user viewmodel.User
if err := ctx.Bind(&user); err != nil {
return routeutils.HandleAPIError(ctx, err)
@@ -319,6 +383,66 @@ func (c *controller) handleMember(ctx echo.Context) error {
}
user.Profiles = append(user.Profiles, profile)
eligibility := viewmodel.Eligibility{}
eligibility.Provider.ProviderNPI = "1699849786"
eligibility.Provider.ProviderName = "LITHOLINK CORPORATION"
eligibility.TrackingID = user.ID
eligibility.Subscriber.SubscriberID = *user.Member
eligibility.Subscriber.PatientType = "S"
eligibility.Subscriber.Name.First = user.First
eligibility.Subscriber.Name.Last = user.Last
eligibility.Subscriber.DemographicInfo.DateOfBirth = *user.BirthDate
eligibility.Subscriber.DemographicInfo.Gender = *user.Gender
eligibility.ServiceInfo.DateOfService = time.Now()
eligibility.ServiceInfo.ServiceTypeCodes = []string{"30"}
fmt.Println("\n\nGet271\n\n")
resp, err := c.bcbsi.BXE.Get271(eligibility)
if err != nil {
fmt.Println("Eligibility Not Found or Error: ", err.Error())
return routeutils.ResponseAPINotEligibleError(ctx)
}
address := viewmodel.Address{}
header := resp.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N3_0950
body := resp.Division.HealthCareEligibilityResponse.LoopHL0030[0].HL_0460[0].HL_0890[0].NM1_0920[0].N4_0960
address.AddressTypeName = "Home"
address.AddressType = "home"
address.Name = fmt.Sprintf("%s, %s", header.N301, body.N401)
address.Address = fmt.Sprintf("%s, %s", header.N301, body.N401)
address.CreatedUserUUID = authUser.ID
address.User = user
googleMapsAPI, err := maps.NewClient(maps.WithClientIDAndSignature("gme-bluecrossandblue1", "msqgD-jdqCyR0M_1u5C1HION5iI="))
if err != nil {
fmt.Println("Error to instantiate googles api: ", err.Error())
return routeutils.ResponseAPINotEligibleError(ctx)
}
r := &maps.GeocodingRequest{
Address: address.Address + " " + body.N402 + ", " + body.N403,
}
result, err := googleMapsAPI.Geocode(context.Background(), r)
if err != nil {
fmt.Println("Error to instantiate googles api: ", err.Error())
return routeutils.ResponseAPINotEligibleError(ctx)
}
if len(result) > 0 {
address.Latitude = result[0].Geometry.Location.Lat
address.Longitude = result[0].Geometry.Location.Lng
_, err := c.svc.Users.SaveAddress(address)
if err != nil {
fmt.Println("Error to save address: ", err.Error())
return routeutils.ResponseAPINotEligibleError(ctx)
}
}
//Get ZIP code and check if it is participating
user, err = c.svc.Users.Create(user, authUser)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
@@ -389,6 +513,10 @@ func (c *controller) handlePortal(ctx echo.Context) error {
return routeutils.HandleAPIError(ctx, err)
}
if !authorization.CanCreateUser(authUser, user) {
return routeutils.ResponseAPIAuthorizationError(ctx)
}
if len(user.Profiles) == 0 {
return routeutils.ResponseAPIAuthError(ctx, "profile is required", false)
}
@@ -411,6 +539,10 @@ func (c *controller) handlePortal(ctx echo.Context) error {
}
user.Pass = string(pass)
if passwordValidationErrors := validation.ValidatePassword(&user) ; len(passwordValidationErrors) > 0 {
return routeutils.ResponseAPICustomValidationError(ctx, "Password not strong enough", passwordValidationErrors)
}
if len(user.Name) == 0 && len(user.First) == 0 && len(user.Last) == 0 {
return routeutils.ResponseAPIAuthError(ctx, "name is required", false)
}

View File

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

View File

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

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

@@ -0,0 +1,183 @@
package validation
import (
"time"
"fmt"
"strconv"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/infra/errors"
)
const (
tripTypeFromVisit = "From Visit"
tripTypeToVisit = "To Visit"
tripTypeFromVisitWillCall = "From Visit / Will Call"
tripTypeRoundTrip = "Round Trip"
tripTypeRountTripWillCall = "Round Trip / Will Call"
)
const (
loadingTime = 30 //in minutes
minimumLoadTime = 30 //in minutes
minimumPickupTime = 10 //in minutes
)
const (
hoursInDay = 24
hoursIn180Days = 24*180
time8Hours = 8
time10Minutes = 10
)
func ValidateRide(requestRide *viewmodel.RideRequest, user *viewmodel.User) []errors.ValidationError {
var result []errors.ValidationError
//Step #1 validation
if userID, err := strconv.Atoi(user.ID) ; err != nil || userID <= 0 {
result = append(result, errors.ValidationError{Field : "user_uuid", Message : "Step #1 - Choose a Member" })
}
if originID, err := strconv.Atoi(requestRide.Origin.ID) ; err != nil || originID <= 0 {
result = append (result, errors.ValidationError{Field : "origin.id", Message : "Step #1 - Choose a Pickup Address"})
}
if !requestRide.UserConsent {
result = append (result, errors.ValidationError{Field : "user_consent", Message : "Step #1 - Member must consent to Terms of Use"})
}
//Step #2 validation
if destinationID, err := strconv.Atoi(requestRide.Destination.ID) ; err!= nil || destinationID <= 0 {
result = append (result, errors.ValidationError{Field : "destination.id", Message : "Step #2 - Choose a Provider"})
}
//Step #3 validation
isVisitDayToday := requestRide.VisitDate.Day() == time.Now().Day() && requestRide.VisitDate.Month() == time.Now().Month() && requestRide.VisitDate.Year() == time.Now().Year()
before8Hours := time.Now().Add(-time.Hour*time8Hours)
if requestRide.VisitDate == nil {
result = append (result, errors.ValidationError{Field : "visit_date", Message : "Step #3 - Choose a Date for the Visit"})
}else{
dayBeforeToday := time.Now().Add(-time.Hour*hoursInDay)
if requestRide.VisitDate.Before(dayBeforeToday) {
result = append (result, errors.ValidationError{Field : "visit_date", Message : "Step #3 - Visit cannot occur more than one day before today"})
}
dayAfter180Days := time.Now().Add(time.Hour*hoursIn180Days)
if requestRide.VisitDate.After(dayAfter180Days) {
result = append (result, errors.ValidationError{Field : "visit_date", Message : "Step #3 - Visit cannot occur more than 180 days after today"})
}
if requestRide.VisitTime == nil {
result = append (result, errors.ValidationError{Field : "visit_time", Message : "Step #3 - Choose a Time for the Visit"})
}else{
if isVisitDayToday && requestRide.VisitTime.Before(before8Hours) {
result = append (result, errors.ValidationError{Field : "visit_time", Message : "Step #3 - Visit is more than 8 hours in the past"})
}
}
}
//Step #4 validation
if requestRide.TripType.Value == "" {
result = append (result, errors.ValidationError{Field : "trip_type.value", Message : "Step #4 - Choose a Trip Type"})
}
timeWithDurationAndLoadingTime := requestRide.VisitTime.Add(-time.Duration(requestRide.Duration)*time.Second).Add(-loadingTime*time.Minute)
after10Minutes := time.Now().Add(time.Minute*time10Minutes)
switch requestRide.TripType.Value {
case tripTypeToVisit:
if requestRide.PickupTime == nil {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Choose a Pickup Time"})
}else{
if requestRide.PickupTime.After(*requestRide.VisitTime) {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Pickup Time must occur before Visit Time"})
}
if requestRide.PickupTime.After(timeWithDurationAndLoadingTime) {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Pickup Time less than required time before Visit Time"})
}
if isVisitDayToday && requestRide.PickupTime.Before(before8Hours) {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Visit cannot occour in the past"})
}
}
case tripTypeFromVisit :
if requestRide.PickupTime == nil {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Choose a Pickup Time"})
}else{
timeWithMinimumPickupTime := time.Now().Add(minimumPickupTime*time.Minute)
if isVisitDayToday && requestRide.PickupTime.Before(timeWithMinimumPickupTime) {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : fmt.Sprint("Step #4 - Time must be more than %d minutes from now",minimumPickupTime)})
}
if requestRide.PickupTime.Before(*requestRide.VisitTime) {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Pickup Time less than required time after Visit Time"})
}
timeWithMinimumLoadTime := time.Now().Add(minimumLoadTime*time.Minute)
if requestRide.PickupTime.Before(timeWithMinimumLoadTime) {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Pickup Time less than Minimum Load Time before Visit Time"})
}
}
case tripTypeFromVisitWillCall:
//no special validation for this case
case tripTypeRoundTrip:
if requestRide.PickupTime == nil {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Choose a Pickup Time"})
}else{
if requestRide.PickupTime.After(*requestRide.VisitTime) {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Pickup Time must occur before Visit Time"})
}
if requestRide.PickupTime.After(timeWithDurationAndLoadingTime) {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Pickup Time less than required time before Visit Time"})
}
if isVisitDayToday && requestRide.PickupTime.Before(after10Minutes) {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Pickup Time must be at least 10 minutes from now"})
}
}
if requestRide.ReturnTime == nil {
result = append (result, errors.ValidationError{Field : "return_time", Message : "Step #4 - Choose a Pickup Time"})
}else{
if isVisitDayToday {
if requestRide.ReturnTime.Before(before8Hours) {
result = append (result, errors.ValidationError{Field : "return_time", Message : "Step #4 - Return Time is more than 8 hours after Visit Time"})
}
if requestRide.ReturnTime.Before(after10Minutes) {
result = append (result, errors.ValidationError{Field : "return_time", Message : "Step #4 - Return Time must be at least 10 minutes from now"})
}
}
}
case tripTypeRountTripWillCall:
if requestRide.PickupTime == nil {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Choose a Pickup Time"})
}else{
if requestRide.PickupTime.After(*requestRide.VisitTime) {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Pickup Time must occur before Visit Time"})
}
if requestRide.PickupTime.After(timeWithDurationAndLoadingTime) {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Pickup Time less than required time after Visit Time"})
}
if isVisitDayToday && requestRide.PickupTime.Before(before8Hours) {
result = append (result, errors.ValidationError{Field : "pickup_time", Message : "Step #4 - Visit cannot occur in the past "})
}
}
}
return result
}

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

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