diff --git a/pagerduty/resource_pagerduty_user_contact_method.go b/pagerduty/resource_pagerduty_user_contact_method.go index 36a5a34de..14fec0fc6 100644 --- a/pagerduty/resource_pagerduty_user_contact_method.go +++ b/pagerduty/resource_pagerduty_user_contact_method.go @@ -23,19 +23,7 @@ func resourcePagerDutyUserContactMethod() *schema.Resource { Importer: &schema.ResourceImporter{ State: resourcePagerDutyUserContactMethodImport, }, - CustomizeDiff: func(context context.Context, diff *schema.ResourceDiff, i interface{}) error { - a := diff.Get("address").(string) - t := diff.Get("type").(string) - if t == "sms_contact_method" || t == "phone_contact_method" { - if strings.HasPrefix(a, "0") { - return fmt.Errorf("phone numbers starting with a 0 are not supported was %q", a) - } - if _, err := strconv.Atoi(a); err != nil { - return fmt.Errorf("phone number %q is not valid as it contains non-digit characters: %w", a, err) - } - } - return nil - }, + CustomizeDiff: customizeDiffResourceUserContactMethod, Schema: map[string]*schema.Schema{ "user_id": { Type: schema.TypeString, @@ -88,6 +76,47 @@ func resourcePagerDutyUserContactMethod() *schema.Resource { } } +func customizeDiffResourceUserContactMethod(context context.Context, diff *schema.ResourceDiff, i interface{}) error { + a := diff.Get("address").(string) + t := diff.Get("type").(string) + c := diff.Get("country_code").(int) + + if t == "sms_contact_method" || t == "phone_contact_method" { + // Validation logic based on https://support.pagerduty.com/docs/user-profile#phone-number-formatting + maxLength := 40 + if len(a) > maxLength { + return fmt.Errorf("phone numbers may not exceed 40 characters") + } + for _, char := range a { + isAllowedChar := char == ',' || char == '*' || char == '#' + if _, err := strconv.ParseInt(string(char), 10, 64); err != nil && !isAllowedChar { + return fmt.Errorf("phone numbers may only include digits from 0-9 and the symbols: comma (,), asterisk (*), and pound (#)") + } + } + + isMexicoNumber := c == 52 + if t == "sms_contact_method" && isMexicoNumber && strings.HasPrefix(a, "1") { + return fmt.Errorf("Mexico-based SMS numbers should be free of area code prefixes, so please remove the leading 1 in the number %q", a) + } + + isTrunkPrefixNotSupported := map[int]string{ + 33: "0", // France (33-0) + 40: "0", // Romania (40-0) + 44: "0", // UK (44-0) + 45: "0", // Denmark (45-0) + 49: "0", // Germany (49-0) + 61: "0", // Australia (61-0) + 66: "0", // Thailand (66-0) + 91: "0", // India (91-0) + 1: "1", // North America (1-1) + } + if prefix, ok := isTrunkPrefixNotSupported[c]; ok && strings.HasPrefix(a, prefix) { + return fmt.Errorf("Trunk prefixes are not supported for following countries and regions: France, Romania, UK, Denmark, Germany, Australia, Thailand, India and North America, so must be formatted for international use without the leading %s", prefix) + } + } + return nil +} + func buildUserContactMethodStruct(d *schema.ResourceData) *pagerduty.ContactMethod { contactMethod := &pagerduty.ContactMethod{ Type: d.Get("type").(string), diff --git a/pagerduty/resource_pagerduty_user_contact_method_test.go b/pagerduty/resource_pagerduty_user_contact_method_test.go index 3e3574779..9806e3863 100644 --- a/pagerduty/resource_pagerduty_user_contact_method_test.go +++ b/pagerduty/resource_pagerduty_user_contact_method_test.go @@ -68,6 +68,40 @@ func TestAccPagerDutyUserContactMethodPhone_Basic(t *testing.T) { }) } +func TestAccPagerDutyUserContactMethodPhone_FormatValidation(t *testing.T) { + username := fmt.Sprintf("tf-%s", acctest.RandString(5)) + email := fmt.Sprintf("%s@foo.test", username) + tooLongNumber := "4153013250415301325041530132504153013250,415301325041530132504,530132504153013250" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyUserContactMethodDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyUserContactMethodPhoneFormatValidationConfig(username, email, "phone_contact_method", "1", tooLongNumber), + PlanOnly: true, + ExpectError: regexp.MustCompile("phone numbers may not exceed 40 characters"), + }, + { + Config: testAccCheckPagerDutyUserContactMethodPhoneFormatValidationConfig(username, email, "phone_contact_method", "1", "+4153013250"), + PlanOnly: true, + ExpectError: regexp.MustCompile("phone numbers may only include digits from 0-9 and the symbols"), + }, + { + Config: testAccCheckPagerDutyUserContactMethodPhoneFormatValidationConfig(username, email, "phone_contact_method", "44", "01332412251"), + PlanOnly: true, + ExpectError: regexp.MustCompile("Trunk prefixes are not supported for following countries and regions: France, Romania, UK, Denmark, Germany, Australia, Thailand, India and North America, so must be formatted for international use without the leading 0"), + }, + { + Config: testAccCheckPagerDutyUserContactMethodPhoneFormatValidationConfig(username, email, "sms_contact_method", "52", "15558889999"), + PlanOnly: true, + ExpectError: regexp.MustCompile("Mexico-based SMS numbers should be free of area code prefixes, so please remove the leading 1 in the number"), + }, + }, + }) +} + func TestAccPagerDutyUserContactMethodPhone_EnforceUpdateIfAlreadyExist(t *testing.T) { username := fmt.Sprintf("tf-%s", acctest.RandString(5)) email := fmt.Sprintf("%s@foo.test", username) @@ -281,6 +315,27 @@ resource "pagerduty_user_contact_method" "foo" { `, username, email, phone) } +func testAccCheckPagerDutyUserContactMethodPhoneFormatValidationConfig(username, email, method_type, countryCode, phone string) string { + return fmt.Sprintf(` +resource "pagerduty_user" "foo" { + name = "%[1]v" + email = "%[2]v" + color = "red" + role = "user" + job_title = "bar" + description = "bar" +} + +resource "pagerduty_user_contact_method" "foo" { + user_id = pagerduty_user.foo.id + type = "%[3]s" + country_code = "+%[4]s" + address = "%[5]s" + label = "%[1]v" +} +`, username, email, method_type, countryCode, phone) +} + func testAccCheckPagerDutyUserContactMethodSMSConfig(username, email string) string { return fmt.Sprintf(` resource "pagerduty_user" "foo" {