Skip to content

Commit

Permalink
greenhouse-basic syncs integration templates
Browse files Browse the repository at this point in the history
  • Loading branch information
hassan254-prog committed Jan 16, 2024
1 parent 0a583e1 commit e3a083c
Show file tree
Hide file tree
Showing 11 changed files with 497 additions and 2 deletions.
21 changes: 21 additions & 0 deletions docs-v2/integration-templates/greenhouse.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: 'Greenhouse API Integration Template'
sidebarTitle: 'Greenhouse'
---

## Get started with the Greenhouse template

<Card title="How to use integration templates"
href="/integration-templates/overview#how-to-use-integration-templates"
icon="book-open">
Learn how to use integration templates in Nango
</Card>

<Card title="Get the Greenhouse template"
href="https://github.com/NangoHQ/nango/tree/master/integration-templates/greenhouse"
icon="github">
Get the latest version of the Greenhouse integration template from GitHub
</Card>

## Need help with the template?
Please reach out on the [Slack community](https://nango.dev/slack), we are very active there and happy to help!
4 changes: 4 additions & 0 deletions docs-v2/integration-templates/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ As Nango and its community expand, we're looking forward to offering hundreds of
Sync users, organization units, and authorized 3rd party APIs from Google Workspace
</Card>

<Card title="Greenhouse" href="/integration-templates/greenhouse" icon="people-arrows">
Sync applications, candidates and jobs from harvest resource on Greenhouse
</Card>

<Card title="MS Active Directory" href="/integration-templates/microsoft-active-directory" icon="microsoft" iconType="brands">
Sync users and groups from Microsoft Active Directory
</Card>
Expand Down
7 changes: 5 additions & 2 deletions docs-v2/integrations/all/greenhouse.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ title: Greenhouse
sidebarTitle: Greenhouse
---

API configuration: [`greenhouse`](https://nango.dev/providers.yaml)
API configuration: [`greenhouse`](https://nango.dev/providers.yaml), [`greenhouse-basic`](https://nango.dev/providers.yaml)

## Features

| Feature | Status |
| -------------------------------------------------------------------------------- | ------------------------------- |
| [Auth (OAuth)](/guides/oauth) ||
| Auth ([Basic](/guides/api-key) + [OAuth](/guides/oauth)) ||
| [Syncs](/guides/sync) & [Actions](/guides/action) ||
| [Nango Proxy](/guides/proxy) ||
| Auto-pagination | 🚫 (time to contribute: &lt;1h) |
Expand All @@ -18,16 +18,19 @@ API configuration: [`greenhouse`](https://nango.dev/providers.yaml)
<Tip>We can implement missing features in &lt;48h, just ask for it in the [community](https://nango.dev/slack).</Tip>

## Getting started
Greenhouse offers both `Basic` and `OAuth` as authentication and Nango implements both.

- [How to register an Application](https://developers.greenhouse.io/candidate-ingestion.html#authentication)
- [OAuth-related docs](https://developers.greenhouse.io/candidate-ingestion.html#introduction)
- [List of OAuth scopes](https://developers.greenhouse.io/candidate-ingestion.html#oauth-scopes)
- [API](https://developers.greenhouse.io)
- [Harvest API authentication](https://developers.greenhouse.io/harvest.html#authentication)

<Tip>Need help getting started? Get help in the [community](https://nango.dev/slack).</Tip>

## API gotchas

- For `Basic` auth pass Greenhouse API token as username and the password should be blank.
- If you need to use the proxy, it is important to provide the resource that you will be calling in the config (as green house has many forms for API resource). Please see [here](https://developers.greenhouse.io/) for different types of resources. Once confirmed, you have to add `resource` as a config.

<Note>Add Getting Started links and Gotchas by [editing this page](https://github.com/nangohq/nango/tree/master/docs-v2/integrations/all/gorgias.mdx)</Note>
1 change: 1 addition & 0 deletions docs-v2/mint.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"integration-templates/github",
"integration-templates/gmail",
"integration-templates/google-workspace",
"integration-templates/greenhouse",
"integration-templates/hackerrank-work",
"integration-templates/hubspot",
"integration-templates/intercom",
Expand Down
55 changes: 55 additions & 0 deletions integration-templates/greenhouse-basic/greenhouse-applications.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import type { GreenhouseApplication, NangoSync } from './models';

export default async function fetchData(nango: NangoSync) {
let totalRecords = 0;

try {
const endpoint = '/v1/applications';
const config = {
...(nango.lastSyncDate ? { params: { created_after: nango.lastSyncDate?.toISOString() } } : {}),
paginate: {
type: 'link',
link_path_in_response_body: 'links.next',
limit_name_in_request: 'per_page',
limit: 100
}
};
for await (const application of nango.paginate({ ...config, endpoint })) {
const mappedApplication: GreenhouseApplication[] = application.map(mapApplication) || [];

const batchSize: number = mappedApplication.length;
totalRecords += batchSize;
await nango.log(`Saving batch of ${batchSize} application(s) (total application(s): ${totalRecords})`);
await nango.batchSave(mappedApplication, 'GreenhouseApplication');
}
} catch (error: any) {
throw new Error(`Error in fetchData: ${error.message}`);
}
}

function mapApplication(application: any): GreenhouseApplication {
return {
id: application.id,
candidate_id: application.candidate_id,
prospect: application.prospect,
applied_at: application.applied_at,
rejected_at: application.rejected_at,
last_activity_at: application.last_activity_at,
location: application.location,
source: application.source,
credited_to: application.credited_to,
rejection_reason: application.rejection_reason,
rejection_details: application.rejection_details,
jobs: application.jobs,
job_post_id: application.job_post_id,
status: application.status,
current_stage: application.current_stage,
answers: application.answers,
prospective_office: application.prospective_office,
prospective_department: application.prospective_department,
prospect_detail: application.prospect_detail,
custom_fields: application.custom_fields,
keyed_custom_fields: application.keyed_custom_fields,
attachments: application.attachments
};
}
60 changes: 60 additions & 0 deletions integration-templates/greenhouse-basic/greenhouse-candidates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import type { GreenhouseCandidate, NangoSync } from './models';

export default async function fetchData(nango: NangoSync) {
let totalRecords = 0;

try {
const endpoint = '/v1/candidates';
const config = {
...(nango.lastSyncDate ? { params: { created_after: nango.lastSyncDate?.toISOString() } } : {}),
paginate: {
type: 'link',
link_path_in_response_body: 'links.next',
limit_name_in_request: 'per_page',
limit: 100
}
};
for await (const candidate of nango.paginate({ ...config, endpoint })) {
const mappedCandidate: GreenhouseCandidate[] = candidate.map(mapCandidate) || [];

const batchSize: number = mappedCandidate.length;
totalRecords += batchSize;
await nango.log(`Saving batch of ${batchSize} candidate(s) (total candidate(s): ${totalRecords})`);
await nango.batchSave(mappedCandidate, 'GreenhouseCandidate');
}
} catch (error: any) {
throw new Error(`Error in fetchData: ${error.message}`);
}
}

function mapCandidate(candidate: any): GreenhouseCandidate {
return {
id: candidate.id,
first_name: candidate.first_name,
last_name: candidate.last_name,
company: candidate.company,
title: candidate.title,
created_at: candidate.created_at,
updated_at: candidate.updated_at,
last_activity: candidate.last_activity,
is_private: candidate.is_private,
photo_url: candidate.photo_url,
attachments: candidate.attachments,
application_ids: candidate.application_ids,
phone_numbers: candidate.phone_numbers,
addresses: candidate.addresses,
email_addresses: candidate.email_addresses,
website_addresses: candidate.website_addresses,
social_media_addresses: candidate.social_media_addresses,
recruiter: candidate.recruiter,
coordinator: candidate.coordinator,
can_email: candidate.can_email,
tags: candidate.tags,
applications: candidate.applications,
educations: candidate.educations,
employments: candidate.employments,
linked_user_ids: candidate.linked_user_ids,
custom_fields: candidate.custom_fields,
keyed_custom_fields: candidate.keyed_custom_fields
};
}
51 changes: 51 additions & 0 deletions integration-templates/greenhouse-basic/greenhouse-jobs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { GreenhouseJob, NangoSync } from './models';

export default async function fetchData(nango: NangoSync) {
let totalRecords = 0;

try {
const endpoint = '/v1/jobs';
const config = {
...(nango.lastSyncDate ? { params: { created_after: nango.lastSyncDate?.toISOString() } } : {}),
paginate: {
type: 'link',
link_path_in_response_body: 'links.next',
limit_name_in_request: 'per_page',
limit: 100
}
};
for await (const job of nango.paginate({ ...config, endpoint })) {
const mappedJob: GreenhouseJob[] = job.map(mapJob) || [];

const batchSize: number = mappedJob.length;
totalRecords += batchSize;
await nango.log(`Saving batch of ${batchSize} job(s) (total job(s): ${totalRecords})`);
await nango.batchSave(mappedJob, 'GreenhouseJob');
}
} catch (error: any) {
throw new Error(`Error in fetchData: ${error.message}`);
}
}

function mapJob(job: any): GreenhouseJob {
return {
id: job.id,
name: job.name,
requisition_id: job.requisition_id,
notes: job.notes,
confidential: job.confidential,
status: job.status,
created_at: job.created_at,
opened_at: job.opened_at,
closed_at: job.closed_at,
updated_at: job.updated_at,
is_template: job.is_template,
copied_from_id: job.copied_from_id,
departments: job.departments,
offices: job.offices,
custom_fields: job.custom_fields,
keyed_custom_fields: job.keyed_custom_fields,
hiring_team: job.hiring_team,
openings: job.openings
};
}
147 changes: 147 additions & 0 deletions integration-templates/greenhouse-basic/nango.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
integrations:
greenhouse-basic:
greenhouse-applications:
runs: every 6 hours
returns:
- GreenhouseApplication
description: |
Fetches all organization's applications from greenhouse.
Details: incremental sync, doesn't track deletes, metadata is not required.
greenhouse-candidates:
runs: every 6 hours
returns:
- GreenhouseCandidate
description: |
Fetches all organization's candidates from greenhouse.
Details: incremental sync, doesn't track deletes, metadata is not required.
greenhouse-jobs:
runs: every 6 hours
returns:
- GreenhouseJob
description: |
Fetches all organization's jobs from greenhouse.
Details: incremental sync, doesn't track deletes, metadata is not required.
models:
GreenhouseApplication:
id: string
candidate_id: string
prospect: boolean
applied_at: date
rejected_at: date
last_activity_at: date
location:
address: string
source:
id: string
public_name: string
credited_to:
id: string
first_name: string
last_name: string
name: string
employee_id: string
rejection_reason:
id: string
name: string
type:
id: string
name: string
rejection_details:
custom_fields: object
keyed_custom_fields: object
jobs: []
job_post_id: string
status: string
current_stage:
id: string
name: string
answers: []
prospective_office:
primary_contact_user_id: string
parent_id: string
name: string
location:
name: string
id: string
external_id: string
child_ids: []
prospective_department:
parent_id: string
name: string
id: string
external_id: string
child_ids: []
prospect_detail:
prospect_pool:
id: string
name: string
prospect_stage:
id: string
name: string
prospect_owner:
id: string
name: string
custom_fields: object
keyed_custom_fields: object
attachments: []
GreenhouseCandidate:
id: string
first_name: string
last_name: string
company: string
title: string
created_at: date
updated_at: date
last_activity: date
is_private: boolean
photo_url: string
attachments: []
application_ids: []
phone_numbers: []
addresses: []
email_addresses: []
website_addresses: []
social_media_addresses: []
recruiter:
id: string
first_name: string
last_name: string
name: string
employee_id: string
coordinator:
id: string
first_name: string
last_name: string
name: string
employee_id: string
can_email: boolean
tags: []
applications: []
educations: []
employments: []
linked_user_ids: string
custom_fields: object
keyed_custom_fields: object
GreenhouseJob:
id: string
name: string
requisition_id: string
notes: string
confidential: boolean
status: string
created_at: date
opened_at: date
closed_at: date
updated_at: date
is_template: boolean
copied_from_id: string
departments: []
offices: []
custom_fields: object
keyed_custom_fields: object
hiring_team:
hiring_managers: []
recruiters: []
coordinators: []
sourcers: []
openings: []
Loading

0 comments on commit e3a083c

Please sign in to comment.