Skip to content

Commit 348b830

Browse files
committed
feat: Added support for Organizations
1 parent 0dae49c commit 348b830

File tree

8 files changed

+217
-2
lines changed

8 files changed

+217
-2
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ and retry the original request.
7676

7777
* notifications - Operations to send push notifications to SmartThings mobile app. Link to code interface [here](https://github.com/SmartThingsCommunity/smartthings-core-sdk/blob/master/src/endpoint/notifications.ts#L83), link to wiki page description [here](https://github.com/SmartThingsCommunity/smartthings-core-sdk/wiki/Notifications3)
7878

79+
* organizations - Operations to list and get organizations. Link to code interface [here](https://github.com/SmartThingsCommunity/smartthings-core-sdk/blob/master/src/endpoint/organizations.ts#L38). _Future feature. Not yet supported._
80+
7981
* presentation - Operation on device configurations and presentations. Link to code interface [here](https://github.com/SmartThingsCommunity/smartthings-core-sdk/blob/master/src/endpoint/presentation.ts#L189).
8082

8183
* rooms - Operations related to **Rooms**, a grouping of devices within a location. Link to code interface [here](https://github.com/SmartThingsCommunity/smartthings-core-sdk/blob/master/src/endpoint/rooms.ts#L27), link to wiki page description [here](https://github.com/SmartThingsCommunity/smartthings-core-sdk/wiki/Rooms)

src/endpoint/organizations.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Endpoint } from '../endpoint'
2+
import { EndpointClient, EndpointClientConfig } from '../endpoint-client'
3+
4+
5+
export interface OrganizationUpdateRequest {
6+
label?: string
7+
warehouseGroupId?: string
8+
}
9+
10+
export interface OrganizationCreateRequest extends OrganizationUpdateRequest {
11+
name: string
12+
manufacturerName?: string
13+
mnid?: string
14+
}
15+
16+
export interface OrganizationResponse extends OrganizationCreateRequest {
17+
/**
18+
* A generated UUID for an organization.
19+
*/
20+
organizationId: string
21+
22+
/**
23+
* The user group for organization developers.
24+
*/
25+
developerGroupId?: string
26+
27+
/**
28+
* The user group for organization admins.
29+
*/
30+
adminGroupId?: string
31+
32+
/**
33+
* Denotes whether this is the default user org for the caller.
34+
*/
35+
isDefaultUserOrg?: boolean
36+
}
37+
38+
export class OrganizationsEndpoint extends Endpoint {
39+
constructor(config: EndpointClientConfig) {
40+
super(new EndpointClient('organizations', config))
41+
}
42+
43+
public list(): Promise<OrganizationResponse[]>{
44+
return this.client.getPagedItems<OrganizationResponse>('')
45+
}
46+
47+
public get(id: string): Promise<OrganizationResponse>{
48+
return this.client.get<OrganizationResponse>(id)
49+
}
50+
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export * from './endpoint/installedapps'
1818
export * from './endpoint/locations'
1919
export * from './endpoint/modes'
2020
export * from './endpoint/notifications'
21+
export * from './endpoint/organizations'
2122
export * from './endpoint/presentation'
2223
export * from './endpoint/rooms'
2324
export * from './endpoint/rules'

src/st-client.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { InstalledAppsEndpoint } from './endpoint/installedapps'
1212
import { ModesEndpoint } from './endpoint/modes'
1313
import { LocationsEndpoint } from './endpoint/locations'
1414
import { NotificationsEndpoint } from './endpoint/notifications'
15+
import { OrganizationsEndpoint } from './endpoint/organizations'
1516
import { PresentationEndpoint } from './endpoint/presentation'
1617
import { RoomsEndpoint } from './endpoint/rooms'
1718
import { RulesEndpoint } from './endpoint/rules'
@@ -20,7 +21,7 @@ import { SubscriptionsEndpoint } from './endpoint/subscriptions'
2021
import { SchedulesEndpoint } from './endpoint/schedules'
2122
import { SchemaEndpoint } from './endpoint/schema'
2223
import { ServicesEndpoint } from './endpoint/services'
23-
import { SmartThingsURLProvider, defaultSmartThingsURLProvider } from './endpoint-client'
24+
import { SmartThingsURLProvider, defaultSmartThingsURLProvider, HttpClientHeaders } from './endpoint-client'
2425

2526

2627
export class SmartThingsClient extends RESTClient {
@@ -33,6 +34,7 @@ export class SmartThingsClient extends RESTClient {
3334
public readonly installedApps: InstalledAppsEndpoint
3435
public readonly modes: ModesEndpoint
3536
public readonly notifications: NotificationsEndpoint
37+
public readonly organizations: OrganizationsEndpoint
3638
public readonly locations: LocationsEndpoint
3739
public readonly presentation: PresentationEndpoint
3840
public readonly rooms: RoomsEndpoint
@@ -56,6 +58,7 @@ export class SmartThingsClient extends RESTClient {
5658
this.locations = new LocationsEndpoint(this.config)
5759
this.modes = new ModesEndpoint(this.config)
5860
this.notifications = new NotificationsEndpoint(this.config)
61+
this.organizations = new OrganizationsEndpoint(this.config)
5962
this.presentation = new PresentationEndpoint(this.config)
6063
this.rooms = new RoomsEndpoint(this.config)
6164
this.rules = new RulesEndpoint(this.config)
@@ -70,6 +73,10 @@ export class SmartThingsClient extends RESTClient {
7073
this.config.locationId = id
7174
return this
7275
}
76+
77+
public clone(headers?: HttpClientHeaders): SmartThingsClient {
78+
return new SmartThingsClient(this.config.authenticator, {...this.config, headers})
79+
}
7380
}
7481

7582
export class SmartThingsOAuthClient {
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
export const get_organizations = {
2+
request: {
3+
'url': 'https://api.smartthings.com/organizations',
4+
'method': 'get',
5+
'headers': {
6+
'Content-Type': 'application/json;charset=utf-8',
7+
'Accept': 'application/json',
8+
'Authorization': 'Bearer 00000000-0000-0000-0000-000000000000',
9+
},
10+
},
11+
response: {
12+
items: [
13+
{
14+
'label': 'default user organization',
15+
'warehouseGroupId': '00000000-0000-0000-0000-000000000000',
16+
'name': 'orgnamespace1',
17+
'developerGroupId': '00000000-0000-0000-0000-000000000000',
18+
'adminGroupId': '00000000-0000-0000-0000-000000000000',
19+
'organizationId': '00000000-0000-0000-0000-000000000000',
20+
'isDefaultUserOrg': true,
21+
},
22+
{
23+
'label': 'Organization Two',
24+
'warehouseGroupId': '00000000-0000-0000-0000-000000000000',
25+
'name': 'orgnamespace2',
26+
'developerGroupId': '00000000-0000-0000-0000-000000000000',
27+
'adminGroupId': '00000000-0000-0000-0000-000000000000',
28+
'organizationId': '00000000-0000-0000-0000-000000000002',
29+
'isDefaultUserOrg': false,
30+
},
31+
{
32+
'label': 'Organization Three',
33+
'warehouseGroupId': '00000000-0000-0000-0000-000000000000',
34+
'name': 'orgnamespace3',
35+
'developerGroupId': '00000000-0000-0000-0000-000000000000',
36+
'adminGroupId': '00000000-0000-0000-0000-000000000000',
37+
'organizationId': '00000000-0000-0000-0000-000000000003',
38+
'isDefaultUserOrg': false,
39+
},
40+
],
41+
'_links': null,
42+
},
43+
}
44+
45+
export const get_an_organization = {
46+
request: {
47+
'url': 'https://api.smartthings.com/organizations/00000000-0000-0000-0000-000000000000',
48+
'method': 'get',
49+
'headers': {
50+
'Content-Type': 'application/json;charset=utf-8',
51+
'Accept': 'application/json',
52+
'Authorization': 'Bearer 00000000-0000-0000-0000-000000000000',
53+
},
54+
},
55+
response: {
56+
'label': 'default user organization',
57+
'warehouseGroupId': '00000000-0000-0000-0000-000000000000',
58+
'name': 'orgnamespace1',
59+
'developerGroupId': '00000000-0000-0000-0000-000000000000',
60+
'adminGroupId': '00000000-0000-0000-0000-000000000000',
61+
'organizationId': '00000000-0000-0000-0000-000000000000',
62+
'isDefaultUserOrg': true,
63+
},
64+
}

test/unit/endpoint-client.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ describe('Endpoint Client', () => {
7474
})
7575

7676
test('request with header overrides', async () => {
77-
const headerOverrides = { 'Content-Type': 'overridden content type'}
77+
const headerOverrides = {
78+
'Content-Type': 'overridden content type',
79+
'X-ST-Organization': '00000000-0000-0000-0000-000000000008',
80+
}
7881
const response = await client.request('POST', 'mypath', { name: 'Bob' }, undefined, { headerOverrides })
7982
expect(axios.request).toHaveBeenCalledTimes(1)
8083
expect(axios.request).toHaveBeenCalledWith({
@@ -85,6 +88,7 @@ describe('Endpoint Client', () => {
8588
'Accept': 'application/json',
8689
'Authorization': `Bearer ${token}`,
8790
'X-ST-CORRELATION': 'AAABBBCCC',
91+
'X-ST-Organization': '00000000-0000-0000-0000-000000000008',
8892
},
8993
'data': { name: 'Bob' },
9094
'params': undefined,

test/unit/organizations.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import axios from '../../__mocks__/axios'
2+
import {
3+
BearerTokenAuthenticator,
4+
SmartThingsClient,
5+
OrganizationResponse,
6+
} from '../../src'
7+
import { expectedRequest } from './helpers/utils'
8+
import {
9+
get_organizations as list,
10+
get_an_organization as get,
11+
} from './data/organizations/get'
12+
13+
14+
const authenticator = new BearerTokenAuthenticator('00000000-0000-0000-0000-000000000000')
15+
const client = new SmartThingsClient(authenticator)
16+
17+
describe('Organizations', () => {
18+
afterEach(() => {
19+
axios.request.mockReset()
20+
})
21+
22+
it('list', async () => {
23+
axios.request.mockImplementationOnce(() => Promise.resolve({status: 200, data: list.response}))
24+
const response: OrganizationResponse[] = await client.organizations.list()
25+
expect(axios.request).toHaveBeenCalledTimes(1)
26+
expect(axios.request).toHaveBeenCalledWith(expectedRequest(list.request))
27+
expect(response).toBe(list.response.items)
28+
})
29+
30+
it('explicit get', async () => {
31+
axios.request.mockImplementationOnce(() => Promise.resolve({status: 200, data: get.response}))
32+
const response: OrganizationResponse = await client.organizations.get('00000000-0000-0000-0000-000000000000')
33+
expect(axios.request).toHaveBeenCalledWith(expectedRequest(get.request))
34+
expect(response).toBe(get.response)
35+
})
36+
})

test/unit/st-client.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import axios from '../../__mocks__/axios'
2+
import {
3+
BearerTokenAuthenticator,
4+
SmartThingsClient,
5+
} from '../../src'
6+
7+
8+
describe('ST Client', () => {
9+
afterEach(() => {
10+
axios.request.mockReset()
11+
})
12+
13+
it('Construction with no location', async () => {
14+
const client = new SmartThingsClient(
15+
new BearerTokenAuthenticator('00000000-0000-0000-0000-000000000000'))
16+
expect(client.config.locationId).toBeUndefined()
17+
})
18+
19+
it('Construction with location ID', async () => {
20+
const client = new SmartThingsClient(
21+
new BearerTokenAuthenticator('00000000-0000-0000-0000-000000000000'),
22+
{ locationId: '95efee9b-6073-4871-b5ba-de6642187293' })
23+
expect(client.config.locationId).toBe('95efee9b-6073-4871-b5ba-de6642187293')
24+
})
25+
26+
it('Construction with setLocation', async () => {
27+
const client = new SmartThingsClient(
28+
new BearerTokenAuthenticator('00000000-0000-0000-0000-000000000000'))
29+
client.setLocation('d52f4bd1-700b-4730-a05a-e1fbe999ee8d')
30+
expect(client.config.locationId).toBe('d52f4bd1-700b-4730-a05a-e1fbe999ee8d')
31+
})
32+
33+
it('Clone with new headers', async () => {
34+
const client = new SmartThingsClient(
35+
new BearerTokenAuthenticator('00000000-0000-0000-0000-000000000000'))
36+
37+
const client2 = client.clone({'X-ST-Organization': 'e639ddd9-8af4-4725-a491-eda77c41dc7b'})
38+
39+
expect(client.config.headers).toBeDefined()
40+
if (client.config.headers) {
41+
expect(client.config.headers['X-ST-Organization']).toBeUndefined()
42+
}
43+
44+
expect(client2.config.headers).toBeDefined()
45+
if (client2.config.headers) {
46+
expect(client2.config.headers['X-ST-Organization']).toBe('e639ddd9-8af4-4725-a491-eda77c41dc7b')
47+
}
48+
49+
})
50+
51+
})

0 commit comments

Comments
 (0)