diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a0e9ce62..1cb16129d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## Next release + +- Adds `allChildren` function in User service to get a paginated list of children +- Adds `getNextPage` function in User service to get next paginated list of children + ## v7.0.0 (2023-12-06) - Removes `withCarbonOffset` parameter from shipment create and buy functions diff --git a/src/services/user_service.js b/src/services/user_service.js index 0a6571180..54b51bcbb 100644 --- a/src/services/user_service.js +++ b/src/services/user_service.js @@ -116,4 +116,33 @@ export default (easypostClient) => return Promise.reject(e); } } + + /** + * Retrieve a paginated list of children user {@link User user}. + * See {@link https://www.easypost.com/docs/api/node#child-users EasyPost API Documentation} for more information. + * @param {Object} params - Parameters to filter the list of children users. + * @returns {Object} - An object containing a list of {@link Children User} and pagination information. + */ + static async allChildren(params) { + const url = 'beta/users/children'; // TODO: Use GA endpoint + + try { + const response = await easypostClient._get(url, params); + + return this._convertToEasyPostObject(response.body, params); + } catch (e) { + return Promise.reject(e); + } + } + + /** + * Retrieve the next page of children collection. + * @param {Object} children An object containing a list of {@link Children children} and pagination information. + * @param {Number} pageSize The number of records to return on each page + * @returns {EasyPostObject|Promise} The retrieved {@link EasyPostObject}-based class instance, or a `Promise` that rejects with an error. + */ + static async getNextPage(children, pageSize = null) { + const url = 'beta/users/children'; // TODO: Use GA endpoint + return this._getNextPage(url, 'children', children, pageSize); + } }; diff --git a/test/cassettes/User-Service_2658581389/retrieves-a-paginated-list-of-children_3912335410/recording.har b/test/cassettes/User-Service_2658581389/retrieves-a-paginated-list-of-children_3912335410/recording.har new file mode 100644 index 000000000..e8645ae94 --- /dev/null +++ b/test/cassettes/User-Service_2658581389/retrieves-a-paginated-list-of-children_3912335410/recording.har @@ -0,0 +1,163 @@ +{ + "log": { + "_recordingName": "User Service/retrieves a paginated list of children", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "360e29b6c46cb77351451f989a439019", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept-encoding", + "value": "gzip, deflate" + }, + { + "name": "accept", + "value": "application/json" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "host", + "value": "api.easypost.com" + } + ], + "headersSize": 388, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "page_size", + "value": "5" + } + ], + "url": "https://api.easypost.com//beta/users/children?page_size=5" + }, + "response": { + "bodySize": 332, + "content": { + "encoding": "base64", + "mimeType": "application/json; charset=utf-8", + "size": 332, + "text": "{\"children\":[{\"id\":\"user_584be78af2f141e988b6c60dda9dd8fd\",\"object\":\"User\",\"parent_id\":\"user_54356a6b96c940d8913961a3c7b909f2\",\"name\":\"Test User2\",\"phone_number\":\"\",\"verified\":true,\"created_at\":\"2023-12-11T17:13:38Z\"},{\"id\":\"user_437e724f37de412db6df8821968d8d3c\",\"object\":\"User\",\"parent_id\":\"user_54356a6b96c940d8913961a3c7b909f2\",\"name\":\"Test User2\",\"phone_number\":\"\",\"verified\":true,\"created_at\":\"2023-12-11T17:13:43Z\"}],\"has_more\":false}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-xss-protection", + "value": "1; mode=block" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-download-options", + "value": "noopen" + }, + { + "name": "x-permitted-cross-domain-policies", + "value": "none" + }, + { + "name": "referrer-policy", + "value": "strict-origin-when-cross-origin" + }, + { + "name": "x-ep-request-uuid", + "value": "76c4c42865774e8fe779868800208452" + }, + { + "name": "cache-control", + "value": "private, no-cache, no-store" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "content-type", + "value": "application/json; charset=utf-8" + }, + { + "name": "x-runtime", + "value": "0.049909" + }, + { + "name": "vary", + "value": "Origin" + }, + { + "name": "content-encoding", + "value": "gzip" + }, + { + "name": "transfer-encoding", + "value": "chunked" + }, + { + "name": "x-node", + "value": "bigweb41nuq" + }, + { + "name": "x-version-label", + "value": "easypost-202312082253-518d5f5344-master" + }, + { + "name": "x-backend", + "value": "easypost" + }, + { + "name": "x-proxied", + "value": "intlb1nuq b3de2c47ef, extlb1nuq 003ad9bca0" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload" + }, + { + "name": "connection", + "value": "close" + } + ], + "headersSize": 724, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2023-12-11T18:01:50.687Z", + "time": 452, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 452 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/cassettes/User-Service_2658581389/retrieves-next-page-of-children_3033480518/recording.har b/test/cassettes/User-Service_2658581389/retrieves-next-page-of-children_3033480518/recording.har new file mode 100644 index 000000000..709c0bb4b --- /dev/null +++ b/test/cassettes/User-Service_2658581389/retrieves-next-page-of-children_3033480518/recording.har @@ -0,0 +1,163 @@ +{ + "log": { + "_recordingName": "User Service/retrieves next page of children", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "360e29b6c46cb77351451f989a439019", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept-encoding", + "value": "gzip, deflate" + }, + { + "name": "accept", + "value": "application/json" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "host", + "value": "api.easypost.com" + } + ], + "headersSize": 388, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "page_size", + "value": "5" + } + ], + "url": "https://api.easypost.com//beta/users/children?page_size=5" + }, + "response": { + "bodySize": 332, + "content": { + "encoding": "base64", + "mimeType": "application/json; charset=utf-8", + "size": 332, + "text": "{\"children\":[{\"id\":\"user_584be78af2f141e988b6c60dda9dd8fd\",\"object\":\"User\",\"parent_id\":\"user_54356a6b96c940d8913961a3c7b909f2\",\"name\":\"Test User2\",\"phone_number\":\"\",\"verified\":true,\"created_at\":\"2023-12-11T17:13:38Z\"},{\"id\":\"user_437e724f37de412db6df8821968d8d3c\",\"object\":\"User\",\"parent_id\":\"user_54356a6b96c940d8913961a3c7b909f2\",\"name\":\"Test User2\",\"phone_number\":\"\",\"verified\":true,\"created_at\":\"2023-12-11T17:13:43Z\"}],\"has_more\":false}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-xss-protection", + "value": "1; mode=block" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "x-download-options", + "value": "noopen" + }, + { + "name": "x-permitted-cross-domain-policies", + "value": "none" + }, + { + "name": "referrer-policy", + "value": "strict-origin-when-cross-origin" + }, + { + "name": "x-ep-request-uuid", + "value": "76c4c42765775150e7798baf002477dc" + }, + { + "name": "cache-control", + "value": "private, no-cache, no-store" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "content-type", + "value": "application/json; charset=utf-8" + }, + { + "name": "x-runtime", + "value": "0.036861" + }, + { + "name": "vary", + "value": "Origin" + }, + { + "name": "content-encoding", + "value": "gzip" + }, + { + "name": "transfer-encoding", + "value": "chunked" + }, + { + "name": "x-node", + "value": "bigweb38nuq" + }, + { + "name": "x-version-label", + "value": "easypost-202312082253-518d5f5344-master" + }, + { + "name": "x-backend", + "value": "easypost" + }, + { + "name": "x-proxied", + "value": "intlb1nuq b3de2c47ef, extlb1nuq 003ad9bca0" + }, + { + "name": "strict-transport-security", + "value": "max-age=31536000; includeSubDomains; preload" + }, + { + "name": "connection", + "value": "close" + } + ], + "headersSize": 724, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2023-12-11T18:13:36.063Z", + "time": 462, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 462 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/test/services/user.test.js b/test/services/user.test.js index 2631c56d6..d538cc919 100644 --- a/test/services/user.test.js +++ b/test/services/user.test.js @@ -5,6 +5,8 @@ import EasyPostClient from '../../src/easypost'; import Brand from '../../src/models/brand'; import User from '../../src/models/user'; import * as setupPolly from '../helpers/setup_polly'; +import Fixture from '../helpers/fixture'; +import EndOfPaginationError from '../../src/errors/general/end_of_pagination_error'; /* eslint-disable func-names */ describe('User Service', function () { @@ -84,4 +86,32 @@ describe('User Service', function () { expect(brand.id).to.match(/^brd_/); expect(brand.color).to.equal(color); }); + + it('retrieves a paginated list of children', async function () { + const response = await this.client.User.allChildren({ page_size: Fixture.pageSize() }); + + const childrenArray = response.children; + + expect(childrenArray.length).to.be.lessThanOrEqual(Fixture.pageSize()); + expect(response.has_more).to.exist; + childrenArray.forEach((children) => { + expect(children).to.be.an.instanceOf(User); + }); + }); + + it('retrieves next page of children', async function () { + try { + const children = await this.client.User.allChildren({ page_size: Fixture.pageSize() }); + const nextPage = await this.client.User.getNextPage(children, Fixture.pageSize()); + + const firstIdOfFirstPage = children.children[0].id; + const firstIdOfSecondPage = nextPage.children[0].id; + + expect(firstIdOfFirstPage).to.not.equal(firstIdOfSecondPage); + } catch (error) { + if (!(error instanceof EndOfPaginationError)) { + throw new Error('Test failed intentionally'); + } + } + }); }); diff --git a/types/User/User.d.ts b/types/User/User.d.ts index b3ee6c822..34b18892a 100644 --- a/types/User/User.d.ts +++ b/types/User/User.d.ts @@ -156,4 +156,19 @@ export declare class User implements IUser { * @requires production API Key. */ static delete(id: string): void; + + /** + * Retrieve a list of all children user. + * + * The Children List is a paginated list of all {@link User} objects associated with the given API Key. + * It accepts a variety of parameters which can be used to modify the scope. + * The has_more attribute indicates whether additional pages can be requested. + * The recommended way of paginating is to use either the `before_id` or `after_id` parameter to specify where the next page begins. + * + * @see https://www.easypost.com/docs/api/node#child-users + * + * @param {Object} params - The parameters to use for the request. + * @returns {Object} - An object containing a list of {@link Children children} and pagination information. + */ + static allChildren(params: Object): Promise<{ children: User[]; has_more: boolean }>; }