Skip to content

Commit

Permalink
DEVTOOLING-879: Fixing nil pointer exception in external_contacts res…
Browse files Browse the repository at this point in the history
…ource (#1295)

* Fixing code smells/potential nil pointer exceptions

* Fixed linting errors in external_contacts package

* Cleaned up more code smells
  • Loading branch information
charliecon authored Oct 16, 2024
1 parent 903714a commit 0320015
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ var internalProxy *externalContactsContactsProxy

// Type definitions for each func on our proxy so we can easily mock them out later
type getAllExternalContactsFunc func(ctx context.Context, p *externalContactsContactsProxy) (*[]platformclientv2.Externalcontact, *platformclientv2.APIResponse, error)
type createExternalContactFunc func(ctx context.Context, p *externalContactsContactsProxy, externalContact *platformclientv2.Externalcontact) (*platformclientv2.Externalcontact, *platformclientv2.APIResponse, error)
type createExternalContactFunc func(ctx context.Context, p *externalContactsContactsProxy, externalContact platformclientv2.Externalcontact) (*platformclientv2.Externalcontact, *platformclientv2.APIResponse, error)
type deleteExternalContactFunc func(ctx context.Context, p *externalContactsContactsProxy, externalContactId string) (response *platformclientv2.APIResponse, err error)
type getExternalContactByIdFunc func(ctx context.Context, p *externalContactsContactsProxy, externalContactId string) (externalContact *platformclientv2.Externalcontact, response *platformclientv2.APIResponse, err error)
type getExternalContactIdBySearchFunc func(ctx context.Context, p *externalContactsContactsProxy, search string) (externalContactId string, retryable bool, response *platformclientv2.APIResponse, err error)
type updateExternalContactFunc func(ctx context.Context, p *externalContactsContactsProxy, externalContactId string, externalContact *platformclientv2.Externalcontact) (*platformclientv2.Externalcontact, *platformclientv2.APIResponse, error)
type updateExternalContactFunc func(ctx context.Context, p *externalContactsContactsProxy, externalContactId string, externalContact platformclientv2.Externalcontact) (*platformclientv2.Externalcontact, *platformclientv2.APIResponse, error)

// externalContactsContactsProxy contains all of the methods that call genesys cloud APIs.
type externalContactsContactsProxy struct {
Expand Down Expand Up @@ -87,7 +87,7 @@ func (p *externalContactsContactsProxy) getAllExternalContacts(ctx context.Conte
}

// createExternalContact creates a Genesys Cloud External Contact
func (p *externalContactsContactsProxy) createExternalContact(ctx context.Context, externalContact *platformclientv2.Externalcontact) (*platformclientv2.Externalcontact, *platformclientv2.APIResponse, error) {
func (p *externalContactsContactsProxy) createExternalContact(ctx context.Context, externalContact platformclientv2.Externalcontact) (*platformclientv2.Externalcontact, *platformclientv2.APIResponse, error) {
return p.createExternalContactAttr(ctx, p, externalContact)
}

Expand All @@ -110,7 +110,7 @@ func (p *externalContactsContactsProxy) getExternalContactIdBySearch(ctx context
}

// updateExternalContact updates a Genesys Cloud External Contact
func (p *externalContactsContactsProxy) updateExternalContact(ctx context.Context, externalContactId string, externalContact *platformclientv2.Externalcontact) (*platformclientv2.Externalcontact, *platformclientv2.APIResponse, error) {
func (p *externalContactsContactsProxy) updateExternalContact(ctx context.Context, externalContactId string, externalContact platformclientv2.Externalcontact) (*platformclientv2.Externalcontact, *platformclientv2.APIResponse, error) {
return p.updateExternalContactAttr(ctx, p, externalContactId, externalContact)
}

Expand All @@ -122,16 +122,14 @@ func getAllExternalContactsFn(ctx context.Context, p *externalContactsContactsPr
for {
externalContacts, resp, err := p.externalContactsApi.GetExternalcontactsScanContacts(100, cursor)
if err != nil {
return nil, resp, fmt.Errorf("Failed to get external contacts: %v", err)
return nil, resp, fmt.Errorf("failed to get external contacts: %v", err)
}
response = resp
if externalContacts.Entities == nil || len(*externalContacts.Entities) == 0 {
break
}

for _, externalContact := range *externalContacts.Entities {
allExternalContacts = append(allExternalContacts, externalContact)
}
allExternalContacts = append(allExternalContacts, *externalContacts.Entities...)

if externalContacts.Cursors == nil || externalContacts.Cursors.After == nil {
break
Expand All @@ -141,37 +139,33 @@ func getAllExternalContactsFn(ctx context.Context, p *externalContactsContactsPr

// Cache the External Contacts resource into the p.externalContactsCache for later use
for _, externalContact := range allExternalContacts {
if externalContact.Id == nil {
continue
}
rc.SetCache(p.externalContactsCache, *externalContact.Id, externalContact)
}

return &allExternalContacts, response, nil
}

// createExternalContactFn is an implementation function for creating a Genesys Cloud External Contact
func createExternalContactFn(ctx context.Context, p *externalContactsContactsProxy, externalContact *platformclientv2.Externalcontact) (*platformclientv2.Externalcontact, *platformclientv2.APIResponse, error) {
contact, resp, err := p.externalContactsApi.PostExternalcontactsContacts(*externalContact)
if err != nil {
return nil, resp, fmt.Errorf("Failed to create external contact: %s", err)
}
return contact, resp, nil
func createExternalContactFn(ctx context.Context, p *externalContactsContactsProxy, externalContact platformclientv2.Externalcontact) (*platformclientv2.Externalcontact, *platformclientv2.APIResponse, error) {
return p.externalContactsApi.PostExternalcontactsContacts(externalContact)
}

// deleteExternalContactsFn is an implementation function for deleting a Genesys Cloud External Contact
func deleteExternalContactsFn(ctx context.Context, p *externalContactsContactsProxy, externalContactId string) (*platformclientv2.APIResponse, error) {
_, resp, err := p.externalContactsApi.DeleteExternalcontactsContact(externalContactId)
if err != nil {
return resp, fmt.Errorf("Failed to delete external contact: %s", err)
return resp, err
}
rc.DeleteCacheItem(p.externalContactsCache, externalContactId)
return resp, nil
}

// getExternalContactByIdFn is an implementation of the function to get a Genesys Cloud External Contact by Id
func getExternalContactByIdFn(ctx context.Context, p *externalContactsContactsProxy, externalContactId string) (*platformclientv2.Externalcontact, *platformclientv2.APIResponse, error) {
externalContact, resp, err := p.externalContactsApi.GetExternalcontactsContact(externalContactId, nil)
if err != nil {
return nil, resp, fmt.Errorf("Failed to retrieve external contact by id %s: %s", externalContactId, err)
}
return externalContact, resp, nil
return p.externalContactsApi.GetExternalcontactsContact(externalContactId, nil)
}

// getExternalContactIdBySearchFn is an implementation of the function to get a Genesys Cloud External contact by a search team
Expand All @@ -180,27 +174,26 @@ func getExternalContactIdBySearchFn(ctx context.Context, p *externalContactsCont
const pageSize = 100
contacts, resp, err := p.externalContactsApi.GetExternalcontactsContacts(pageSize, pageNum, search, "", nil)
if err != nil {
return "", false, resp, fmt.Errorf("Error searching external contact %s: %s", search, err)
return "", false, resp, fmt.Errorf("error searching external contact %s: %s", search, err)
}

if contacts.Entities == nil || len(*contacts.Entities) == 0 {
return "", true, resp, fmt.Errorf("No external contact found with search %s", search)
return "", true, resp, fmt.Errorf("no external contact found with search %s", search)
}

if len(*contacts.Entities) > 1 {
return "", false, resp, fmt.Errorf("Too many values returned in look for external contact. Unable to choose 1 external contact. Please refine search and continue.")
return "", false, resp, fmt.Errorf("too many values returned in look for external contact. Unable to choose 1 external contact. Please refine search and continue")
}

if contactId := (*contacts.Entities)[0].Id; contactId != nil {
log.Printf("Retrieved the external contact search id %s by name %s", *contactId, search)
return *contactId, false, resp, nil
}

log.Printf("Retrieved the external contact search id %s by name %s", *(*contacts.Entities)[0].Id, search)
contact := (*contacts.Entities)[0]
return *contact.Id, false, resp, nil
return "", true, resp, fmt.Errorf("external contact id not found for search %s", search)
}

// updateExternalContactFn is an implementation of the function to update a Genesys Cloud external contact
func updateExternalContactFn(ctx context.Context, p *externalContactsContactsProxy, externalContactId string, externalContact *platformclientv2.Externalcontact) (*platformclientv2.Externalcontact, *platformclientv2.APIResponse, error) {
externalContact, resp, err := p.externalContactsApi.PutExternalcontactsContact(externalContactId, *externalContact)
if err != nil {
return nil, resp, fmt.Errorf("Failed to update external contact: %s", err)
}
return externalContact, resp, nil
func updateExternalContactFn(ctx context.Context, p *externalContactsContactsProxy, externalContactId string, externalContact platformclientv2.Externalcontact) (*platformclientv2.Externalcontact, *platformclientv2.APIResponse, error) {
return p.externalContactsApi.PutExternalcontactsContact(externalContactId, externalContact)
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ func getAllAuthExternalContacts(ctx context.Context, clientConfig *platformclien
}

for _, externalContact := range *externalContacts {
if externalContact.Id == nil {
continue
}
log.Printf("Dealing with external contact id : %s", *externalContact.Id)
resources[*externalContact.Id] = &resourceExporter.ResourceMeta{Name: *externalContact.Id}
}
Expand All @@ -61,13 +64,18 @@ func createExternalContact(ctx context.Context, d *schema.ResourceData, meta int
sdkConfig := meta.(*provider.ProviderMeta).ClientConfig
ep := getExternalContactsContactsProxy(sdkConfig)

log.Printf("Creating external contact")
externalContact := getExternalContactFromResourceData(d)

contact, resp, err := ep.createExternalContact(ctx, &externalContact)
contact, resp, err := ep.createExternalContact(ctx, externalContact)
if err != nil {
return util.BuildAPIDiagnosticError(resourceName, fmt.Sprintf("Failed to create external contact error: %s", err), resp)
}

if contact == nil || contact.Id == nil {
msg := "No contact ID was returned on the response object from createExternalContact"
return util.BuildDiagnosticError(resourceName, msg, fmt.Errorf("%s", msg))
}

d.SetId(*contact.Id)
log.Printf("Created external contact %s", *contact.Id)
return readExternalContact(ctx, d, meta)
Expand All @@ -79,7 +87,7 @@ func readExternalContact(ctx context.Context, d *schema.ResourceData, meta inter
ep := getExternalContactsContactsProxy(sdkConfig)
cc := consistency_checker.NewConsistencyCheck(ctx, d, meta, ResourceExternalContact(), constants.DefaultConsistencyChecks, resourceName)

log.Printf("Reading contact %s", d.Id())
log.Printf("Reading external contact %s", d.Id())

return util.WithRetriesForRead(ctx, d, func() *retry.RetryError {
externalContact, resp, getErr := ep.getExternalContactById(ctx, d.Id())
Expand Down Expand Up @@ -120,13 +128,14 @@ func updateExternalContact(ctx context.Context, d *schema.ResourceData, meta int
sdkConfig := meta.(*provider.ProviderMeta).ClientConfig
ep := getExternalContactsContactsProxy(sdkConfig)

log.Printf("Updating external contact %s", d.Id())
externalContact := getExternalContactFromResourceData(d)
_, resp, err := ep.updateExternalContact(ctx, d.Id(), &externalContact)
_, resp, err := ep.updateExternalContact(ctx, d.Id(), externalContact)
if err != nil {
return util.BuildAPIDiagnosticError(resourceName, fmt.Sprintf("Failed to update external contact %s error: %s", *externalContact.Id, err), resp)
return util.BuildAPIDiagnosticError(resourceName, fmt.Sprintf("Failed to update external contact %s error: %s", d.Id(), err), resp)
}

log.Printf("Updated external contact")
log.Printf("Updated external contact %s", d.Id())
return readExternalContact(ctx, d, meta)
}

Expand All @@ -135,6 +144,7 @@ func deleteExternalContact(ctx context.Context, d *schema.ResourceData, meta int
sdkConfig := meta.(*provider.ProviderMeta).ClientConfig
ep := getExternalContactsContactsProxy(sdkConfig)

log.Printf("Deleting external contact %s", d.Id())
resp, err := ep.deleteExternalContactId(ctx, d.Id())
if err != nil {
return util.BuildAPIDiagnosticError(resourceName, fmt.Sprintf("Failed to delete external contact %s error: %s", d.Id(), err), resp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,20 @@ func buildSdkPhoneNumber(d *schema.ResourceData, key string) *platformclientv2.P

// flattenPhoneNumber converts a platformclientv2.Phonenumber into a map and then into array for consumption by Terraform
func flattenPhoneNumber(phonenumber *platformclientv2.Phonenumber) []interface{} {
if phonenumber == nil {
return nil
}

phonenumberInterface := make(map[string]interface{})
resourcedata.SetMapValueIfNotNil(phonenumberInterface, "display", phonenumber.Display)
resourcedata.SetMapValueIfNotNil(phonenumberInterface, "extension", phonenumber.Extension)
resourcedata.SetMapValueIfNotNil(phonenumberInterface, "accepts_sms", phonenumber.AcceptsSMS)
var phoneNumberE164 string
if phonenumber != nil && phonenumber.E164 != nil && *phonenumber.E164 != "" {
if phonenumber.E164 != nil && *phonenumber.E164 != "" {
var phoneNumberE164 string
utilE164 := util.NewUtilE164Service()
phoneNumberE164 = utilE164.FormatAsCalculatedE164Number(*phonenumber.E164)
phonenumberInterface["e164"] = phoneNumberE164
}
resourcedata.SetMapValueIfNotNil(phonenumberInterface, "e164", &phoneNumberE164)
resourcedata.SetMapValueIfNotNil(phonenumberInterface, "country_code", phonenumber.CountryCode)
return []interface{}{phonenumberInterface}
}
Expand Down Expand Up @@ -204,15 +208,24 @@ func buildSdkLineId(d *schema.ResourceData, key string) *platformclientv2.Lineid

// flattenSdkLineId maps platformclientv2.Lineid to a []interace{}
func flattenSdkLineId(lineId *platformclientv2.Lineid) []interface{} {
if lineId == nil {
return nil
}
lineInterface := make(map[string]interface{})
flattenUserid := flattenSdkLineUserId(lineId.Ids)
lineInterface["display_name"] = *lineId.DisplayName
lineInterface["ids"] = &flattenUserid

if flattenUserid := flattenSdkLineUserId(lineId.Ids); flattenUserid != nil {
lineInterface["ids"] = &flattenUserid
}
resourcedata.SetMapValueIfNotNil(lineInterface, "display_name", lineId.DisplayName)

return []interface{}{lineInterface}
}

// flattenSdkLineUserId maps an []platformclientv2.Lineuserid to a []interface{}
func flattenSdkLineUserId(lineUserdid *[]platformclientv2.Lineuserid) []interface{} {
if lineUserdid == nil || len(*lineUserdid) == 0 {
return nil
}
lineUseridInterface := make(map[string]interface{})
if (*lineUserdid)[0].UserId != nil {
lineUseridInterface["user_id"] = (*lineUserdid)[0].UserId
Expand All @@ -239,10 +252,7 @@ func buildSdkWhatsAppId(d *schema.ResourceData, key string) *platformclientv2.Wh

// flattenSdkWhatsAppId maps a Genesys Cloud platformclientv2.Whatsappid to a []interface{}
func flattenSdkWhatsAppId(whatsappId *platformclientv2.Whatsappid) []interface{} {
if whatsappId.DisplayName == nil {
return nil
}
if whatsappId.PhoneNumber == nil {
if whatsappId.DisplayName == nil || whatsappId.PhoneNumber == nil {
return nil
}
whatsappInterface := make(map[string]interface{})
Expand Down Expand Up @@ -278,15 +288,24 @@ func buildSdkFacebookId(d *schema.ResourceData, key string) *platformclientv2.Fa

// flattenSdkFacebookId maps a Genesys Cloud platformclientv2.Facebookid object to a []interface{}
func flattenSdkFacebookId(facebookid *platformclientv2.Facebookid) []interface{} {
if facebookid == nil {
return nil
}

whatsappInterface := make(map[string]interface{})
flattenScopedid := flattenSdkFacebookScopedId(facebookid.Ids)
whatsappInterface["display_name"] = *facebookid.DisplayName
whatsappInterface["ids"] = &flattenScopedid
resourcedata.SetMapValueIfNotNil(whatsappInterface, "display_name", facebookid.DisplayName)
if flattenScopedId := flattenSdkFacebookScopedId(facebookid.Ids); flattenScopedId != nil {
whatsappInterface["ids"] = &flattenScopedId
}

return []interface{}{whatsappInterface}
}

// flattenSdkFacebookScopedId maps a Genesys Cloud platformclientv2.Facebookscopedid struct ot a []interface{}
func flattenSdkFacebookScopedId(facebookScopedid *[]platformclientv2.Facebookscopedid) []interface{} {
if facebookScopedid == nil || len(*facebookScopedid) == 0 {
return nil
}
facebookScopedidInterface := make(map[string]interface{})
if (*facebookScopedid)[0].ScopedId != nil {
facebookScopedidInterface["scoped_id"] = (*facebookScopedid)[0].ScopedId
Expand Down

0 comments on commit 0320015

Please sign in to comment.