-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(harvest): add Harvest integration (#71)
## Describe your changes Add harvest integrations with the following endpoints: https://www.loom.com/share/b5a9580f7ca14e7cb5bd6f12d3337e43 ### Syncs - users ### Actions - create-user - delete-user ## Issue ticket number and link N/A ## Checklist before requesting a review (skip if just adding/editing APIs & templates) - [X] I added tests, otherwise the reason is: - [X] External API requests have `retries` - [X] Pagination is used where appropriate - [X] The built in `nango.paginate` call is used instead of a `while (true)` loop - [ ] Third party requests are NOT parallelized (this can cause issues with rate limits) - [X] If a sync requires metadata the `nango.yaml` has `auto_start: false` - [X] If the sync is a `full` sync then `track_deletes: true` is set --------- Co-authored-by: Khaliq <[email protected]>
- Loading branch information
1 parent
bbc2526
commit 9034419
Showing
23 changed files
with
900 additions
and
299 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import type { NangoAction, ProxyConfiguration, User, HarvestCreateUser } from '../../models'; | ||
import { toUser } from '../mappers/to-user.js'; | ||
import { harvestCreateUserSchema } from '../schema.zod.js'; | ||
import type { HarvestUser } from '../types'; | ||
|
||
/** | ||
* Creates a Haverst user. | ||
* | ||
* This function validates the input against the defined schema and constructs a request | ||
* to the Harvest API to create a new user contact. If the input is invalid, it logs the | ||
* errors and throws an ActionError. | ||
* | ||
* @param {NangoAction} nango - The Nango action context, used for logging and making API requests. | ||
* @param {HaverstCreateUser} input - The input data for creating a user contact | ||
* | ||
* @returns {Promise<User>} - A promise that resolves to the created User object. | ||
* | ||
* @throws {nango.ActionError} - Throws an error if the input validation fails. | ||
* | ||
* For detailed endpoint documentation, refer to: | ||
* https://help.getharvest.com/api-v2/users-api/users/users/#create-a-user | ||
*/ | ||
export default async function runAction(nango: NangoAction, input: HarvestCreateUser): Promise<User> { | ||
const parsedInput = harvestCreateUserSchema.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 config: ProxyConfiguration = { | ||
// https://help.getharvest.com/api-v2/users-api/users/users/#create-a-user | ||
endpoint: `/v2/users`, | ||
data: parsedInput.data, | ||
retries: 10 | ||
}; | ||
|
||
const response = await nango.post<HarvestUser>(config); | ||
const { data } = response; | ||
|
||
return toUser(data); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import type { NangoAction, ProxyConfiguration, SuccessResponse, IdEntity } from '../../models'; | ||
import { idEntitySchema } from '../schema.zod.js'; | ||
|
||
/** | ||
* Deletes a Haverst user. | ||
* | ||
* This function validates the input against the defined schema and constructs a request | ||
* to the Harvest API to delete a user contact by their ID. If the input is invalid, | ||
* it logs the errors and throws an ActionError. | ||
* | ||
* @param {NangoAction} nango - The Nango action context, used for logging and making API requests. | ||
* @param {IdEntity} input - The input data containing the ID of the user contact to be deleted | ||
* | ||
* @returns {Promise<SuccessResponse>} - A promise that resolves to a SuccessResponse object indicating the result of the deletion. | ||
* | ||
* @throws {nango.ActionError} - Throws an error if the input validation fails. | ||
* | ||
* For detailed endpoint documentation, refer to: | ||
* https://developers.intercom.com/docs/references/rest-api/api.intercom.io/contacts/deletecontact | ||
*/ | ||
export default async function runAction(nango: NangoAction, input: IdEntity): Promise<SuccessResponse> { | ||
const parsedInput = idEntitySchema.safeParse(input); | ||
|
||
if (!parsedInput.success) { | ||
for (const error of parsedInput.error.errors) { | ||
await nango.log(`Invalid input provided to delete a user: ${error.message} at path ${error.path.join('.')}`, { level: 'error' }); | ||
} | ||
|
||
throw new nango.ActionError({ | ||
message: 'Invalid input provided to delete a user' | ||
}); | ||
} | ||
|
||
const config: ProxyConfiguration = { | ||
// https://developers.intercom.com/docs/references/rest-api/api.intercom.io/contacts/deletecontact | ||
endpoint: `/v2/users/${parsedInput.data.id}`, | ||
retries: 10 | ||
}; | ||
|
||
await nango.delete(config); | ||
|
||
return { | ||
success: true | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"email": "[email protected]", | ||
"first_name": "John", | ||
"last_name": "Doe" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"id": "5083917" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import type { User } from '../../models'; | ||
import type { HarvestUser } from '../types'; | ||
|
||
/** | ||
* Maps an Harvest API user object to a Nango User object. | ||
* | ||
* @param contact The raw user object from the Harvest API. | ||
* @returns Mapped Nango User object with essential properties. | ||
*/ | ||
export function toUser(harvestUser: HarvestUser): User { | ||
return { | ||
id: harvestUser.id.toString(), | ||
email: harvestUser.email, | ||
firstName: harvestUser.first_name, | ||
lastName: harvestUser.last_name | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"email": "[email protected]", | ||
"first_name": "John", | ||
"last_name": "Doe" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"id": "5083917", | ||
"email": "[email protected]", | ||
"firstName": "John", | ||
"lastName": "Doe" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"id": "5083917" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"success": true | ||
} |
23 changes: 23 additions & 0 deletions
23
integrations/harvest/mocks/nango/delete/proxy/v2/users/5083917/delete-user.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"id": 5083917, | ||
"first_name": "John", | ||
"last_name": "Doe", | ||
"email": "[email protected]", | ||
"telephone": "", | ||
"timezone": "Central Time (US & Canada)", | ||
"weekly_capacity": 126000, | ||
"has_access_to_all_future_projects": false, | ||
"is_contractor": false, | ||
"is_active": true, | ||
"calendar_integration_enabled": false, | ||
"calendar_integration_source": null, | ||
"created_at": "2024-10-24T11:55:46Z", | ||
"updated_at": "2024-10-24T12:11:53Z", | ||
"can_create_projects": false, | ||
"default_hourly_rate": null, | ||
"cost_rate": null, | ||
"roles": [], | ||
"access_roles": [], | ||
"permissions_claims": ["expenses:read:own", "expenses:write:own", "timers:read:own", "timers:write:own"], | ||
"avatar_url": "https://d3s3969qhosaug.cloudfront.net/v2/default-avatars/4a44.png" | ||
} |
89 changes: 89 additions & 0 deletions
89
integrations/harvest/mocks/nango/get/proxy/v2/users/users.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
{ | ||
"users": [ | ||
{ | ||
"id": 5085064, | ||
"first_name": "John", | ||
"last_name": "Doe", | ||
"email": "[email protected]", | ||
"telephone": "", | ||
"timezone": "Jerusalem", | ||
"weekly_capacity": 126000, | ||
"has_access_to_all_future_projects": false, | ||
"is_contractor": false, | ||
"is_active": true, | ||
"calendar_integration_enabled": false, | ||
"calendar_integration_source": null, | ||
"created_at": "2024-10-25T17:01:08Z", | ||
"updated_at": "2024-10-25T17:01:08Z", | ||
"can_create_projects": false, | ||
"default_hourly_rate": null, | ||
"cost_rate": null, | ||
"roles": [], | ||
"access_roles": ["member"], | ||
"permissions_claims": ["expenses:read:own", "expenses:write:own", "timers:read:own", "timers:write:own"], | ||
"avatar_url": "https://d3s3969qhosaug.cloudfront.net/v2/default-avatars/4a44.png" | ||
}, | ||
{ | ||
"id": 5085050, | ||
"first_name": "Johnny", | ||
"last_name": "Doeseph", | ||
"email": "[email protected]", | ||
"telephone": "", | ||
"timezone": "Jerusalem", | ||
"weekly_capacity": 126000, | ||
"has_access_to_all_future_projects": false, | ||
"is_contractor": false, | ||
"is_active": true, | ||
"calendar_integration_enabled": false, | ||
"calendar_integration_source": null, | ||
"created_at": "2024-10-25T16:42:52Z", | ||
"updated_at": "2024-10-25T16:43:23Z", | ||
"can_create_projects": true, | ||
"default_hourly_rate": null, | ||
"cost_rate": null, | ||
"roles": [], | ||
"access_roles": ["administrator"], | ||
"permissions_claims": [ | ||
"billable_rates:read:all", | ||
"billable_rates:write:all", | ||
"billing:read:own", | ||
"billing:write:own", | ||
"clients:read:all", | ||
"clients:write:all", | ||
"company:read:own", | ||
"company:write:own", | ||
"cost_rates:read:all", | ||
"cost_rates:write:all", | ||
"estimates:read:all", | ||
"estimates:write:all", | ||
"expenses:read:all", | ||
"expenses:write:all", | ||
"invoices:read:all", | ||
"invoices:write:all", | ||
"projects:read:all", | ||
"projects:write:all", | ||
"saved_reports:read:inactive", | ||
"saved_reports:write:inactive", | ||
"tasks:read:all", | ||
"tasks:write:all", | ||
"timers:read:all", | ||
"timers:write:all", | ||
"users:read:all", | ||
"users:write:all" | ||
], | ||
"avatar_url": "https://d3s3969qhosaug.cloudfront.net/v2/default-avatars/4b47.png" | ||
} | ||
], | ||
"per_page": 2000, | ||
"total_pages": 1, | ||
"total_entries": 2, | ||
"next_page": null, | ||
"previous_page": null, | ||
"page": 1, | ||
"links": { | ||
"first": "https://api.harvestapp.com/v2/users?is_active=true&page=1&per_page=2000&ref=first", | ||
"next": null, | ||
"previous": null, | ||
"last": "https://api.harvestapp.com/v2/users?is_active=true&page=1&per_page=2000&ref=last" | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
integrations/harvest/mocks/nango/post/proxy/v2/users/create-user.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"id": 5083917, | ||
"first_name": "John", | ||
"last_name": "Doe", | ||
"email": "[email protected]", | ||
"telephone": "", | ||
"timezone": "Central Time (US & Canada)", | ||
"weekly_capacity": 126000, | ||
"has_access_to_all_future_projects": false, | ||
"is_contractor": false, | ||
"is_active": true, | ||
"calendar_integration_enabled": false, | ||
"calendar_integration_source": null, | ||
"created_at": "2024-10-24T11:55:46Z", | ||
"updated_at": "2024-10-24T11:55:46Z", | ||
"can_create_projects": false, | ||
"default_hourly_rate": null, | ||
"cost_rate": null, | ||
"roles": [], | ||
"access_roles": ["member"], | ||
"permissions_claims": ["expenses:read:own", "expenses:write:own", "timers:read:own", "timers:write:own"], | ||
"avatar_url": "https://d3s3969qhosaug.cloudfront.net/v2/default-avatars/4a44.png" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[ | ||
{ | ||
"id": "5085064", | ||
"email": "[email protected]", | ||
"firstName": "John", | ||
"lastName": "Doe" | ||
}, | ||
{ | ||
"id": "5085050", | ||
"email": "[email protected]", | ||
"firstName": "Johnny", | ||
"lastName": "Doeseph" | ||
} | ||
] |
Oops, something went wrong.