From 4ba2903e45e030eeb5b7cb826ecd1308ea75346a Mon Sep 17 00:00:00 2001 From: Ken Kaizu Date: Thu, 29 Aug 2024 23:06:18 +0900 Subject: [PATCH] New resource: zoom_phone_external_contact (#41) Signed-off-by: krrrr38 --- docs/resources/phone_external_contact.md | 70 +++++ .../zoom_phone_external_contact/import.sh | 2 + .../zoom_phone_external_contact/provider.tf | 22 ++ .../zoom_phone_external_contact/resource.tf | 17 + generated/api/zoomphone/oas_json_gen.go | 19 +- generated/api/zoomphone/oas_schemas_gen.go | 13 + internal/provider/provider.go | 8 +- .../externalcontact/external_contact_crud.go | 118 +++++++ .../externalcontact/external_contact_dto.go | 43 +++ .../external_contact_resource.go | 294 ++++++++++++++++++ scripts/patchSpec.js | 9 + spec/ZoomPhoneAPISpec.json | 5 + 12 files changed, 616 insertions(+), 4 deletions(-) create mode 100644 docs/resources/phone_external_contact.md create mode 100644 examples/resources/zoom_phone_external_contact/import.sh create mode 100644 examples/resources/zoom_phone_external_contact/provider.tf create mode 100644 examples/resources/zoom_phone_external_contact/resource.tf create mode 100644 internal/services/phone/externalcontact/external_contact_crud.go create mode 100644 internal/services/phone/externalcontact/external_contact_dto.go create mode 100644 internal/services/phone/externalcontact/external_contact_resource.go diff --git a/docs/resources/phone_external_contact.md b/docs/resources/phone_external_contact.md new file mode 100644 index 0000000..f8214d0 --- /dev/null +++ b/docs/resources/phone_external_contact.md @@ -0,0 +1,70 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "zoom_phone_external_contact Resource - zoom" +subcategory: "" +description: |- + External contact's information. + API Permissions + The following API permissions are required in order to use this resource. + This resource requires the phone:read:external_contact:admin, phone:write:external_contact:admin, phone:update:external_contact:admin, phone:delete:external_contact:admin. +--- + +# zoom_phone_external_contact (Resource) + +External contact's information. + +## API Permissions +The following API permissions are required in order to use this resource. +This resource requires the `phone:read:external_contact:admin`, `phone:write:external_contact:admin`, `phone:update:external_contact:admin`, `phone:delete:external_contact:admin`. + +## Example Usage + +```terraform +resource "zoom_phone_external_contact" "example" { + id = "4gAYcVCwTUGGDpYWdFpXxx" + name = "Example" + description = "Description" + email = "example@example.com" + phone_numbers = [ + "+0123456789", + ] + auto_call_recorded = true +} + +resource "zoom_phone_external_contact" "other" { + name = "Other" + phone_numbers = [ + "+0123456789", + ] +} +``` + + +## Schema + +### Required + +- `name` (String) The external contact's username or extension display name. +- `phone_numbers` (Set of String) The external contact's phone numbers. This value must be in [E.164](https://en.wikipedia.org/wiki/E.164) format. If you do not provide an extension number, you must provide this value. + +### Optional + +- `auto_call_recorded` (Boolean) Whether to allow the automatic call recording. +- `description` (String) The external contact's description. +- `email` (String) The external contact's email address. +- `extension_number` (String) The external contact's extension number. +- `id` (String) The customer-configured external contact ID. It is recommended that you use a primary key from the original phone system. If you do not use this parameter, the API automatically generates an `external_contact_id`. +- `routing_path` (String) The external contact's SIP group, to define the call routing path. This is for customers that use SIP trunking. + +### Read-Only + +- `external_contact_id` (String) The Zoom-generated external contact ID. + +## Import + +Import is supported using the following syntax: + +```shell +# ${external_contact_id} +terraform import zoom_phone_external_contact.example lSq8jyDORe6tmbaUkOVhXx +``` diff --git a/examples/resources/zoom_phone_external_contact/import.sh b/examples/resources/zoom_phone_external_contact/import.sh new file mode 100644 index 0000000..cb93910 --- /dev/null +++ b/examples/resources/zoom_phone_external_contact/import.sh @@ -0,0 +1,2 @@ +# ${external_contact_id} +terraform import zoom_phone_external_contact.example lSq8jyDORe6tmbaUkOVhXx diff --git a/examples/resources/zoom_phone_external_contact/provider.tf b/examples/resources/zoom_phone_external_contact/provider.tf new file mode 100644 index 0000000..23b61ca --- /dev/null +++ b/examples/resources/zoom_phone_external_contact/provider.tf @@ -0,0 +1,22 @@ +terraform { + required_providers { + zoom = { + source = "folio-sec/zoom" + version = "~> 0.0.0" + } + } +} + +provider "zoom" { + account_id = var.zoom_account_id + client_id = var.zoom_client_id + client_secret = var.zoom_client_secret +} + +variable "zoom_account_id" {} + +variable "zoom_client_id" {} + +variable "zoom_client_secret" { + sensitive = true +} diff --git a/examples/resources/zoom_phone_external_contact/resource.tf b/examples/resources/zoom_phone_external_contact/resource.tf new file mode 100644 index 0000000..22e9a98 --- /dev/null +++ b/examples/resources/zoom_phone_external_contact/resource.tf @@ -0,0 +1,17 @@ +resource "zoom_phone_external_contact" "example" { + id = "4gAYcVCwTUGGDpYWdFpXxx" + name = "Example" + description = "Description" + email = "example@example.com" + phone_numbers = [ + "+0123456789", + ] + auto_call_recorded = true +} + +resource "zoom_phone_external_contact" "other" { + name = "Other" + phone_numbers = [ + "+0123456789", + ] +} diff --git a/generated/api/zoomphone/oas_json_gen.go b/generated/api/zoomphone/oas_json_gen.go index 442e620..6b7215d 100644 --- a/generated/api/zoomphone/oas_json_gen.go +++ b/generated/api/zoomphone/oas_json_gen.go @@ -25567,9 +25567,15 @@ func (s *GetAExternalContactOK) encodeFields(e *jx.Encoder) { s.AutoCallRecorded.Encode(e) } } + { + if s.RoutingPath.Set { + e.FieldStart("routing_path") + s.RoutingPath.Encode(e) + } + } } -var jsonFieldsNameOfGetAExternalContactOK = [8]string{ +var jsonFieldsNameOfGetAExternalContactOK = [9]string{ 0: "description", 1: "email", 2: "extension_number", @@ -25578,6 +25584,7 @@ var jsonFieldsNameOfGetAExternalContactOK = [8]string{ 5: "name", 6: "phone_numbers", 7: "auto_call_recorded", + 8: "routing_path", } // Decode decodes GetAExternalContactOK from json. @@ -25677,6 +25684,16 @@ func (s *GetAExternalContactOK) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"auto_call_recorded\"") } + case "routing_path": + if err := func() error { + s.RoutingPath.Reset() + if err := s.RoutingPath.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"routing_path\"") + } default: return d.Skip() } diff --git a/generated/api/zoomphone/oas_schemas_gen.go b/generated/api/zoomphone/oas_schemas_gen.go index ddf7493..56c0925 100644 --- a/generated/api/zoomphone/oas_schemas_gen.go +++ b/generated/api/zoomphone/oas_schemas_gen.go @@ -10776,6 +10776,9 @@ type GetAExternalContactOK struct { PhoneNumbers []string `json:"phone_numbers"` // Whether to allow the automatic call recording. AutoCallRecorded OptBool `json:"auto_call_recorded"` + // The external contact's SIP group, to define the call routing path. This is for customers that use + // SIP trunking. + RoutingPath OptString `json:"routing_path"` } // GetDescription returns the value of Description. @@ -10818,6 +10821,11 @@ func (s *GetAExternalContactOK) GetAutoCallRecorded() OptBool { return s.AutoCallRecorded } +// GetRoutingPath returns the value of RoutingPath. +func (s *GetAExternalContactOK) GetRoutingPath() OptString { + return s.RoutingPath +} + // SetDescription sets the value of Description. func (s *GetAExternalContactOK) SetDescription(val OptString) { s.Description = val @@ -10858,6 +10866,11 @@ func (s *GetAExternalContactOK) SetAutoCallRecorded(val OptBool) { s.AutoCallRecorded = val } +// SetRoutingPath sets the value of RoutingPath. +func (s *GetAExternalContactOK) SetRoutingPath(val OptString) { + s.RoutingPath = val +} + type GetASharedLineGroupOK struct { // The display name of the shared line group. DisplayName OptString `json:"display_name"` diff --git a/internal/provider/provider.go b/internal/provider/provider.go index a39f642..bff5042 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -18,10 +18,11 @@ import ( "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/callqueue" "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/callqueuemember" "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/callqueuephonenumber" + "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/externalcontact" "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/phonenumbers" - sharedlinegroupgroup "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/sharedlinegroup" - sharedlinegroupgroupmembers "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/sharedlinegroupmember" - sharedlinegroupgroupphonenumbers "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/sharedlinegroupphonenumber" + "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/sharedlinegroup" + "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/sharedlinegroupmember" + "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/sharedlinegroupphonenumber" phoneuser "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/user" "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/usercallingplans" "github.com/folio-sec/terraform-provider-zoom/internal/services/phone/userphonenumber" @@ -216,6 +217,7 @@ func (p *zoomProvider) Resources(_ context.Context) []func() resource.Resource { callqueue.NewPhoneCallQueueResource, callqueuemember.NewPhoneCallQueueMembersResource, callqueuephonenumber.NewPhoneCallQueuePhoneNumbersResource, + externalcontact.NewPhoneExternalContactResource, sharedlinegroupgroup.NewPhoneSharedLineGroupResource, sharedlinegroupgroupmembers.NewPhoneSharedLineGroupMembersResource, sharedlinegroupgroupphonenumbers.NewPhoneSharedLineGroupPhoneNumbersResource, diff --git a/internal/services/phone/externalcontact/external_contact_crud.go b/internal/services/phone/externalcontact/external_contact_crud.go new file mode 100644 index 0000000..b9d11f1 --- /dev/null +++ b/internal/services/phone/externalcontact/external_contact_crud.go @@ -0,0 +1,118 @@ +package externalcontact + +import ( + "context" + "errors" + "fmt" + "github.com/samber/lo" + + "github.com/folio-sec/terraform-provider-zoom/generated/api/zoomphone" + "github.com/folio-sec/terraform-provider-zoom/internal/util" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +func newCrud(client *zoomphone.Client) *crud { + return &crud{ + client: client, + } +} + +type crud struct { + client *zoomphone.Client +} + +func (c *crud) read(ctx context.Context, externalContactID types.String) (*readDto, error) { + detail, err := c.client.GetAExternalContact(ctx, zoomphone.GetAExternalContactParams{ + ExternalContactId: externalContactID.ValueString(), + }) + if err != nil { + var status *zoomphone.ErrorResponseStatusCode + if errors.As(err, &status) { + if status.StatusCode == 400 && status.Response.Code.Value == 300 { + return nil, nil // already deleted + } + } + return nil, fmt.Errorf("unable to read phone external contact: %v", err) + } + + return &readDto{ + description: util.FromOptString(detail.Description), + email: util.FromOptString(detail.Email), + extensionNumber: util.FromOptString(detail.ExtensionNumber), + externalContactID: util.FromOptString(detail.ExternalContactID), + id: util.FromOptString(detail.ID), + name: util.FromOptString(detail.Name), + phoneNumbers: lo.Map(detail.PhoneNumbers, func(item string, index int) types.String { + return types.StringValue(item) + }), + routingPath: util.FromOptString(detail.RoutingPath), + autoCallRecorded: util.FromOptBool(detail.AutoCallRecorded), + }, nil +} + +func (c *crud) create(ctx context.Context, dto *createDto) (*createdDto, error) { + res, err := c.client.AddExternalContact(ctx, zoomphone.OptAddExternalContactReq{ + Value: zoomphone.AddExternalContactReq{ + Description: util.ToPhoneOptString(dto.description), + Email: util.ToPhoneOptString(dto.email), + ExtensionNumber: util.ToPhoneOptString(dto.extensionNumber), + ID: util.ToPhoneOptString(dto.id), + Name: dto.name.ValueString(), + PhoneNumbers: lo.Map(dto.phoneNumbers, func(item types.String, index int) string { + return item.ValueString() + }), + RoutingPath: util.ToPhoneOptString(dto.routingPath), + AutoCallRecorded: util.ToPhoneOptBool(dto.autoCallRecorded), + }, + Set: true, + }) + if err != nil { + return nil, fmt.Errorf("error creating phone external contact: %v", err) + } + + return &createdDto{ + externalContactID: util.FromOptString(res.ExternalContactID), + }, nil +} + +func (c *crud) update(ctx context.Context, dto *updateDto) error { + err := c.client.UpdateExternalContact(ctx, zoomphone.OptUpdateExternalContactReq{ + Value: zoomphone.UpdateExternalContactReq{ + Description: util.ToPhoneOptString(dto.description), + Email: util.ToPhoneOptString(dto.email), + ExtensionNumber: util.ToPhoneOptString(dto.extensionNumber), + ID: util.ToPhoneOptString(dto.id), + Name: util.ToPhoneOptString(dto.name), + PhoneNumbers: lo.Map(dto.phoneNumbers, func(item types.String, index int) string { + return item.ValueString() + }), + RoutingPath: util.ToPhoneOptString(dto.routingPath), + AutoCallRecorded: util.ToPhoneOptBool(dto.autoCallRecorded), + }, + Set: true, + }, zoomphone.UpdateExternalContactParams{ + ExternalContactId: dto.externalContactID.ValueString(), + }) + if err != nil { + return fmt.Errorf("error updating phone external contact: %v", err) + } + + return nil +} + +func (c *crud) delete(ctx context.Context, externalContactId types.String) error { + err := c.client.DeleteAExternalContact(ctx, zoomphone.DeleteAExternalContactParams{ + ExternalContactId: externalContactId.ValueString(), + }) + if err != nil { + var status *zoomphone.ErrorResponseStatusCode + if errors.As(err, &status) { + if status.StatusCode == 400 && status.Response.Code.Value == 300 { + return nil + } + } + return fmt.Errorf("error deleting phone external contact: %v", err) + } + + return nil +} diff --git a/internal/services/phone/externalcontact/external_contact_dto.go b/internal/services/phone/externalcontact/external_contact_dto.go new file mode 100644 index 0000000..b184246 --- /dev/null +++ b/internal/services/phone/externalcontact/external_contact_dto.go @@ -0,0 +1,43 @@ +package externalcontact + +import "github.com/hashicorp/terraform-plugin-framework/types" + +type readDto struct { + description types.String + email types.String + extensionNumber types.String + externalContactID types.String + id types.String + name types.String + phoneNumbers []types.String + routingPath types.String + autoCallRecorded types.Bool +} + +type createDto struct { + description types.String + email types.String + extensionNumber types.String + externalContactID types.String + id types.String + name types.String + phoneNumbers []types.String + routingPath types.String + autoCallRecorded types.Bool +} + +type createdDto struct { + externalContactID types.String +} + +type updateDto struct { + externalContactID types.String + description types.String + email types.String + extensionNumber types.String + id types.String + name types.String + phoneNumbers []types.String + routingPath types.String + autoCallRecorded types.Bool +} diff --git a/internal/services/phone/externalcontact/external_contact_resource.go b/internal/services/phone/externalcontact/external_contact_resource.go new file mode 100644 index 0000000..48b0819 --- /dev/null +++ b/internal/services/phone/externalcontact/external_contact_resource.go @@ -0,0 +1,294 @@ +package externalcontact + +import ( + "context" + "fmt" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "strings" + + "github.com/folio-sec/terraform-provider-zoom/internal/provider/shared" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +var ( + _ resource.Resource = &tfResource{} + _ resource.ResourceWithConfigure = &tfResource{} + _ resource.ResourceWithImportState = &tfResource{} +) + +func NewPhoneExternalContactResource() resource.Resource { + return &tfResource{} +} + +type tfResource struct { + crud *crud +} + +func (r *tfResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + data, ok := req.ProviderData.(*shared.ProviderData) + if !ok { + resp.Diagnostics.AddError( + "Unexpected ProviderData Source Configure Type", + fmt.Sprintf("Expected *provider.ProviderData, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + r.crud = newCrud(data.PhoneClient) +} + +func (r *tfResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_phone_external_contact" +} + +func (r *tfResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: `External contact's information. + +## API Permissions +The following API permissions are required in order to use this resource. +This resource requires the ` + strings.Join([]string{ + "`phone:read:external_contact:admin`", + "`phone:write:external_contact:admin`", + "`phone:update:external_contact:admin`", + "`phone:delete:external_contact:admin`", + }, ", ") + ".", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The customer-configured external contact ID. It is recommended that you use a primary key from the original phone system. If you do not use this parameter, the API automatically generates an `external_contact_id`.", + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, + "name": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthAtMost(255), + }, + MarkdownDescription: "The external contact's username or extension display name.", + }, + "description": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The external contact's description.", + }, + "extension_number": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The external contact's extension number.", + }, + "email": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtMost(255), + }, + MarkdownDescription: "The external contact's email address.", + }, + "phone_numbers": schema.SetAttribute{ + ElementType: types.StringType, + Required: true, + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), + }, + MarkdownDescription: "The external contact's phone numbers. This value must be in [E.164](https://en.wikipedia.org/wiki/E.164) format. If you do not provide an extension number, you must provide this value.", + }, + "auto_call_recorded": schema.BoolAttribute{ + Computed: true, + Optional: true, + Default: booldefault.StaticBool(false), + MarkdownDescription: "Whether to allow the automatic call recording.", + }, + "external_contact_id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The Zoom-generated external contact ID.", + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, + "routing_path": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The external contact's SIP group, to define the call routing path. This is for customers that use SIP trunking.", + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, + }, + } +} + +type resourceModel struct { + ID types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + ExtensionNumber types.String `tfsdk:"extension_number"` + Email types.String `tfsdk:"email"` + PhoneNumbers []types.String `tfsdk:"phone_numbers"` + AutoCallRecorded types.Bool `tfsdk:"auto_call_recorded"` + ExternalContactID types.String `tfsdk:"external_contact_id"` + RoutingPath types.String `tfsdk:"routing_path"` +} + +func (r *tfResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state resourceModel + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + output, err := r.read(ctx, state.ExternalContactID) + if err != nil { + resp.Diagnostics.AddError("Error reading phone external contact", err.Error()) + return + } + + diags = resp.State.Set(ctx, &output) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *tfResource) read(ctx context.Context, externalContactID types.String) (*resourceModel, error) { + dto, err := r.crud.read(ctx, externalContactID) + if err != nil { + return nil, fmt.Errorf("error read: %v", err) + } + if dto == nil { + return nil, nil // already deleted + } + + return &resourceModel{ + ID: dto.id, + Name: dto.name, + Description: dto.description, + ExtensionNumber: dto.extensionNumber, + Email: dto.email, + PhoneNumbers: dto.phoneNumbers, + AutoCallRecorded: dto.autoCallRecorded, + ExternalContactID: dto.externalContactID, + RoutingPath: dto.routingPath, + }, nil +} + +func (r *tfResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan resourceModel + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + ret, err := r.crud.create(ctx, &createDto{ + description: plan.Description, + email: plan.Email, + extensionNumber: plan.ExtensionNumber, + externalContactID: plan.ExternalContactID, + id: plan.ID, + name: plan.Name, + phoneNumbers: plan.PhoneNumbers, + routingPath: plan.RoutingPath, + autoCallRecorded: plan.AutoCallRecorded, + }) + if err != nil { + resp.Diagnostics.AddError( + "Error creating phone external contact", + err.Error(), + ) + return + } + + output, err := r.read(ctx, ret.externalContactID) + if err != nil { + resp.Diagnostics.AddError("Error creating phone external contact on reading", err.Error()) + return + } + + diags = resp.State.Set(ctx, output) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *tfResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan resourceModel + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + resp.Diagnostics.AddError( + "Error updating phone external contact", + "Error updating phone external contact", + ) + return + } + + if err := r.crud.update(ctx, &updateDto{ + externalContactID: plan.ExternalContactID, + description: plan.Description, + email: plan.Email, + extensionNumber: plan.ExtensionNumber, + id: plan.ID, + name: plan.Name, + phoneNumbers: plan.PhoneNumbers, + routingPath: plan.RoutingPath, + autoCallRecorded: plan.AutoCallRecorded, + }); err != nil { + resp.Diagnostics.AddError( + "Error updating phone external contact", + fmt.Sprintf( + "Could not update phone external contact %s, unexpected error: %s", + plan.ID.ValueString(), + err, + ), + ) + return + } + + output, err := r.read(ctx, plan.ExternalContactID) + if err != nil { + resp.Diagnostics.AddError("Error updating phone external contact", err.Error()) + return + } + + diags = resp.State.Set(ctx, output) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *tfResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state resourceModel + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if err := r.crud.delete(ctx, state.ExternalContactID); err != nil { + resp.Diagnostics.AddError( + "Error deleting phone external contact", + fmt.Sprintf( + "Could not delete phone external contact %s, unexpected error: %s", + state.ID.ValueString(), + err, + ), + ) + return + } + + tflog.Info(ctx, "deleted phone external contact", map[string]interface{}{ + "external_contact_id": state.ExternalContactID.ValueString(), + }) +} + +func (r *tfResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("external_contact_id"), req, resp) +} diff --git a/scripts/patchSpec.js b/scripts/patchSpec.js index 7086bb4..fa9bb74 100755 --- a/scripts/patchSpec.js +++ b/scripts/patchSpec.js @@ -338,6 +338,15 @@ function phonePatch(spec) { } } + // GET /phone/external_contacts/{externalContactId} should have routing_path response body + if (spec.paths['/phone/external_contacts/{externalContactId}']) { + spec.paths['/phone/external_contacts/{externalContactId}']['get']['responses']['200']['content']['application/json']['schema']['properties']['routing_path'] = { + type: "string", + description: "The external contact's SIP group, to define the call routing path. This is for customers that use SIP trunking.", + example: "PSTN" + }; + } + // GET PATCH /phone/users/{userId} should have calling_plans[].name property if (spec.paths['/phone/users/{userId}']) { spec.paths['/phone/users/{userId}']['get']['responses']['200']['content']['application/json']['schema']['properties']['calling_plans']['items']['properties']['name'] = { diff --git a/spec/ZoomPhoneAPISpec.json b/spec/ZoomPhoneAPISpec.json index 64cc304..ac122e6 100644 --- a/spec/ZoomPhoneAPISpec.json +++ b/spec/ZoomPhoneAPISpec.json @@ -18160,6 +18160,11 @@ "type": "boolean", "description": "Whether to allow the automatic call recording.", "example": true + }, + "routing_path": { + "type": "string", + "description": "The external contact's SIP group, to define the call routing path. This is for customers that use SIP trunking.", + "example": "PSTN" } } }