From b0aee49b5c46cb77f260144ed8ced8698e8a6eb4 Mon Sep 17 00:00:00 2001 From: victor langat Date: Thu, 16 Jan 2025 22:01:34 +0300 Subject: [PATCH] feat(gorgias): implement gorgias user provisioning using only the necessary User fields and add corresponding tests: Actions: - Create user - Delete user with id Syncs - List Users --- flows.yaml | 55 ++++++++++++++++ integrations/gorgias/actions/create-user.md | 53 +++++++++++++++ integrations/gorgias/actions/create-user.ts | 52 +++++++++++++++ integrations/gorgias/actions/delete-user.md | 46 +++++++++++++ integrations/gorgias/actions/delete-user.ts | 30 +++++++++ .../gorgias/fixtures/create-user.json | 6 ++ .../gorgias/fixtures/delete-user.json | 3 + .../gorgias/mocks/create-user/input.json | 6 ++ .../gorgias/mocks/create-user/output.json | 6 ++ .../gorgias/mocks/delete-user/input.json | 3 + .../gorgias/mocks/delete-user/output.json | 3 + ...1b3ef41998ebf4ba8bbdc07e5a0e661de7173.json | 36 ++++++++++ ...d1de4b5f46d6b29659d53227eab98bb2f2729.json | 36 ++++++++++ ...d13300a8b792236860fa99c4bedeeaed97cab.json | 65 +++++++++++++++++++ integrations/gorgias/nango.yaml | 53 +++++++++++++++ integrations/gorgias/schema.zod.ts | 34 ++++++++++ integrations/gorgias/syncs/users.md | 49 ++++++++++++++ integrations/gorgias/syncs/users.ts | 40 ++++++++++++ .../gorgias/tests/gorgias-create-user.test.ts | 19 ++++++ .../gorgias/tests/gorgias-delete-user.test.ts | 19 ++++++ integrations/gorgias/types.ts | 23 +++++++ 21 files changed, 637 insertions(+) create mode 100644 integrations/gorgias/actions/create-user.md create mode 100644 integrations/gorgias/actions/create-user.ts create mode 100644 integrations/gorgias/actions/delete-user.md create mode 100644 integrations/gorgias/actions/delete-user.ts create mode 100644 integrations/gorgias/fixtures/create-user.json create mode 100644 integrations/gorgias/fixtures/delete-user.json create mode 100644 integrations/gorgias/mocks/create-user/input.json create mode 100644 integrations/gorgias/mocks/create-user/output.json create mode 100644 integrations/gorgias/mocks/delete-user/input.json create mode 100644 integrations/gorgias/mocks/delete-user/output.json create mode 100644 integrations/gorgias/mocks/nango/delete/proxy/api/users/454003867/delete-user/4541b3ef41998ebf4ba8bbdc07e5a0e661de7173.json create mode 100644 integrations/gorgias/mocks/nango/delete/proxy/api/users/455843658/delete-user/7dcd1de4b5f46d6b29659d53227eab98bb2f2729.json create mode 100644 integrations/gorgias/mocks/nango/post/proxy/api/users/create-user/04dd13300a8b792236860fa99c4bedeeaed97cab.json create mode 100644 integrations/gorgias/syncs/users.md create mode 100644 integrations/gorgias/syncs/users.ts create mode 100644 integrations/gorgias/tests/gorgias-create-user.test.ts create mode 100644 integrations/gorgias/tests/gorgias-delete-user.test.ts diff --git a/flows.yaml b/flows.yaml index b715b453d..7cb10ecfb 100644 --- a/flows.yaml +++ b/flows.yaml @@ -4431,6 +4431,19 @@ integrations: path: /tickets group: Tickets version: 1.0.1 + users: + description: | + Fetches the list of users + endpoint: + method: GET + path: /users + group: Users + sync_type: full + track_deletes: true + runs: every 6 hours + output: GorgiasUser + scopes: + - users:read actions: create-ticket: description: | @@ -4446,7 +4459,35 @@ integrations: path: /ticket group: Tickets output: Ticket + create-user: + description: > + Creates a new user with a role in Gorgias. Defaults to agent if a role + is not provided + input: GorgiasCreateUser + output: GorgiasUser + endpoint: + method: POST + path: /user + group: Users + scopes: + - users:write + delete-user: + description: Deletes a user in Gorgias + output: SuccessResponse + input: IdEntity + endpoint: + method: DELETE + path: /users + group: Users + scopes: + - users:write models: + IdEntity: + id: string + SuccessResponse: + success: boolean + ActionResponseError: + message: string Ticket: id: number assignee_user: AssigneeUser | null @@ -4578,6 +4619,20 @@ integrations: body_html: string body_text: string id: string + CreateUser: + firstName: string + lastName: string + email: string + GorgiasCreateUser: + firstName: string + lastName: string + email: string + role: admin | agent | basic-agent | lite-agent | observer-agent + GorgiasUser: + id: string + firstName: string + lastName: string + email: string greenhouse-basic: syncs: applications: diff --git a/integrations/gorgias/actions/create-user.md b/integrations/gorgias/actions/create-user.md new file mode 100644 index 000000000..124c483b9 --- /dev/null +++ b/integrations/gorgias/actions/create-user.md @@ -0,0 +1,53 @@ + +# Create User + +## General Information + +- **Description:** Creates a new user with a role in Gorgias. Defaults to agent if a role is not provided + +- **Version:** 0.0.1 +- **Group:** Users +- **Scopes:** `users:write` +- **Endpoint Type:** Action +- **Code:** [github.com](https://github.com/NangoHQ/integration-templates/tree/main/integrations/gorgias/actions/create-user.ts) + + +## Endpoint Reference + +### Request Endpoint + +`POST /user` + +### Request Query Parameters + +_No request parameters_ + +### Request Body + +```json +{ + "firstName": "", + "lastName": "", + "email": "", + "role": "" +} +``` + +### Request Response + +```json +{ + "id": "", + "firstName": "", + "lastName": "", + "email": "" +} +``` + +## Changelog + +- [Script History](https://github.com/NangoHQ/integration-templates/commits/main/integrations/gorgias/actions/create-user.ts) +- [Documentation History](https://github.com/NangoHQ/integration-templates/commits/main/integrations/gorgias/actions/create-user.md) + + + diff --git a/integrations/gorgias/actions/create-user.ts b/integrations/gorgias/actions/create-user.ts new file mode 100644 index 000000000..5edb1b218 --- /dev/null +++ b/integrations/gorgias/actions/create-user.ts @@ -0,0 +1,52 @@ +import type { NangoAction, ProxyConfiguration, GorgiasCreateUser, GorgiasUser } from '../../models'; +import { gorgiasCreateUserSchema } from '../schema.zod.js'; +import type { GorgiasCreateUserReq, GorgiasUserResponse } from '../types'; + +/** + * Creates a new user in Gorgias. + * + * @param {NangoAction} nango - The Nango action instance. + * @param {GorgiasCreateUser} input - The input data for creating a user. + * @returns {Promise} - A promise that resolves to the created Gorgias user. + * @throws {nango.ActionError} - Throws an error if the input validation fails. + */ +export default async function runAction(nango: NangoAction, input: GorgiasCreateUser): Promise { + const parsedInput = gorgiasCreateUserSchema.safeParse(input); + + if (!parsedInput.success) { + for (const error of parsedInput.error.errors) { + await nango.log(`Invalid input provided to create a user: ${error.message} at path ${error.path.join('.')}`, { level: 'error' }); + } + throw new nango.ActionError({ + message: 'Invalid input provided to create a user' + }); + } + + const data: GorgiasCreateUserReq = { + name: `${parsedInput.data.firstName} ${parsedInput.data.lastName}`, + email: parsedInput.data.email.toLowerCase(), + role: { + name: parsedInput.data.role || 'agent' + } + }; + + const config: ProxyConfiguration = { + // https://developers.gorgias.com/reference/create-user + endpoint: '/api/users', + retries: 10, + data + }; + + const response = await nango.post(config); + + const { data: dataResponse } = response; + + const user: GorgiasUser = { + id: dataResponse.id.toString(), + firstName: dataResponse.name.split(' ')[0] || '', + lastName: dataResponse.name.split(' ')[1] || '', + email: dataResponse.email + }; + + return user; +} diff --git a/integrations/gorgias/actions/delete-user.md b/integrations/gorgias/actions/delete-user.md new file mode 100644 index 000000000..96c02518c --- /dev/null +++ b/integrations/gorgias/actions/delete-user.md @@ -0,0 +1,46 @@ + +# Delete User + +## General Information + +- **Description:** Deletes a user in Gorgias +- **Version:** 0.0.1 +- **Group:** Users +- **Scopes:** `users:write` +- **Endpoint Type:** Action +- **Code:** [github.com](https://github.com/NangoHQ/integration-templates/tree/main/integrations/gorgias/actions/delete-user.ts) + + +## Endpoint Reference + +### Request Endpoint + +`DELETE /users` + +### Request Query Parameters + +_No request parameters_ + +### Request Body + +```json +{ + "id": "" +} +``` + +### Request Response + +```json +{ + "success": "" +} +``` + +## Changelog + +- [Script History](https://github.com/NangoHQ/integration-templates/commits/main/integrations/gorgias/actions/delete-user.ts) +- [Documentation History](https://github.com/NangoHQ/integration-templates/commits/main/integrations/gorgias/actions/delete-user.md) + + + diff --git a/integrations/gorgias/actions/delete-user.ts b/integrations/gorgias/actions/delete-user.ts new file mode 100644 index 000000000..2403b1e14 --- /dev/null +++ b/integrations/gorgias/actions/delete-user.ts @@ -0,0 +1,30 @@ +import type { NangoAction, ProxyConfiguration, SuccessResponse, IdEntity } from '../../models'; + +/** + * Deletes a user based on the provided email address. + * + * @param {NangoAction} nango - The Nango action instance. + * @param {EmailEntity} input - The input containing the email of the user to be deleted. + * @throws {nango.ActionError} - Throws an error if the email is not provided. + * + * {@link https://developers.gorgias.com/reference/delete-user} for more information on the Gorgias API endpoint. + */ +export default async function runAction(nango: NangoAction, input: IdEntity): Promise { + if (!input.id) { + throw new nango.ActionError({ + message: 'Id is required to delete a user' + }); + } + + const config: ProxyConfiguration = { + // https://developers.gorgias.com/reference/delete-user + endpoint: `/api/users/${input.id}`, + retries: 10 + }; + + await nango.delete(config); + + return { + success: true + }; +} diff --git a/integrations/gorgias/fixtures/create-user.json b/integrations/gorgias/fixtures/create-user.json new file mode 100644 index 000000000..51639f33f --- /dev/null +++ b/integrations/gorgias/fixtures/create-user.json @@ -0,0 +1,6 @@ +{ + "email": "Johndo2l@testdomain.tld", + "firstName": "John", + "lastName": "Doe", + "role": "agent" +} diff --git a/integrations/gorgias/fixtures/delete-user.json b/integrations/gorgias/fixtures/delete-user.json new file mode 100644 index 000000000..bcc3f75a8 --- /dev/null +++ b/integrations/gorgias/fixtures/delete-user.json @@ -0,0 +1,3 @@ +{ + "id": "455843658" +} diff --git a/integrations/gorgias/mocks/create-user/input.json b/integrations/gorgias/mocks/create-user/input.json new file mode 100644 index 000000000..51639f33f --- /dev/null +++ b/integrations/gorgias/mocks/create-user/input.json @@ -0,0 +1,6 @@ +{ + "email": "Johndo2l@testdomain.tld", + "firstName": "John", + "lastName": "Doe", + "role": "agent" +} diff --git a/integrations/gorgias/mocks/create-user/output.json b/integrations/gorgias/mocks/create-user/output.json new file mode 100644 index 000000000..084246f27 --- /dev/null +++ b/integrations/gorgias/mocks/create-user/output.json @@ -0,0 +1,6 @@ +{ + "id": "455925547", + "firstName": "John", + "lastName": "Doe", + "email": "johndo2l@testdomain.tld" +} diff --git a/integrations/gorgias/mocks/delete-user/input.json b/integrations/gorgias/mocks/delete-user/input.json new file mode 100644 index 000000000..7041e1aee --- /dev/null +++ b/integrations/gorgias/mocks/delete-user/input.json @@ -0,0 +1,3 @@ +{ + "id": 455843658 +} diff --git a/integrations/gorgias/mocks/delete-user/output.json b/integrations/gorgias/mocks/delete-user/output.json new file mode 100644 index 000000000..33c0c847e --- /dev/null +++ b/integrations/gorgias/mocks/delete-user/output.json @@ -0,0 +1,3 @@ +{ + "success": true +} diff --git a/integrations/gorgias/mocks/nango/delete/proxy/api/users/454003867/delete-user/4541b3ef41998ebf4ba8bbdc07e5a0e661de7173.json b/integrations/gorgias/mocks/nango/delete/proxy/api/users/454003867/delete-user/4541b3ef41998ebf4ba8bbdc07e5a0e661de7173.json new file mode 100644 index 000000000..37c1cdf0c --- /dev/null +++ b/integrations/gorgias/mocks/nango/delete/proxy/api/users/454003867/delete-user/4541b3ef41998ebf4ba8bbdc07e5a0e661de7173.json @@ -0,0 +1,36 @@ +{ + "method": "delete", + "endpoint": "api/users/454003867", + "requestIdentityHash": "4541b3ef41998ebf4ba8bbdc07e5a0e661de7173", + "requestIdentity": { + "method": "delete", + "endpoint": "api/users/454003867", + "params": [], + "headers": [] + }, + "response": "", + "status": 204, + "headers": { + "date": "Thu, 16 Jan 2025 16:31:15 GMT", + "connection": "keep-alive", + "cf-ray": "902f7ea29d870372-NBO", + "cf-cache-status": "DYNAMIC", + "access-control-allow-origin": "*", + "strict-transport-security": "max-age=5184000; includeSubDomains", + "access-control-expose-headers": "Authorization, Etag, Content-Type, Content-Length, X-Nango-Signature, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset", + "content-security-policy-report-only": "default-src 'self' https://app.nango.dev https://api.nango.dev;child-src 'self';connect-src 'self' https://*.google-analytics.com https://*.sentry.io https://app.nango.dev https://api.nango.dev wss://api.nango.dev/ https://*.posthog.com https://bluegrass.nango.dev;font-src 'self' https://*.googleapis.com https://*.gstatic.com;frame-src 'self' https://accounts.google.com https://app.nango.dev https://api.nango.dev https://connect.nango.dev https://www.youtube.com;img-src 'self' data: https://app.nango.dev https://api.nango.dev https://*.google-analytics.com https://*.googleapis.com https://*.posthog.com https://img.logo.dev https://*.ytimg.com;manifest-src 'self';media-src 'self';object-src 'self';script-src 'self' 'unsafe-eval' 'unsafe-inline' https://app.nango.dev https://api.nango.dev https://*.google-analytics.com https://*.googleapis.com https://apis.google.com https://*.posthog.com https://www.youtube.com https://shoegaze.nango.dev;style-src blob: 'self' 'unsafe-inline' https://*.googleapis.com https://app.nango.dev https://api.nango.dev;worker-src blob: 'self' https://app.nango.dev https://api.nango.dev https://*.googleapis.com https://*.posthog.com;base-uri 'self';form-action 'self';frame-ancestors 'self';script-src-attr 'none';upgrade-insecure-requests", + "rndr-id": "6380cb49-dff3-478c", + "x-content-type-options": "nosniff", + "x-dns-prefetch-control": "off", + "x-download-options": "noopen", + "x-frame-options": "SAMEORIGIN", + "x-ratelimit-limit": "2400", + "x-ratelimit-remaining": "2383", + "x-ratelimit-reset": "1737045094", + "x-render-origin-server": "Render", + "x-xss-protection": "0", + "vary": "Accept-Encoding", + "server": "cloudflare", + "alt-svc": "h3=\":443\"; ma=86400" + } +} diff --git a/integrations/gorgias/mocks/nango/delete/proxy/api/users/455843658/delete-user/7dcd1de4b5f46d6b29659d53227eab98bb2f2729.json b/integrations/gorgias/mocks/nango/delete/proxy/api/users/455843658/delete-user/7dcd1de4b5f46d6b29659d53227eab98bb2f2729.json new file mode 100644 index 000000000..0d796baef --- /dev/null +++ b/integrations/gorgias/mocks/nango/delete/proxy/api/users/455843658/delete-user/7dcd1de4b5f46d6b29659d53227eab98bb2f2729.json @@ -0,0 +1,36 @@ +{ + "method": "delete", + "endpoint": "api/users/455843658", + "requestIdentityHash": "7dcd1de4b5f46d6b29659d53227eab98bb2f2729", + "requestIdentity": { + "method": "delete", + "endpoint": "api/users/455843658", + "params": [], + "headers": [] + }, + "response": "", + "status": 204, + "headers": { + "date": "Thu, 16 Jan 2025 17:48:09 GMT", + "connection": "keep-alive", + "cf-ray": "902fef4c4d4ab195-NBO", + "cf-cache-status": "DYNAMIC", + "access-control-allow-origin": "*", + "strict-transport-security": "max-age=5184000; includeSubDomains", + "access-control-expose-headers": "Authorization, Etag, Content-Type, Content-Length, X-Nango-Signature, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset", + "content-security-policy-report-only": "default-src 'self' https://app.nango.dev https://api.nango.dev;child-src 'self';connect-src 'self' https://*.google-analytics.com https://*.sentry.io https://app.nango.dev https://api.nango.dev wss://api.nango.dev/ https://*.posthog.com https://bluegrass.nango.dev;font-src 'self' https://*.googleapis.com https://*.gstatic.com;frame-src 'self' https://accounts.google.com https://app.nango.dev https://api.nango.dev https://connect.nango.dev https://www.youtube.com;img-src 'self' data: https://app.nango.dev https://api.nango.dev https://*.google-analytics.com https://*.googleapis.com https://*.posthog.com https://img.logo.dev https://*.ytimg.com;manifest-src 'self';media-src 'self';object-src 'self';script-src 'self' 'unsafe-eval' 'unsafe-inline' https://app.nango.dev https://api.nango.dev https://*.google-analytics.com https://*.googleapis.com https://apis.google.com https://*.posthog.com https://www.youtube.com https://shoegaze.nango.dev;style-src blob: 'self' 'unsafe-inline' https://*.googleapis.com https://app.nango.dev https://api.nango.dev;worker-src blob: 'self' https://app.nango.dev https://api.nango.dev https://*.googleapis.com https://*.posthog.com;base-uri 'self';form-action 'self';frame-ancestors 'self';script-src-attr 'none';upgrade-insecure-requests", + "rndr-id": "ffd3bd60-42a4-493f", + "x-content-type-options": "nosniff", + "x-dns-prefetch-control": "off", + "x-download-options": "noopen", + "x-frame-options": "SAMEORIGIN", + "x-ratelimit-limit": "2400", + "x-ratelimit-remaining": "2396", + "x-ratelimit-reset": "1737049745", + "x-render-origin-server": "Render", + "x-xss-protection": "0", + "vary": "Accept-Encoding", + "server": "cloudflare", + "alt-svc": "h3=\":443\"; ma=86400" + } +} diff --git a/integrations/gorgias/mocks/nango/post/proxy/api/users/create-user/04dd13300a8b792236860fa99c4bedeeaed97cab.json b/integrations/gorgias/mocks/nango/post/proxy/api/users/create-user/04dd13300a8b792236860fa99c4bedeeaed97cab.json new file mode 100644 index 000000000..34e3ea85f --- /dev/null +++ b/integrations/gorgias/mocks/nango/post/proxy/api/users/create-user/04dd13300a8b792236860fa99c4bedeeaed97cab.json @@ -0,0 +1,65 @@ +{ + "method": "post", + "endpoint": "api/users", + "requestIdentityHash": "9d7b0f7cb5b3c6b67ba90c8d88d94ee2637fa496", + "requestIdentity": { + "method": "post", + "endpoint": "api/users", + "params": [], + "headers": [["Content-Length", "77"]], + "data": "{\"name\":\"John Doe\",\"email\":\"johndo2l@testdomain.tld\",\"role\":{\"name\":\"agent\"}}" + }, + "response": { + "id": 455925547, + "active": true, + "bio": null, + "created_datetime": "2025-01-16T18:36:45.698253+00:00", + "country": null, + "deactivated_datetime": null, + "email": "johndo2l@testdomain.tld", + "external_id": null, + "firstname": "John", + "has_password": false, + "has_2fa_enabled": false, + "lastname": "Doe", + "language": null, + "meta": { + "sso": null, + "profile_picture_url": null + }, + "name": "John Doe", + "role": { + "name": "agent" + }, + "timezone": "Africa/Nairobi", + "updated_datetime": "2025-01-16T18:36:45.698257+00:00", + "uri": "https://testfx.gorgias.com/api/users/455925547/" + }, + "status": 200, + "headers": { + "date": "Thu, 16 Jan 2025 18:36:45 GMT", + "content-type": "application/json; charset=utf-8", + "content-length": "300", + "connection": "keep-alive", + "cf-ray": "9030367f8bf9b19c-NBO", + "cf-cache-status": "DYNAMIC", + "access-control-allow-origin": "*", + "etag": "W/\"203-qyNWr+SpWX1Xin2YCrydsiMymfQ\"", + "strict-transport-security": "max-age=5184000; includeSubDomains", + "vary": "Accept-Encoding", + "access-control-expose-headers": "Authorization, Etag, Content-Type, Content-Length, X-Nango-Signature, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset", + "content-security-policy-report-only": "default-src 'self' https://app.nango.dev https://api.nango.dev;child-src 'self';connect-src 'self' https://*.google-analytics.com https://*.sentry.io https://app.nango.dev https://api.nango.dev wss://api.nango.dev/ https://*.posthog.com https://bluegrass.nango.dev;font-src 'self' https://*.googleapis.com https://*.gstatic.com;frame-src 'self' https://accounts.google.com https://app.nango.dev https://api.nango.dev https://connect.nango.dev https://www.youtube.com;img-src 'self' data: https://app.nango.dev https://api.nango.dev https://*.google-analytics.com https://*.googleapis.com https://*.posthog.com https://img.logo.dev https://*.ytimg.com;manifest-src 'self';media-src 'self';object-src 'self';script-src 'self' 'unsafe-eval' 'unsafe-inline' https://app.nango.dev https://api.nango.dev https://*.google-analytics.com https://*.googleapis.com https://apis.google.com https://*.posthog.com https://www.youtube.com https://shoegaze.nango.dev;style-src blob: 'self' 'unsafe-inline' https://*.googleapis.com https://app.nango.dev https://api.nango.dev;worker-src blob: 'self' https://app.nango.dev https://api.nango.dev https://*.googleapis.com https://*.posthog.com;base-uri 'self';form-action 'self';frame-ancestors 'self';script-src-attr 'none';upgrade-insecure-requests", + "rndr-id": "62bf5cba-d312-49bf", + "x-content-type-options": "nosniff", + "x-dns-prefetch-control": "off", + "x-download-options": "noopen", + "x-frame-options": "SAMEORIGIN", + "x-ratelimit-limit": "2400", + "x-ratelimit-remaining": "2395", + "x-ratelimit-reset": "1737052659", + "x-render-origin-server": "Render", + "x-xss-protection": "0", + "server": "cloudflare", + "alt-svc": "h3=\":443\"; ma=86400" + } +} diff --git a/integrations/gorgias/nango.yaml b/integrations/gorgias/nango.yaml index 0a7bbaca7..fe9223860 100644 --- a/integrations/gorgias/nango.yaml +++ b/integrations/gorgias/nango.yaml @@ -15,6 +15,19 @@ integrations: path: /tickets group: Tickets version: 1.0.1 + users: + description: | + Fetches the list of users + endpoint: + method: GET + path: /users + group: Users + sync_type: full + track_deletes: true + runs: every 6 hours + output: GorgiasUser + scopes: + - users:read actions: create-ticket: description: | @@ -30,7 +43,35 @@ integrations: path: /ticket group: Tickets output: Ticket + create-user: + description: | + Creates a new user with a role in Gorgias. Defaults to agent if a role is not provided + input: GorgiasCreateUser + output: GorgiasUser + endpoint: + method: POST + path: /user + group: Users + scopes: + - users:write + delete-user: + description: Deletes a user in Gorgias + output: SuccessResponse + input: IdEntity + endpoint: + method: DELETE + path: /users + group: Users + scopes: + - users:write models: + #generic + IdEntity: + id: string + SuccessResponse: + success: boolean + ActionResponseError: + message: string Ticket: id: number assignee_user: AssigneeUser | null @@ -132,3 +173,15 @@ models: body_html: string body_text: string id: string + CreateUser: + firstName: string + lastName: string + email: string + GorgiasCreateUser: + __extends: CreateUser + role: admin | agent | basic-agent | lite-agent | observer-agent + GorgiasUser: + id: string + firstName: string + lastName: string + email: string diff --git a/integrations/gorgias/schema.zod.ts b/integrations/gorgias/schema.zod.ts index cbe1d1689..c53cdaab4 100644 --- a/integrations/gorgias/schema.zod.ts +++ b/integrations/gorgias/schema.zod.ts @@ -1,6 +1,18 @@ // Generated by ts-to-zod import { z } from 'zod'; +export const idEntitySchema = z.object({ + id: z.string() +}); + +export const successResponseSchema = z.object({ + success: z.boolean() +}); + +export const actionResponseErrorSchema = z.object({ + message: z.string() +}); + export const userSchema = z.object({ id: z.number(), firstname: z.string(), @@ -244,3 +256,25 @@ export const createTicketInputSchema = z.object({ messages: z.array(createTicketMessageSchema) }) }); + +export const createUserSchema = z.object({ + firstName: z.string(), + lastName: z.string(), + email: z.string() +}); + +export const gorgiasUserSchema = z.object({ + id: z.string(), + firstName: z.string(), + lastName: z.string(), + email: z.string() +}); + +export const gorgiasCreateUserSchema = z.object({ + firstName: z.string(), + lastName: z.string(), + email: z.string(), + role: z.union([z.literal('admin'), z.literal('agent'), z.literal('basic-agent'), z.literal('lite-agent'), z.literal('observer-agent')]) +}); + +export const anonymousGorgiasActionCreateuserOutputSchema = z.literal('CreateUserOutput'); diff --git a/integrations/gorgias/syncs/users.md b/integrations/gorgias/syncs/users.md new file mode 100644 index 000000000..f9adec8b9 --- /dev/null +++ b/integrations/gorgias/syncs/users.md @@ -0,0 +1,49 @@ + +# Users + +## General Information + +- **Description:** Fetches the list of users + +- **Version:** 0.0.1 +- **Group:** Users +- **Scopes:** `users:read` +- **Endpoint Type:** Sync +- **Code:** [github.com](https://github.com/NangoHQ/integration-templates/tree/main/integrations/gorgias/syncs/users.ts) + + +## Endpoint Reference + +### Request Endpoint + +`GET /users` + +### Request Query Parameters + +- **modified_after:** `(optional, string)` A timestamp (e.g., `2023-05-31T11:46:13.390Z`) used to fetch records modified after this date and time. If not provided, all records are returned. The modified_after parameter is less precise than cursor, as multiple records may share the same modification timestamp. +- **limit:** `(optional, integer)` The maximum number of records to return per page. Defaults to 100. +- **cursor:** `(optional, string)` A marker used to fetch records modified after a specific point in time.If not provided, all records are returned.Each record includes a cursor value found in _nango_metadata.cursor.Save the cursor from the last record retrieved to track your sync progress.Use the cursor parameter together with the limit parameter to paginate through records.The cursor is more precise than modified_after, as it can differentiate between records with the same modification timestamp. +- **filter:** `(optional, added | updated | deleted)` Filter to only show results that have been added or updated or deleted. + +### Request Body + +_No request body_ + +### Request Response + +```json +{ + "id": "", + "firstName": "", + "lastName": "", + "email": "" +} +``` + +## Changelog + +- [Script History](https://github.com/NangoHQ/integration-templates/commits/main/integrations/gorgias/syncs/users.ts) +- [Documentation History](https://github.com/NangoHQ/integration-templates/commits/main/integrations/gorgias/syncs/users.md) + + + diff --git a/integrations/gorgias/syncs/users.ts b/integrations/gorgias/syncs/users.ts new file mode 100644 index 000000000..29e262d55 --- /dev/null +++ b/integrations/gorgias/syncs/users.ts @@ -0,0 +1,40 @@ +import type { NangoSync, ProxyConfiguration, GorgiasUser } from '../../models'; +import type { GorgiasUserResponse } from '../types'; + +/** + * Fetches data from the Gorgias API and saves it using NangoSync. + * + * @param {NangoSync} nango - The NangoSync instance used for fetching and saving data. + * + * @returns {Promise} A promise that resolves when the data fetching and saving process is complete. + * + * {@link https://developers.gorgias.com/reference/list-users} for more information on the Gorgias API endpoint. + */ +export default async function fetchData(nango: NangoSync) { + const config: ProxyConfiguration = { + // https://developers.gorgias.com/reference/list-users + endpoint: `/api/users`, + retries: 10, + paginate: { + type: 'cursor', + cursor_path_in_response: 'meta.next_cursor', + cursor_name_in_request: 'cursor', + response_path: 'data', + limit: 30, + limit_name_in_request: 'limit' + } + }; + + for await (const zUsers of nango.paginate(config)) { + const users: GorgiasUser[] = zUsers.map((zUser: GorgiasUserResponse) => { + return { + id: zUser.id.toString(), + firstName: zUser.firstname, + lastName: zUser.lastname, + email: zUser.email + }; + }); + + await nango.batchSave(users, 'GorgiasUser'); + } +} diff --git a/integrations/gorgias/tests/gorgias-create-user.test.ts b/integrations/gorgias/tests/gorgias-create-user.test.ts new file mode 100644 index 000000000..0791d3360 --- /dev/null +++ b/integrations/gorgias/tests/gorgias-create-user.test.ts @@ -0,0 +1,19 @@ +import { vi, expect, it, describe } from 'vitest'; + +import runAction from '../actions/create-user.js'; + +describe('gorgias create-user tests', () => { + const nangoMock = new global.vitest.NangoActionMock({ + dirname: __dirname, + name: 'create-user', + Model: 'GorgiasUser' + }); + + it('should output the action output that is expected', async () => { + const input = await nangoMock.getInput(); + const response = await runAction(nangoMock, input); + const output = await nangoMock.getOutput(); + + expect(response).toEqual(output); + }); +}); diff --git a/integrations/gorgias/tests/gorgias-delete-user.test.ts b/integrations/gorgias/tests/gorgias-delete-user.test.ts new file mode 100644 index 000000000..b43c43c16 --- /dev/null +++ b/integrations/gorgias/tests/gorgias-delete-user.test.ts @@ -0,0 +1,19 @@ +import { vi, expect, it, describe } from 'vitest'; + +import runAction from '../actions/delete-user.js'; + +describe('gorgias delete-user tests', () => { + const nangoMock = new global.vitest.NangoActionMock({ + dirname: __dirname, + name: 'delete-user', + Model: 'SuccessResponse' + }); + + it('should output the action output that is expected', async () => { + const input = await nangoMock.getInput(); + const response = await runAction(nangoMock, input); + const output = await nangoMock.getOutput(); + + expect(response).toEqual(output); + }); +}); diff --git a/integrations/gorgias/types.ts b/integrations/gorgias/types.ts index 67a1382c5..e52ac75da 100644 --- a/integrations/gorgias/types.ts +++ b/integrations/gorgias/types.ts @@ -373,3 +373,26 @@ interface SettingsItem { export interface GorgiasSettingsResponse { data: SettingsItem[]; } +export interface GorgiasUserResponse { + id: number; + active: boolean; + name: string; + email: string; + bio?: string | null; + country?: string | null; + external_id?: string; + language?: string | null; + firstname: string; + lastname: string; + meta?: Record; + role: { + name: 'admin' | 'agent' | 'basic-agent' | 'lite-agent' | 'observer-agent' | 'bot'; + }; +} +export interface GorgiasCreateUserReq { + name: string; + email: string; + role: { + name: 'admin' | 'agent' | 'basic-agent' | 'lite-agent' | 'observer-agent' | 'bot'; + }; +}