diff --git a/__tests__/services/sunshine-conversation-api-service.spec.ts b/__tests__/services/sunshine-conversation-api-service.spec.ts index 572bf07..34f2817 100644 --- a/__tests__/services/sunshine-conversation-api-service.spec.ts +++ b/__tests__/services/sunshine-conversation-api-service.spec.ts @@ -6,6 +6,7 @@ import { Capabilities, IAuthor, IContent, + IIntegrationSuncoTwilio, IIntegrationWhatsApp, ISendNotificationPayload, IServiceConfig, @@ -473,21 +474,19 @@ describe("SunshineConversationApiService", () => { } }; + const notification: IIntegrationSuncoTwilio = { + id: "id", + status: "status", + "type": UserChannelTypes.Twilio, + accountSid: "accountSid", + phoneNumberSid: "phoneNumberSid", + messagingServiceSid: "messagingServiceSid", + displayName: "Twilio", + phoneNumber: "+12345678900" + }; + // Sending twilio notification - await sunshineConversationApiService.sendNotification( - { - id: "id", - status: "status", - "type": UserChannelTypes.Twilio, - accountSid: "accountSid", - phoneNumberSid: "phoneNumberSid", - messagingServiceSid: "messagingServiceSid", - displayName: "Twilio", - phoneNumber: "+12345678900" - }, - phoneNumberSample, - contentSample - ); + await sunshineConversationApiService.sendNotification(notification, phoneNumberSample, contentSample); expect(client.request).toHaveBeenCalledWith(options); }); diff --git a/__tests__/services/zendesk-api-service.spec.ts b/__tests__/services/zendesk-api-service.spec.ts index e1c4606..fe18f20 100644 --- a/__tests__/services/zendesk-api-service.spec.ts +++ b/__tests__/services/zendesk-api-service.spec.ts @@ -439,6 +439,43 @@ describe("ZendeskService", () => { expect(result).toEqual(locales); }); }); + + describe("getVoiceLines", () => { + it("should call the API and return the voice lines", async () => { + const lines = [{ name: "line1" }]; + requestMock.mockResolvedValueOnce({ lines }); + + const result = await service.getVoiceLines(); + + expect(requestMock).toHaveBeenCalledWith(`/api/v2/channels/voice/lines`); + expect(result).toEqual(lines); + }); + + it("should continue calling the API until next_page disappears", async () => { + const lines = [{ name: "line1" }]; + requestMock + .mockResolvedValueOnce({ lines, next_page: "next_page" }) + .mockResolvedValueOnce({ lines: [] }); + + const result = await service.getVoiceLines(); + + expect(requestMock).toHaveBeenCalledTimes(2); + expect(requestMock).toHaveBeenNthCalledWith(1, `/api/v2/channels/voice/lines`); + expect(requestMock).toHaveBeenNthCalledWith(2, "next_page"); + expect(result).toEqual(lines); + }); + + it("should only call the API one time with fetchAllLines set to false", async () => { + const lines = [{ name: "line1" }]; + requestMock.mockResolvedValueOnce({ lines, next_page: "next_page" }); + + const result = await service.getVoiceLines(false); + + expect(requestMock).toHaveBeenCalledTimes(1); + expect(requestMock).toHaveBeenCalledWith(`/api/v2/channels/voice/lines`); + expect(result).toEqual(lines); + }); + }); }); }); }); diff --git a/package.json b/package.json index 1874022..23edcd0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zendesk/zaf-toolbox", - "version": "0.2.12", + "version": "0.3.0", "description": "A toolbox for ZAF application built with 🩷 by Zendesk Labs", "main": "lib/src/index.js", "types": "lib/src/index.d.ts", diff --git a/src/models/sunshine-conversation.ts b/src/models/sunshine-conversation.ts index 1767e08..c6582a6 100644 --- a/src/models/sunshine-conversation.ts +++ b/src/models/sunshine-conversation.ts @@ -432,7 +432,7 @@ export type IIntegration = | IIntegrationIos | IIntegrationMessageBirds | IIntegrationMessenger - | IIntegrationTwillio + | IIntegrationTwilio | IIntegrationTwitter | IIntegrationWeb | IIntegrationWhatsApp @@ -548,8 +548,18 @@ export interface IIntegrationMessenger extends IIntegrationBase { pageName?: string; } -export interface IIntegrationTwillio extends IIntegrationBase { +export interface IIntegrationTwilio extends IIntegrationBase { type: UserChannelTypes.Twilio; + phoneNumber: string; + isTalk?: boolean; +} + +export interface IIntegrationTwilioTalk extends IIntegrationTwilio { + sms: boolean; + mms: boolean; +} + +export interface IIntegrationSuncoTwilio extends IIntegrationTwilio { /** * Twilio Account SID. */ @@ -558,7 +568,6 @@ export interface IIntegrationTwillio extends IIntegrationBase { * SID for specific phone number. One of messagingServiceSid or phoneNumberSid must be provided when creating a Twilio integration */ phoneNumberSid: string; - phoneNumber: string; /** * SID for specific messaging service. One of messagingServiceSid or phoneNumberSid must be provided when creating a Twilio integration. */ diff --git a/src/models/zendesk-api.ts b/src/models/zendesk-api.ts index 7121852..97fa907 100644 --- a/src/models/zendesk-api.ts +++ b/src/models/zendesk-api.ts @@ -54,6 +54,63 @@ export interface IOrganizationsResults extends IZendeskResponse { organizations: IZendeskOrganizations[]; } +export interface ILinesResults extends IZendeskResponse { + lines: Line[]; +} + +export interface LineBase { + id: number; + nickname: string; + priority: number; + default_group_id: number | null; + line_type: string; + transcription: boolean; + recorded: boolean; + call_recording_consent: string; + group_ids: number[]; + greeting_ids: string[]; + default_greeting_ids: string[]; + categorised_greetings_with_sub_settings: Record>; + schedule_id: number | null; + created_at: string; +} + +export interface DigitalLine extends LineBase { + line_type: "digital"; + brand_id: number; + line_id: string; + outbound_number: string | null; +} + +export interface PhoneLine extends LineBase { + line_type: "phone"; + country_code: string; + external: boolean; + // eslint-disable-next-line id-denylist + number: string; + name: string; + display_number: string; + location: string; + toll_free: boolean; + categorised_greetings: Record; + sms_group_id: number | null; + capabilities: Capabilities; + sms_enabled: boolean; + voice_enabled: boolean; + outbound_enabled: boolean; + ivr_id: number | null; + failover_number: string | null; +} + +interface Capabilities { + sms: boolean; + mms: boolean; + voice: boolean; + emergency_address: boolean; +} + +export type Line = DigitalLine | PhoneLine; + export interface ILocalesResults { locales: IZendeskLocale[]; } diff --git a/src/services/zendesk-api-service.ts b/src/services/zendesk-api-service.ts index 40a6012..11655aa 100644 --- a/src/services/zendesk-api-service.ts +++ b/src/services/zendesk-api-service.ts @@ -18,7 +18,10 @@ import { IZendeskTag, IZendeskLocale, IZendeskGroup, - IZendeskOrganizations + IZendeskOrganizations, + ILinesResults, + IZendeskResponse, + LineBase } from "@models/index"; import { convertContentMessageToHtml } from "@utils/convert-content-message-to-html"; import { getFromClient } from "@utils/get-from-client"; @@ -40,16 +43,15 @@ export class ZendeskApiService { * @param extractArrayFn Function to extract the array of items from the response. * @returns A promise resolving to a flattened array of all items. */ - private async fetchAllPaginatedResults( + private async fetchAllPaginatedResults( url: string, fetchAll: boolean, extractArrayFn: (response: TResponse) => TItem[] ): Promise { const results: TResponse[] = [await this.client.request(url)]; - if (fetchAll) { while (true) { - const nextPage = (results[results.length - 1] as TResponse & { next_page?: string }).next_page; + const nextPage = results[results.length - 1].next_page; if (!nextPage) break; results.push(await this.client.request(nextPage)); } @@ -253,4 +255,15 @@ export class ZendeskApiService { return results.locales; } + + /** + * Fetch all voice lines + */ + public async getVoiceLines(fetchAllLines = true): Promise { + return this.fetchAllPaginatedResults( + `/api/v2/channels/voice/lines`, + fetchAllLines, + (response) => response.lines + ); + } }