diff --git a/index.ts b/index.ts index 8673d05..b2d971f 100644 --- a/index.ts +++ b/index.ts @@ -1,4 +1,5 @@ export default './src/d4h.js'; export * from './src/d4h.js' +export * from './src/group.js' export * from './src/member.js' diff --git a/package.json b/package.json index 5af15be..0ac96c2 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,5 @@ "typescript": "^4.8.4" }, "dependencies": { - "node-fetch": "^3.3.0" } } diff --git a/src/d4h.ts b/src/d4h.ts index 9689a16..cd892b2 100644 --- a/src/d4h.ts +++ b/src/d4h.ts @@ -1,20 +1,10 @@ -import fetch from 'node-fetch'; +import HttpUtils from "./httpUtils"; +import type { Group } from "./group"; import type { Member } from "./member"; const D4H_FETCH_LIMIT = 250; const D4H_BASE_URL = "https://api.d4h.org/v2"; -interface D4HResponse { - statusCode: number; - data: DataType; - error: string; -} - -interface D4HError { - statusCode: number; - error: string; -} - export interface GetMemberOptions { includeDetails?: boolean; } @@ -25,17 +15,22 @@ export interface GetMembersOptions { includeDetails?: boolean; } +export interface GetGroupsOptions { + memberId?: number; + title?: string; +} + export default class D4H { - private readonly _token: string; + private readonly _httpUtils: HttpUtils; constructor(token: string) { - if (!token) { - throw new Error("Token cannot be empty"); - } - - this._token = token; + this._httpUtils = new HttpUtils(token, D4H_FETCH_LIMIT); } + /********************************************/ + /**************** MEMBERS *******************/ + /********************************************/ + async getMember(id: number, options?: GetMemberOptions): Promise { let url = new URL(`${D4H_BASE_URL}/team/members/${id}`) @@ -47,15 +42,14 @@ export default class D4H { } } - return await this.get(url); + return await this._httpUtils.get(url); } async getMembers(options?: GetMembersOptions): Promise { - let members: Member[] = []; - let baseUrl = new URL(`${D4H_BASE_URL}/team/members`) + let url = new URL(`${D4H_BASE_URL}/team/members`) if (options !== undefined) { - let optionsList = baseUrl.searchParams; + let optionsList = url.searchParams; if (options.groupId !== undefined) { optionsList.append("group_id", "true"); @@ -70,38 +64,33 @@ export default class D4H { } } - let offset = 0; - while (true) { - let url = new URL(baseUrl); - url.searchParams.append('offset', offset.toString()); + return await this._httpUtils.getMany(url); + } - let newMembers = await this.get(url); - members = members.concat(newMembers); - offset += D4H_FETCH_LIMIT; + /********************************************/ + /***************** GROUPS *******************/ + /********************************************/ - if (newMembers.length < D4H_FETCH_LIMIT) { - break; + async getGroup(id: number): Promise { + let url = new URL(`${D4H_BASE_URL}/team/groups/${id}`) + return await this._httpUtils.get(url); + } + + async getGroups(options?: GetGroupsOptions): Promise { + let url = new URL(`${D4H_BASE_URL}/team/groups`) + + if (options !== undefined) { + let optionsList = url.searchParams; + + if (options.memberId !== undefined) { + optionsList.append("member_id", options.memberId.toString()); + } + + if (options.title !== undefined) { + optionsList.append("title", options.title); } } - return members; - } - - private async get(url: URL): Promise { - let method = "GET"; - let headers = { - "Authorization": `Bearer ${this._token}`, - }; - - console.log(url); - - let rawResponse = await fetch(url.toString(), { method, headers }); - let response = await rawResponse.json() as D4HResponse; - - if (response.statusCode !== 200) { - throw response as D4HError; - } - - return response.data as DataType; + return await this._httpUtils.getMany(url); } } \ No newline at end of file diff --git a/src/group.ts b/src/group.ts new file mode 100644 index 0000000..ca8871c --- /dev/null +++ b/src/group.ts @@ -0,0 +1,5 @@ +export interface Group { + bundle: string; + id: number; + title: string; +} \ No newline at end of file diff --git a/src/httpUtils.ts b/src/httpUtils.ts new file mode 100644 index 0000000..a05d896 --- /dev/null +++ b/src/httpUtils.ts @@ -0,0 +1,63 @@ +interface D4HResponse { + statusCode: number; + data: DataType; + error: string; +} + +interface D4HError { + statusCode: number; + error: string; +} + +export default class HttpUtils { + private readonly _fetchLimit: number; + private readonly _token: string; + + constructor(token: string, fetchLimit: number) { + if (!token) { + throw new Error("Token cannot be empty"); + } + + this._fetchLimit = fetchLimit; + this._token = token; + } + + async get(url: URL): Promise { + let method = "GET"; + let headers = { + "Authorization": `Bearer ${this._token}`, + }; + + console.log(url); + + let rawResponse = await fetch(url.toString(), { method, headers }); + let response = await rawResponse.json() as D4HResponse; + + if (response.statusCode !== 200) { + throw response as D4HError; + } + + return response.data as DataType; + } + + async getMany(url: URL): Promise { + let results: DataType[] = []; + + let offset = 0; + while (true) { + let urlWithOffset = new URL(url); + url.searchParams.append('offset', offset.toString()); + url.searchParams.append('limit', this._fetchLimit.toString()); + + let newResults = await this.get(urlWithOffset); + results = results.concat(newResults); + offset += this._fetchLimit; + + if (newResults.length < this._fetchLimit) { + break; + } + } + + return results; + } +} diff --git a/src/member.ts b/src/member.ts index 92cf34a..415ba2d 100644 --- a/src/member.ts +++ b/src/member.ts @@ -1,9 +1,15 @@ +export enum CustomFieldType { + Number = "number", + Text = "text", + Date = "date", +} + export interface CustomField { id: number; - type: string; + type: CustomFieldType; label: string; - value_string: string; - value: string; + value_string: string | undefined; + value: string | undefined; } export interface EmergencyContact { @@ -30,6 +36,7 @@ export interface Member { custom_fields: CustomField[]; email: string; emergency_contacts: EmergencyContact; + group_ids: number[]; homephone: string; id: number; mobilephone: string;