Compare commits
2 Commits
sql_query_
...
users-crea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffab9fe30f | ||
|
|
4852a5586c |
@@ -149,3 +149,23 @@ func (s *userService) GetContactType() (retVal []viewmodel.ContactType, err erro
|
|||||||
|
|
||||||
return s.mapEntity.User.ToContactTypeModelSlice(entity), nil
|
return s.mapEntity.User.ToContactTypeModelSlice(entity), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *userService) SaveContact(contact viewmodel.Contact) (retVal viewmodel.Contact, err error) {
|
||||||
|
entity := s.mapEntity.User.ToContactEntity(contact)
|
||||||
|
entity, err = s.svc.Users.SaveContact(entity)
|
||||||
|
if err != nil {
|
||||||
|
return retVal, errors.Wrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.mapEntity.User.ToContactModel(entity), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *userService) RemoveContact(contact viewmodel.Contact) (retVal viewmodel.Contact, err error) {
|
||||||
|
entity := s.mapEntity.User.ToContactEntity(contact)
|
||||||
|
entity, err = s.svc.Users.RemoveContact(entity)
|
||||||
|
if err != nil {
|
||||||
|
return retVal, errors.Wrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.mapEntity.User.ToContactModel(entity), err
|
||||||
|
}
|
||||||
|
|||||||
@@ -158,8 +158,11 @@ func (mapping *userMapping) ToContactTypeModelSlice(list []entity.ContactType) (
|
|||||||
// ToContactModel maps a Contact entity to Contact view model
|
// ToContactModel maps a Contact entity to Contact view model
|
||||||
func (mapping *userMapping) ToContactModel(item entity.ContactInfo) viewmodel.Contact {
|
func (mapping *userMapping) ToContactModel(item entity.ContactInfo) viewmodel.Contact {
|
||||||
return viewmodel.Contact{
|
return viewmodel.Contact{
|
||||||
Type: mapping.ToContactTypeModel(item.Type),
|
ID: item.UUID,
|
||||||
Value: item.Value,
|
User: mapping.ToUserModel(item.User),
|
||||||
|
Author: mapping.ToUserModel(item.Author),
|
||||||
|
Type: mapping.ToContactTypeModel(item.Type),
|
||||||
|
Value: item.Value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,8 +180,11 @@ func (mapping *userMapping) ToContactModelSlice(list []entity.ContactInfo) (retV
|
|||||||
// ToContactEntity maps a Contact entity to Contact view model
|
// ToContactEntity maps a Contact entity to Contact view model
|
||||||
func (mapping *userMapping) ToContactEntity(item viewmodel.Contact) entity.ContactInfo {
|
func (mapping *userMapping) ToContactEntity(item viewmodel.Contact) entity.ContactInfo {
|
||||||
return entity.ContactInfo{
|
return entity.ContactInfo{
|
||||||
Type: mapping.ToContactTypeEntity(item.Type),
|
UUID: item.ID,
|
||||||
Value: item.Value,
|
User: mapping.ToUserEntity(item.User),
|
||||||
|
Author: mapping.ToUserEntity(item.Author),
|
||||||
|
Type: mapping.ToContactTypeEntity(item.Type),
|
||||||
|
Value: item.Value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type WebhookResponse struct {
|
|||||||
//RideRequest has the data to dispatch a ride
|
//RideRequest has the data to dispatch a ride
|
||||||
type RideRequest struct {
|
type RideRequest struct {
|
||||||
UserUUID string `json:"user_uuid,omitempty"`
|
UserUUID string `json:"user_uuid,omitempty"`
|
||||||
|
UserConsent bool `json:"user_consent,omitempty"`
|
||||||
Status string `json:"status,omitempty"`
|
Status string `json:"status,omitempty"`
|
||||||
RideID string `json:"ride_id,omitempty"`
|
RideID string `json:"ride_id,omitempty"`
|
||||||
RideType string `json:"ride_type,omitempty"`
|
RideType string `json:"ride_type,omitempty"`
|
||||||
@@ -158,4 +159,4 @@ type RideRoute struct {
|
|||||||
Duration int64 `json:"duration,omitempty"`
|
Duration int64 `json:"duration,omitempty"`
|
||||||
ETA int64 `json:"eta,omitempty"`
|
ETA int64 `json:"eta,omitempty"`
|
||||||
Bearing int64 `json:"bearing,omitempty"`
|
Bearing int64 `json:"bearing,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -26,8 +26,11 @@ type User struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Contact struct {
|
type Contact struct {
|
||||||
Type ContactType `json:"type,omitempty"`
|
ID string `json:"id,omitempty"`
|
||||||
Value string `json:"contact,omitempty"`
|
User User `json:"-"`
|
||||||
|
Type ContactType `json:"type,omitempty"`
|
||||||
|
Value string `json:"contact,omitempty"`
|
||||||
|
Author User `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContactType struct {
|
type ContactType struct {
|
||||||
|
|||||||
@@ -79,18 +79,23 @@ p, *, *, *, *, *, *, /v1/nemt/organization/type, GET
|
|||||||
p, AD, *, *, *, *, *, /v1/nemt/organization/*, GET
|
p, AD, *, *, *, *, *, /v1/nemt/organization/*, GET
|
||||||
p, AD, *, *, *, *, *, /v1/nemt/organization/*, POST
|
p, AD, *, *, *, *, *, /v1/nemt/organization/*, POST
|
||||||
p, AD, *, *, *, *, *, /v1/nemt/organization/*, PUT
|
p, AD, *, *, *, *, *, /v1/nemt/organization/*, PUT
|
||||||
|
p, AD, *, *, *, *, *, /v1/nemt/organization/*, DELETE
|
||||||
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, GET
|
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, GET
|
||||||
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, POST
|
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, POST
|
||||||
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, PUT
|
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, PUT
|
||||||
|
p, SCHDAD, *, *, *, [equal*], *, /v1/nemt/organization/*, DELETE
|
||||||
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, GET
|
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, GET
|
||||||
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, POST
|
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, POST
|
||||||
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, PUT
|
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, PUT
|
||||||
|
p, PLANAD, *, *, *, [equal*], *, /v1/nemt/organization/*, DELETE
|
||||||
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, GET
|
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, GET
|
||||||
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, POST
|
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, POST
|
||||||
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, PUT
|
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, PUT
|
||||||
|
p, BDCAD, *, *, *, *, *, /v1/nemt/organization/*, DELETE
|
||||||
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, GET
|
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, GET
|
||||||
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, POST
|
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, POST
|
||||||
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, PUT
|
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, PUT
|
||||||
|
p, BCBSIAD, *, *, *, *, *, /v1/nemt/organization/*, DELETE
|
||||||
p, SPT, *, programsupport, *, *, *, /v1/nemt/organization/*, GET
|
p, SPT, *, programsupport, *, *, *, /v1/nemt/organization/*, GET
|
||||||
p, SP, *, provider, *, *, *, /v1/nemt/organization, GET
|
p, SP, *, provider, *, *, *, /v1/nemt/organization, GET
|
||||||
p, SP, *, plan, *, *, *, /v1/nemt/organization, GET
|
p, SP, *, plan, *, *, *, /v1/nemt/organization, GET
|
||||||
@@ -108,4 +113,3 @@ p, BCBSIAD, *, bcbsi, *, *, *, /v1/nemt/eligibility, POST
|
|||||||
p, BDCAD, *, techsupport, *, *, *, /v1/nemt/eligibility, POST
|
p, BDCAD, *, techsupport, *, *, *, /v1/nemt/eligibility, POST
|
||||||
p, PLANAD, *, plan, *, *, *, /v1/nemt/eligibility, POST
|
p, PLANAD, *, plan, *, *, *, /v1/nemt/eligibility, POST
|
||||||
p, AD, *, *, *, *, *, /v1/nemt/eligibility, POST
|
p, AD, *, *, *, *, *, /v1/nemt/eligibility, POST
|
||||||
|
|
||||||
|
|||||||
|
@@ -294,7 +294,7 @@ func (c *organizationRepo) GetAllTypes() ([]entity.OrganizationType, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *organizationRepo) GetTypeByKey(key string) (entity.OrganizationType, error) {
|
func (c *organizationRepo) GetTypeByKey(key string) (entity.OrganizationType, error) {
|
||||||
return c.parseTypeEntity(c.conn.QueryRow(c.getTypeQuery()+" WHERE b.organization_type_key=?", key))
|
return c.parseTypeEntity(c.conn.QueryRow(c.getTypeQuery()+" WHERE organization_type_key=? ", key))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *organizationRepo) GetByType(organizationTypeKey string, user entity.User) ([]entity.Organization, error) {
|
func (c *organizationRepo) GetByType(organizationTypeKey string, user entity.User) ([]entity.Organization, error) {
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ func (c *userRepo) GetContacts(userID int64) ([]entity.ContactInfo, error) {
|
|||||||
a.user_id,
|
a.user_id,
|
||||||
b.contact_type_id,
|
b.contact_type_id,
|
||||||
b.key contact_type_key,
|
b.key contact_type_key,
|
||||||
b.name contact_type_name
|
b.name contact_type_name,
|
||||||
|
a.contact_uuid
|
||||||
FROM tab_contact a
|
FROM tab_contact a
|
||||||
INNER JOIN tab_contact_type b
|
INNER JOIN tab_contact_type b
|
||||||
ON a.contact_type_id = b.contact_type_id
|
ON a.contact_type_id = b.contact_type_id
|
||||||
@@ -79,7 +80,7 @@ func (c *userRepo) GetContacts(userID int64) ([]entity.ContactInfo, error) {
|
|||||||
retVal := make([]entity.ContactInfo, 0)
|
retVal := make([]entity.ContactInfo, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
contact := entity.ContactInfo{}
|
contact := entity.ContactInfo{}
|
||||||
err = rows.Scan(&contact.ID, &contact.Value, &contact.UserID, &contact.Type.ID, &contact.Type.Key, &contact.Type.Value)
|
err = rows.Scan(&contact.ID, &contact.Value, &contact.User.ID, &contact.Type.ID, &contact.Type.Key, &contact.Type.Value, &contact.UUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -354,9 +355,11 @@ func (c *userRepo) Create(user entity.User) (retVal entity.User, err error) {
|
|||||||
|
|
||||||
if retVal.Email != "" {
|
if retVal.Email != "" {
|
||||||
contact := entity.ContactInfo{
|
contact := entity.ContactInfo{
|
||||||
Type: entity.ContactType{Key: "email"},
|
Type: entity.ContactType{Key: "email"},
|
||||||
Value: retVal.Email,
|
Value: retVal.Email,
|
||||||
UserID: retVal.ID,
|
User: entity.User{
|
||||||
|
ID: retVal.ID,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
contact, err = c.addContactInfo(contact)
|
contact, err = c.addContactInfo(contact)
|
||||||
@@ -367,9 +370,11 @@ func (c *userRepo) Create(user entity.User) (retVal entity.User, err error) {
|
|||||||
|
|
||||||
if retVal.PhoneNumber != "" {
|
if retVal.PhoneNumber != "" {
|
||||||
contact := entity.ContactInfo{
|
contact := entity.ContactInfo{
|
||||||
Type: entity.ContactType{Key: "phone"},
|
Type: entity.ContactType{Key: "phone"},
|
||||||
Value: retVal.PhoneNumber,
|
Value: retVal.PhoneNumber,
|
||||||
UserID: retVal.ID,
|
User: entity.User{
|
||||||
|
ID: retVal.ID,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
contact, err = c.addContactInfo(contact)
|
contact, err = c.addContactInfo(contact)
|
||||||
@@ -387,19 +392,10 @@ func (c *userRepo) SaveContact(contact entity.ContactInfo) (entity.ContactInfo,
|
|||||||
|
|
||||||
func (c *userRepo) RemoveContact(contact entity.ContactInfo) (entity.ContactInfo, error) {
|
func (c *userRepo) RemoveContact(contact entity.ContactInfo) (entity.ContactInfo, error) {
|
||||||
const (
|
const (
|
||||||
query = `INSERT INTO tab_contact(contact_type_id, user_id, contact)
|
query = `DELETE FROM tab_contact WHERE contact_uuid = ?;`
|
||||||
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)
|
result, err := c.conn.Exec(query, contact.UUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return contact, err
|
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) {
|
func (c *userRepo) addContactInfo(contact entity.ContactInfo) (entity.ContactInfo, error) {
|
||||||
const (
|
const (
|
||||||
query = `INSERT INTO tab_contact(contact_type_id, user_id, contact)
|
query = `INSERT INTO tab_contact(contact_type_id, user_id, contact, contact_uuid)
|
||||||
SELECT a.contact_type_id, ? user_id, ? contact
|
SELECT a.contact_type_id, ? user_id, ? contact, ? contact_uuid
|
||||||
FROM
|
FROM
|
||||||
tab_contact_type a
|
tab_contact_type a
|
||||||
LEFT JOIN tab_contact b
|
LEFT JOIN tab_contact b
|
||||||
@@ -427,7 +423,13 @@ func (c *userRepo) addContactInfo(contact entity.ContactInfo) (entity.ContactInf
|
|||||||
AND b.contact_id IS NULL;`
|
AND b.contact_id IS NULL;`
|
||||||
)
|
)
|
||||||
|
|
||||||
result, err := c.conn.Exec(query, contact.UserID, contact.Value, contact.UserID, contact.Value, contact.Type.Key)
|
sUUID, err := uuid.NewV4()
|
||||||
|
if err != nil {
|
||||||
|
return contact, err
|
||||||
|
}
|
||||||
|
|
||||||
|
contact.UUID = sUUID.String()
|
||||||
|
result, err := c.conn.Exec(query, contact.User.ID, contact.Value, contact.UUID, contact.User.ID, contact.Value, contact.Type.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return contact, err
|
return contact, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ type UserRepo interface {
|
|||||||
GetAddressByUUID(addressUUID string) (entity.Address, error)
|
GetAddressByUUID(addressUUID string) (entity.Address, error)
|
||||||
GetContactType() (retVal []entity.ContactType, err error)
|
GetContactType() (retVal []entity.ContactType, err error)
|
||||||
RemoveAddress(addressUUID string) error
|
RemoveAddress(addressUUID string) error
|
||||||
|
SaveContact(contact entity.ContactInfo) (entity.ContactInfo, error)
|
||||||
|
RemoveContact(contact entity.ContactInfo) (entity.ContactInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RideRepo defines the data set for Rides
|
// RideRepo defines the data set for Rides
|
||||||
|
|||||||
@@ -34,8 +34,10 @@ type User struct {
|
|||||||
|
|
||||||
type ContactInfo struct {
|
type ContactInfo struct {
|
||||||
ID int64 `db:"contact_id" json:"contact_id"`
|
ID int64 `db:"contact_id" json:"contact_id"`
|
||||||
|
UUID string `db:"contact_uuid" json:"contact_uuid"`
|
||||||
Type ContactType `db:"contact_type" json:"contact_type"`
|
Type ContactType `db:"contact_type" json:"contact_type"`
|
||||||
UserID int64 `db:"user_id" json:"-"`
|
User User `db:"user" json:"-"`
|
||||||
|
Author User `db:"author" json:"-"`
|
||||||
Value string `db:"value" json:"value"`
|
Value string `db:"value" json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,26 @@ func (s *userService) SaveAddress(address entity.Address) (entity.Address, error
|
|||||||
return s.svc.db.Users().SaveAddress(address)
|
return s.svc.db.Users().SaveAddress(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *userService) SaveContact(contact entity.ContactInfo) (entity.ContactInfo, error) {
|
||||||
|
user, err := s.svc.db.Users().GetByUUID(contact.User.UUID, "")
|
||||||
|
if err != nil {
|
||||||
|
return entity.ContactInfo{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
contact.User = user
|
||||||
|
return s.svc.db.Users().SaveContact(contact)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *userService) RemoveContact(contact entity.ContactInfo) (entity.ContactInfo, error) {
|
||||||
|
user, err := s.svc.db.Users().GetByUUID(contact.User.UUID, "")
|
||||||
|
if err != nil {
|
||||||
|
return entity.ContactInfo{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
contact.User = user
|
||||||
|
return s.svc.db.Users().RemoveContact(contact)
|
||||||
|
}
|
||||||
|
|
||||||
// GetAddressByUUID returns a list of users by profile
|
// GetAddressByUUID returns a list of users by profile
|
||||||
func (s *userService) GetAddressByUUID(addressUUID string) (entity.Address, error) {
|
func (s *userService) GetAddressByUUID(addressUUID string) (entity.Address, error) {
|
||||||
return s.svc.db.Users().GetAddressByUUID(addressUUID)
|
return s.svc.db.Users().GetAddressByUUID(addressUUID)
|
||||||
|
|||||||
15
server/authorization/address.go
Normal file
15
server/authorization/address.go
Normal 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)
|
||||||
|
}
|
||||||
1
server/authorization/authorization.go
Normal file
1
server/authorization/authorization.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package authorization
|
||||||
15
server/authorization/contact.go
Normal file
15
server/authorization/contact.go
Normal 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)
|
||||||
|
}
|
||||||
76
server/authorization/organization.go
Normal file
76
server/authorization/organization.go
Normal 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)
|
||||||
|
}
|
||||||
62
server/authorization/profile.go
Normal file
62
server/authorization/profile.go
Normal 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
|
||||||
|
}
|
||||||
86
server/authorization/user.go
Normal file
86
server/authorization/user.go
Normal 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
|
||||||
|
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"bitbucket.org/nemt/nemt-portal-api/infra/cache"
|
"bitbucket.org/nemt/nemt-portal-api/infra/cache"
|
||||||
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
||||||
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
|
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
|
||||||
|
"bitbucket.org/nemt/nemt-portal-api/server/authorization"
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -64,6 +65,11 @@ func (c *controller) handleAddOrganization(ctx echo.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return routeutils.HandleAPIError(ctx, err)
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !authorization.CanCreateOrganization(authUser, org) {
|
||||||
|
return routeutils.ResponseAPIAuthorizationError(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
org.Author.ID = authUser.ID
|
org.Author.ID = authUser.ID
|
||||||
org.LastEditor.ID = authUser.ID
|
org.LastEditor.ID = authUser.ID
|
||||||
|
|
||||||
@@ -127,6 +133,15 @@ func (c *controller) handleParent(ctx echo.Context) error {
|
|||||||
return routeutils.HandleAPIError(ctx, err)
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
organization, err := c.svc.Organization.GetByUUID(orgUUID, authUser)
|
||||||
|
if err != nil {
|
||||||
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !authorization.CanUpdateOrganization(authUser, organization){
|
||||||
|
return routeutils.ResponseAPIAuthorizationError(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := c.svc.Organization.SetParentOrganization(orgUUID, parent.UUID, authUser)
|
resp, err := c.svc.Organization.SetParentOrganization(orgUUID, parent.UUID, authUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return routeutils.HandleAPIError(ctx, err)
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
@@ -152,6 +167,15 @@ func (c *controller) handleChild(ctx echo.Context) error {
|
|||||||
return routeutils.HandleAPIError(ctx, err)
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
organization, err := c.svc.Organization.GetByUUID(orgUUID, authUser)
|
||||||
|
if err != nil {
|
||||||
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !authorization.CanUpdateOrganization(authUser, organization){
|
||||||
|
return routeutils.ResponseAPIAuthorizationError(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
_, err = c.svc.Organization.SetParentOrganization(child.UUID, orgUUID, authUser)
|
_, err = c.svc.Organization.SetParentOrganization(child.UUID, orgUUID, authUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return routeutils.HandleAPIError(ctx, err)
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
@@ -246,6 +270,18 @@ func (c *controller) handleAddAddress(ctx echo.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return routeutils.HandleAPIError(ctx, err)
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
organization, err := c.svc.Organization.GetByUUID(orgUUID, authUser)
|
||||||
|
if err != nil {
|
||||||
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !authorization.CanCreateAddress(authUser, organization) {
|
||||||
|
return routeutils.ResponseAPIAuthorizationError(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return routeutils.ResponseAPIAuthorizationError(ctx)
|
||||||
|
|
||||||
address.CreatedUser.ID = authUser.ID
|
address.CreatedUser.ID = authUser.ID
|
||||||
address.UpdatedUser.ID = authUser.ID
|
address.UpdatedUser.ID = authUser.ID
|
||||||
|
|
||||||
@@ -278,6 +314,7 @@ func (c *controller) handleRemoveContact(ctx echo.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return routeutils.HandleAPIError(ctx, err)
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
contact.UpdatedUser.ID = authUser.ID
|
contact.UpdatedUser.ID = authUser.ID
|
||||||
|
|
||||||
err = c.svc.Organization.InactivateOrganizationContact(orgUUID, contact, authUser)
|
err = c.svc.Organization.InactivateOrganizationContact(orgUUID, contact, authUser)
|
||||||
@@ -309,6 +346,16 @@ func (c *controller) handleAddContact(ctx echo.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return routeutils.HandleAPIError(ctx, err)
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
organization, err := c.svc.Organization.GetByUUID(orgUUID, authUser)
|
||||||
|
if err != nil {
|
||||||
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !authorization.CanCreateContact(authUser, organization) {
|
||||||
|
return routeutils.ResponseAPIAuthorizationError(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
contact.CreatedUser.ID = authUser.ID
|
contact.CreatedUser.ID = authUser.ID
|
||||||
contact.UpdatedUser.ID = authUser.ID
|
contact.UpdatedUser.ID = authUser.ID
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,18 @@ func ResponseAPIOK(c echo.Context, data interface{}) error {
|
|||||||
return c.JSON(http.StatusOK, data)
|
return c.JSON(http.StatusOK, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResponseAPIErrorWithData returns a standard API error with additional data to the response
|
||||||
|
func ResponseAPIErrorWithData(c echo.Context, status int, message string, redirect bool, data interface{}) error {
|
||||||
|
returnValue := resultWrapper{
|
||||||
|
Error: true,
|
||||||
|
Message: message,
|
||||||
|
Redirect: redirect,
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(status, returnValue)
|
||||||
|
}
|
||||||
|
|
||||||
// ResponseAPIError returns a standard API error to the response
|
// ResponseAPIError returns a standard API error to the response
|
||||||
func ResponseAPIError(c echo.Context, status int, message string, redirect bool) error {
|
func ResponseAPIError(c echo.Context, status int, message string, redirect bool) error {
|
||||||
returnValue := resultWrapper{
|
returnValue := resultWrapper{
|
||||||
@@ -49,6 +61,11 @@ func ResponseAPIAuthError(c echo.Context, message string, redirect bool) error {
|
|||||||
return ResponseAPIError(c, http.StatusUnauthorized, message, redirect)
|
return ResponseAPIError(c, http.StatusUnauthorized, message, redirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResponseAPIAuthorizationError returns a standard API auth error to the response
|
||||||
|
func ResponseAPIAuthorizationError(c echo.Context) error {
|
||||||
|
return ResponseAPIError(c, http.StatusForbidden, "Forbidden by controller", false)
|
||||||
|
}
|
||||||
|
|
||||||
// ResponseAPIServiceError returns a standard API service unavailable error to the response
|
// ResponseAPIServiceError returns a standard API service unavailable error to the response
|
||||||
func ResponseAPIServiceError(c echo.Context, message string) error {
|
func ResponseAPIServiceError(c echo.Context, message string) error {
|
||||||
return ResponseAPIError(c, http.StatusServiceUnavailable, message, false)
|
return ResponseAPIError(c, http.StatusServiceUnavailable, message, false)
|
||||||
@@ -59,6 +76,11 @@ func ResponseAPIValidationError(c echo.Context, message string) error {
|
|||||||
return ResponseAPIError(c, http.StatusUnprocessableEntity, message, false)
|
return ResponseAPIError(c, http.StatusUnprocessableEntity, message, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResponseAPICustomValidationError returns a standard API validation error with custom data to the response
|
||||||
|
func ResponseAPICustomValidationError(c echo.Context, message string, data interface{}) error {
|
||||||
|
return ResponseAPIErrorWithData(c, http.StatusUnprocessableEntity, message, false, data)
|
||||||
|
}
|
||||||
|
|
||||||
// ResponseAPIFieldValidationError returns a standard API field validation error to the response
|
// ResponseAPIFieldValidationError returns a standard API field validation error to the response
|
||||||
func ResponseAPIFieldValidationError(c echo.Context, field string, message string) error {
|
func ResponseAPIFieldValidationError(c echo.Context, field string, message string) error {
|
||||||
err := errors.NewValidationError(field, message)
|
err := errors.NewValidationError(field, message)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"bitbucket.org/nemt/nemt-portal-api/infra/auth"
|
"bitbucket.org/nemt/nemt-portal-api/infra/auth"
|
||||||
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
||||||
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
|
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
|
||||||
|
"bitbucket.org/nemt/nemt-portal-api/server/validation"
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo"
|
||||||
uuid "github.com/satori/go.uuid"
|
uuid "github.com/satori/go.uuid"
|
||||||
"google.golang.org/api/googleapi/transport"
|
"google.golang.org/api/googleapi/transport"
|
||||||
@@ -231,6 +232,11 @@ func (c *controller) handle(ctx echo.Context) error {
|
|||||||
return routeutils.ResponseAPIValidationError(ctx, "User not found")
|
return routeutils.ResponseAPIValidationError(ctx, "User not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Validate ride request
|
||||||
|
if validationErrors := validation.ValidateRide(&requestRide, &user) ; len(validationErrors) > 0 {
|
||||||
|
return routeutils.ResponseAPICustomValidationError(ctx, "ride validation failed", validationErrors)
|
||||||
|
}
|
||||||
|
|
||||||
createdUser, err := auth.GetUserDetail(ctx, c.cfg)
|
createdUser, err := auth.GetUserDetail(ctx, c.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return routeutils.HandleAPIError(ctx, err)
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
@@ -869,4 +875,4 @@ func (c *controller) handleReady(ctx echo.Context) error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
return routeutils.ResponseAPIOK(ctx, nextRide)
|
return routeutils.ResponseAPIOK(ctx, nextRide)
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"bitbucket.org/nemt/nemt-portal-api/infra/auth"
|
"bitbucket.org/nemt/nemt-portal-api/infra/auth"
|
||||||
"bitbucket.org/nemt/nemt-portal-api/infra/cache"
|
"bitbucket.org/nemt/nemt-portal-api/infra/cache"
|
||||||
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
"bitbucket.org/nemt/nemt-portal-api/infra/config"
|
||||||
|
"bitbucket.org/nemt/nemt-portal-api/server/authorization"
|
||||||
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
|
"bitbucket.org/nemt/nemt-portal-api/server/router/routeutils"
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo"
|
||||||
)
|
)
|
||||||
@@ -127,6 +128,62 @@ func (c *controller) handleRemoveAddress(ctx echo.Context) error {
|
|||||||
return routeutils.ResponseNoContent(ctx, addressID)
|
return routeutils.ResponseNoContent(ctx, addressID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *controller) handlePortalContact(ctx echo.Context) error {
|
||||||
|
userID, err := routeutils.GetAndValidateStringParam(ctx, "user_uuid", "mandatory field")
|
||||||
|
if err != nil {
|
||||||
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
item, err := c.svc.Users.GetByUUID(userID, "")
|
||||||
|
if err != nil {
|
||||||
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
createdUser, err := auth.GetUserDetail(ctx, c.cfg)
|
||||||
|
if err != nil {
|
||||||
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.ID == "" {
|
||||||
|
return routeutils.ResponseAPIValidationError(ctx, "User not found")
|
||||||
|
} else {
|
||||||
|
var Contact viewmodel.Contact
|
||||||
|
if err := ctx.Bind(&Contact); err != nil {
|
||||||
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
|
}
|
||||||
|
Contact.User = item
|
||||||
|
Contact.Author = createdUser
|
||||||
|
Contact, err = c.svc.Users.SaveContact(Contact)
|
||||||
|
if err != nil {
|
||||||
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contact.User, err = c.svc.Users.GetByUUID(userID, "")
|
||||||
|
// if err != nil {
|
||||||
|
// return routeutils.HandleAPIError(ctx, err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
return routeutils.ResponseAPIOK(ctx, Contact)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) handleRemoveContact(ctx echo.Context) error {
|
||||||
|
contactUUID, err := routeutils.GetAndValidateStringParam(ctx, "contact_uuid", "mandatory field")
|
||||||
|
if err != nil {
|
||||||
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
contact := viewmodel.Contact{
|
||||||
|
ID: contactUUID,
|
||||||
|
}
|
||||||
|
contact, err = c.svc.Users.RemoveContact(contact)
|
||||||
|
if err != nil {
|
||||||
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return routeutils.ResponseNoContent(ctx, contact)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *controller) handleMemberAddress(ctx echo.Context) error {
|
func (c *controller) handleMemberAddress(ctx echo.Context) error {
|
||||||
userID, err := routeutils.GetAndValidateStringParam(ctx, "user_uuid", "mandatory field")
|
userID, err := routeutils.GetAndValidateStringParam(ctx, "user_uuid", "mandatory field")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -389,6 +446,10 @@ func (c *controller) handlePortal(ctx echo.Context) error {
|
|||||||
return routeutils.HandleAPIError(ctx, err)
|
return routeutils.HandleAPIError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !authorization.CanCreateUser(authUser, user) {
|
||||||
|
return routeutils.ResponseAPIAuthorizationError(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
if len(user.Profiles) == 0 {
|
if len(user.Profiles) == 0 {
|
||||||
return routeutils.ResponseAPIAuthError(ctx, "profile is required", false)
|
return routeutils.ResponseAPIAuthError(ctx, "profile is required", false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ const (
|
|||||||
userDetailRoute = "/portal/:user_uuid"
|
userDetailRoute = "/portal/:user_uuid"
|
||||||
userAddressRoute = "/portal/:user_uuid/address"
|
userAddressRoute = "/portal/:user_uuid/address"
|
||||||
userRemoveAddressRoute = "/portal/:user_uuid/address/:address_uuid"
|
userRemoveAddressRoute = "/portal/:user_uuid/address/:address_uuid"
|
||||||
|
userContactRoute = "/portal/:user_uuid/contact"
|
||||||
|
userRemoveContactRoute = "/portal/:user_uuid/contact/:contact_uuid"
|
||||||
portalRoute = "/portal"
|
portalRoute = "/portal"
|
||||||
portalBulkRoute = "/portal/bulk"
|
portalBulkRoute = "/portal/bulk"
|
||||||
contacttypeRoute = "/contacttype"
|
contacttypeRoute = "/contacttype"
|
||||||
@@ -41,6 +43,9 @@ func Register(r *echo.Group, cfg *config.Config, svc *applicationservice.Service
|
|||||||
r.POST(userAddressRoute, ctrl.handlePortalAddress)
|
r.POST(userAddressRoute, ctrl.handlePortalAddress)
|
||||||
r.PUT(userRemoveAddressRoute, ctrl.handleRemoveAddress)
|
r.PUT(userRemoveAddressRoute, ctrl.handleRemoveAddress)
|
||||||
|
|
||||||
|
r.POST(userContactRoute, ctrl.handlePortalContact)
|
||||||
|
r.PUT(userRemoveContactRoute, ctrl.handleRemoveContact)
|
||||||
|
|
||||||
//Can be cached
|
//Can be cached
|
||||||
r.GET(contacttypeRoute, ctrl.handleContactType)
|
r.GET(contacttypeRoute, ctrl.handleContactType)
|
||||||
|
|
||||||
|
|||||||
@@ -193,8 +193,6 @@ func (a *Config) objectRelation(object interface{}, currentUser viewmodel.User)
|
|||||||
case viewmodel.User:
|
case viewmodel.User:
|
||||||
if obj.ID == currentUser.ID {
|
if obj.ID == currentUser.ID {
|
||||||
return "[self]"
|
return "[self]"
|
||||||
} else {
|
|
||||||
return "[other]"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "[other]"
|
return "[other]"
|
||||||
|
|||||||
183
server/validation/tnc.go
Normal file
183
server/validation/tnc.go
Normal 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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user