Skip to content

Commit

Permalink
Add an extractor for pulling user information from BambooHR
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanlawrence-asana committed Sep 18, 2020
1 parent c595680 commit e0b3133
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 0 deletions.
65 changes: 65 additions & 0 deletions databuilder/extractor/bamboohr_user_extractor.py
@@ -0,0 +1,65 @@
# Copyright Contributors to the Amundsen project.
# SPDX-License-Identifier: Apache-2.0


from pyhocon import ConfigTree
import requests
from requests.auth import HTTPBasicAuth
from typing import Iterator, Optional
from xml.etree import ElementTree

from databuilder.extractor.base_extractor import Extractor
from databuilder.models.user import User


class BamboohrUserExtractor(Extractor):
API_KEY = 'api_key'
SUBDOMAIN = 'subdomain'

def init(self, conf: ConfigTree) -> None:
self._extract_iter: Optional[Iterator] = None
self._extract_iter = None

self._api_key = conf.get_string(BamboohrUserExtractor.API_KEY)
self._subdomain = conf.get_string(BamboohrUserExtractor.SUBDOMAIN)

def extract(self) -> Optional[User]:
if not self._extract_iter:
self._extract_iter = self._get_extract_iter()
try:
return next(self._extract_iter)
except StopIteration:
return None

def _employee_directory_uri(self) -> str:
return 'https://api.bamboohr.com/api/gateway.php/{subdomain}/v1/employees/directory'.format(
subdomain=self._subdomain
)

def _get_extract_iter(self) -> Iterator[User]:
response = requests.get(
self._employee_directory_uri(), auth=HTTPBasicAuth(self._api_key, 'x')
)

root = ElementTree.fromstring(response.content)

for user in root.findall('./employees/employee'):

def get_field(name: str) -> str:
field = user.find('./field[@id=\'{name}\']'.format(name=name))
if field and field.text:
return field.text
else:
return ''

yield User(
email=get_field('workEmail'),
first_name=get_field('firstName'),
last_name=get_field('lastName'),
name=get_field('displayName'),
team_name=get_field('department'),
role_name=get_field('jobTitle'),
)

def get_scope(self) -> str:
return 'extractor.bamboohr_user'
1 change: 1 addition & 0 deletions requirements.txt
Expand Up @@ -59,3 +59,4 @@ httplib2>=0.18.0
unidecode

requests==2.23.0,<3.0
responses==0.10.6
45 changes: 45 additions & 0 deletions tests/unit/extractor/test_bamboohr_user_extractor.py
@@ -0,0 +1,45 @@
# Copyright Contributors to the Amundsen project.
# SPDX-License-Identifier: Apache-2.0

import io
import unittest

import os

import responses
from pyhocon import ConfigTree, ConfigFactory

from databuilder.models.user import User
from databuilder.extractor.bamboohr_user_extractor import BamboohrUserExtractor


class TestBamboohrUserExtractor(unittest.TestCase):
@responses.activate
def test_parse_testdata(self) -> None:
bhr = BamboohrUserExtractor()
bhr.init(ConfigFactory.from_dict({"api_key": "api_key", "subdomain": "amundsen"}))

testdata_xml = os.path.join(
os.path.dirname(os.path.realpath(__file__)), "../resources/bamboohr_user_extractor/testdata.xml"
)

with io.open(testdata_xml) as testdata:
responses.add(responses.GET, bhr._employee_directory_uri(), body=testdata.read())

expected = User(
email="roald@amundsen.io",
first_name="Roald",
last_name="Amundsen",
name="Roald Amundsen",
team_name="508 Corporate Marketing",
role_name="Antarctic Explorer",
)

actual_users = list(bhr._get_extract_iter())

self.assertEqual(1, len(actual_users))
self.assertEqual(repr(expected), repr(actual_users[0]))


if __name__ == "__main__":
unittest.main()
39 changes: 39 additions & 0 deletions tests/unit/resources/bamboohr_user_extractor/testdata.xml
@@ -0,0 +1,39 @@
<?xml version="1.0"?>
<directory>
<fieldset>
<field id="displayName">Display name</field>
<field id="firstName">First name</field>
<field id="lastName">Last name</field>
<field id="preferredName">Preferred name</field>
<field id="gender">Gender</field>
<field id="jobTitle">Job title</field>
<field id="workPhone">Work Phone</field>
<field id="mobilePhone">Mobile Phone</field>
<field id="workEmail">Work Email</field>
<field id="department">Department</field>
<field id="location">Location</field>
<field id="workPhoneExtension">Work Ext.</field>
<field id="photoUploaded">Employee photo</field>
<field id="photoUrl">Photo URL</field>
<field id="canUploadPhoto">Can Upload Photo</field>
</fieldset>
<employees>
<employee id="1082">
<field id="displayName">Roald Amundsen</field>
<field id="firstName">Roald</field>
<field id="lastName">Amundsen</field>
<field id="preferredName"></field>
<field id="gender">Male</field>
<field id="jobTitle">Antarctic Explorer</field>
<field id="workPhone"></field>
<field id="mobilePhone"></field>
<field id="workEmail">roald@amundsen.io</field>
<field id="department">508 Corporate Marketing</field>
<field id="location">Norway</field>
<field id="workPhoneExtension"></field>
<field id="photoUploaded">true</field>
<field id="photoUrl">https://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Amundsen_in_fur_skins.jpg/440px-Amundsen_in_fur_skins.jpg</field>
<field id="canUploadPhoto">no</field>
</employee>
</employees>
</directory>

0 comments on commit e0b3133

Please sign in to comment.