Upstream sync

This commit is contained in:
Senad Uka
2018-05-22 12:40:22 +02:00
parent 39c614fb98
commit 6e903b4d57
31 changed files with 948 additions and 83 deletions

View File

@@ -1,12 +1,19 @@
package selfregisterroute
import (
"fmt"
"sync"
b64 "encoding/base64"
"bitbucket.org/nemt/nemt-portal-api/application/applicationservice"
"bitbucket.org/nemt/nemt-portal-api/application/third/eligibility/bcbsi"
"bitbucket.org/nemt/nemt-portal-api/application/third/npd/npdmodel"
"bitbucket.org/nemt/nemt-portal-api/application/viewmodel"
"bitbucket.org/nemt/nemt-portal-api/infra/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"
)
@@ -33,6 +40,104 @@ func controllerInstance(svc *applicationservice.Service, cfg *config.Config) *co
}
func (c *controller) handle(ctx echo.Context) error {
var user viewmodel.User
if err := ctx.Bind(&user); err != nil {
return routeutils.HandleAPIError(ctx, err)
}
return routeutils.ResponseAPIOK(ctx, "OK")
authUser, err := auth.GetUserDetail(ctx, c.cfg)
if err != nil {
return routeutils.HandleAPIError(ctx, err)
}
if user.PhoneNumber == nil || len(*user.PhoneNumber) == 0 {
return routeutils.ResponseAPIValidationError(ctx, "phonenumber is required")
}
if user.Email == nil || len(*user.Email) == 0 {
return routeutils.ResponseAPIValidationError(ctx, "email is required")
}
if len(user.Pass) == 0 {
return routeutils.ResponseAPIValidationError(ctx, "password is required")
}
pass, err := b64.StdEncoding.DecodeString(user.Pass)
if err != nil {
return routeutils.ResponseAPIValidationError(ctx, "Invalid password")
}
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.ResponseAPIValidationError(ctx, "name is required")
}
if len(user.First) != 0 && len(user.Last) != 0 {
user.Name = fmt.Sprintf("%s %s", user.First, user.Last)
}
if len(user.Provider.InternalID) == 0 || len(user.Provider.InternalID) > 10 {
return routeutils.ResponseAPIValidationError(ctx, "Provider NPI is invalid")
}
if len(user.Provider.OrganizatioName) == 0 {
return routeutils.ResponseAPIValidationError(ctx, "Provider Organization Name is invalid")
}
provider, err := c.svc.Provider.GetByNPI(user.Provider.InternalID, authUser)
if err != nil {
fmt.Println("Error to create organization", err)
return routeutils.HandleAPIError(ctx, err)
}
var organization viewmodel.Organization
if provider.ProviderUUID == "" {
org := viewmodel.Organization{
Author: authUser,
LastEditor: authUser,
Name: user.Provider.OrganizatioName,
Type: viewmodel.OrganizationType{
Key: "provider",
Name: "Provider",
},
Reference: npdmodel.ProviderResponse{
OrgName: user.Provider.OrganizatioName,
FivePartKeyGroups: []npdmodel.PartKeyGroup{
npdmodel.PartKeyGroup{
ProviderNum: user.Provider.InternalID,
},
},
},
}
organization, err = c.svc.Organization.AddOrganization(org, authUser)
if err != nil {
fmt.Println("Error to create organization", err)
return routeutils.HandleAPIError(ctx, err)
}
if organization.UUID == "" {
return routeutils.ResponseAPIValidationError(ctx, "Error to create organization")
}
} else {
organization = provider.Organization
}
user.Organizations = []viewmodel.Organization{organization}
user.Profiles = []viewmodel.Profile{viewmodel.Profile{
Name: "Visit Reporter",
Key: "VIRPT",
Organization: organization,
}}
user, err = c.svc.Users.Create(user, authUser)
if err != nil {
fmt.Println("Error to create user", err)
return routeutils.HandleAPIError(ctx, err)
}
return routeutils.ResponseAPIOK(ctx, user)
}

View File

@@ -345,6 +345,11 @@ func (c *controller) handleMember(ctx echo.Context) error {
return routeutils.HandleAPIError(ctx, err)
}
//Validate member
if validationErrors := validation.ValidateEligibility(&user) ; len(validationErrors) > 0 {
return routeutils.ResponseAPICustomValidationError(ctx, "eligibility validation failed", validationErrors)
}
authUser, err := auth.GetUserDetail(ctx, c.cfg)
if err != nil {
return routeutils.HandleAPIError(ctx, err)

View File

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

View File

@@ -39,8 +39,10 @@ func ValidatePassword(user *viewmodel.User) []errors.ValidationError {
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."})
if len(userOrganizationName) > 0 {
if strings.Contains(user.Pass, userOrganizationName) {
result = append(result, errors.ValidationError{Field: "password", Message: "Password cannot include your Organization Name."})
}
}
containsUpperCaseLetter := false