diff --git a/examples/channels.ts b/examples/channels.ts new file mode 100644 index 0000000..fb69b30 --- /dev/null +++ b/examples/channels.ts @@ -0,0 +1,203 @@ +// Import the SDK class from the mainflux-sdk package +import SDK from '../src/sdk' + +const defaultUrl = 'http://localhost' + +const mySdk = new SDK({ + thingsUrl: defaultUrl + ':9000', + usersUrl: defaultUrl + ':9002' +}) + +// Channels.ts examples. + +const token = '' + +mySdk.channels + .CreateChannel( + { name: '' }, token) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.channels + .Channel('', token) + .then((response: any) => { + console.log(response) + }) + .catch((error: any) => { + console.log(error) + }) + +mySdk.channels + .Channels({ offset: 0, limit: 10 }, token) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.channels + .UpdateChannel( + { id: '', name: '' }, + token + ) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.channels + .Disable({ id: '' }, token) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.channels + .Enable({ id: '' }, token) + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.channels + .ChannelsByThing( + '', + { offset: 0, limit: 5 }, + token + ) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.channels + .ConnectThing( + '', + '', + token + ) + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.channels + .DisconnectThing( + '', + '', + token + ) + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.channels + .Connect( + '', + '', + token + ) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.channels + .Disconnect( + '', + '', + token + ) + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.channels + .ListChannelUsers( + '', + { offset: 0, limit: 5 }, + token + ) + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error: any) => { + console.log(error) + }) + +mySdk.channels + .ListChannelUsersGroups( + '', + { offset: 0, limit: 5 }, + token + ) + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error: any) => { + console.log(error) + }) + +mySdk.channels + .ChannelPermissions('', token) + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.channels + .AddUserToChannel( + '', + [ + '', '' + ], + 'administrator', + token + ) + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.channels + .RemoveUserFromChannel( + '', + [ + '', '' + ], + 'administrator', + token + ) + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error) => { + console.log(error) + }) diff --git a/examples/things.ts b/examples/things.ts new file mode 100644 index 0000000..9c01beb --- /dev/null +++ b/examples/things.ts @@ -0,0 +1,180 @@ +// Import the SDK class from the mainflux-sdk package +import SDK from '../src/sdk' + +const defaultUrl = 'http://localhost' + +const mySdk = new SDK({ + thingsUrl: defaultUrl + ':9000', + usersUrl: defaultUrl + ':9002' +}) + +// Things.ts examples. + +const token = '' + +mySdk.things + .Create( + { name: '' }, token + ) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.things + .Disable({ id: '' }, token) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.error(error) + }) + +mySdk.things + .Enable({ id: '' }, token) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.error(error) + }) + +mySdk.things + .UpdateThing( + { id: '', name: '' }, token) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.things + .UpdateThingSecret({ id: '', credentials: { secret: 'newSecret' } }, token + ) + .then((response: any) => { + console.log(response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.things + .UpdateThingTags( + { id: '', tags: ['', ''] }, + token + ) + .then((response: any) => { + console.log(response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.things + .ThingsByChannel('', { offset: 0, limit: 5 }, token) + .then((response: any) => { + console.log(response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.things + .Things({ offset: 0, limit: 10 }, token) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.things + .Thing('', token) + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.things + .ThingsPermissions('', token) + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.things + .IdentifyThing('') + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.things + .ShareThing( + '', + + 'administrator', + [ + '', '' + ], token) + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.things + .UnShareThing( + '', + '', + + [ + '', '' + ], token) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.things + .ListThingUsers( + '', + { offset: 0, limit: 10 }, + token + ) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.things + .DeleteThing({ id: '' }, token) + .then((response: any) => { + console.log('response: ', response) + }) + .catch((error) => { + console.log(error) + }) + +mySdk.things + .CreateThings([{ name: '' }, { name: '' }], token) + .then((response: any) => { + console.log('response:', response) + }) + .catch((error) => { + console.log(error) + }) diff --git a/src/bootstrap.js b/src/bootstrap.js deleted file mode 100644 index dee43e8..0000000 --- a/src/bootstrap.js +++ /dev/null @@ -1,365 +0,0 @@ -const axios = require('axios'); -const Errors = require('./errors'); - -class Bootstrap { - //Bootstraps API Client - /** - * @class Bootstrap - * Bootstrap is used to manage bootstrap configurations. - * It is used to create, update, view and remove bootstrap configurations. - * It is also used to bootstrap a thing. - * @param {string} bootstraps_url - The url of the bootstraps service. - * @param {string} content_type - The content type of the request. - * @param {string} bootstrapsEndpoint - The endpoint of the bootstraps service which is - * configs. - * @returns {Bootstrap} - Returns a Bootstrap object. - * - */ - constructor(bootstraps_url) { - this.bootstraps_url = new URL(bootstraps_url); - this.content_type = "application/json"; - this.bootstrapsEndpoint = "configs"; - } - - ValidateConfigAndToken(config, token){ - //Validate config - if (typeof config !== "object" || config === null) { - throw new Error('Invalid config parameter. Expected an object.'); - } - - // Validate token - if (typeof token !== "string" || token === null) { - throw new Error('Invalid token parameter. Expected a string.'); - } - } - - bootstrapError = new Errors; - - Create(config, token){ - //Create a bootstrap configuration - /** - * @method Create - Create a new bootstrap configuration. - * Some of the key data needed include the external_key and external_id which must be - * specific to the thing provided with the thing_id. Mind that every configuration - * must have a specific thing_id. - * @param {object} config - The configuration object. - * @param {string} token - The token to be used for authentication. - * @example - * const config = { - * "external_id": "345", - * "external_key": "012", - * "thing_id": "3d49a42f-63fd-491b-9784-adf4b64ef347", - * "name": "thing_name" - * } - */ - - this.ValidateConfigAndToken(config, token); - - const options = { - method: "post", - maxBodyLength: 2000, - url: new URL (`things/${this.bootstrapsEndpoint}`, this.bootstraps_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - data: config, - }; - return axios.request(options) - .then((_response) => { - return "Configuration added"; - }) - .catch((error) => { - if (error.response) { - return this.bootstrapError.HandleError( - this.bootstrapError.bootstraps.create, - error.response.status - ); - }; - }); - } - - Whitelist(config, thing_id, token){ - //Update a bootstrap configuration - /** - * @method Whitelist - Allows a logged in user to update a bootstrap configuration. - * This changes the status of the config to whitelisted. - * @param {object} config - The configuration object. - * @param {string} token - The token to be used for authentication. - * @example - * const config = { - * "external_id": "345", - * "external_key": "012", - * "thing_id": "3d49a42f-63fd-491b-9784-adf4b64ef347", - * "name": "thing_name" - * } - */ - - if (typeof thing_id !== "string" || thing_id === null) { - throw new Error('Invalid thing_id parameter. Expected a string.'); - } - - this.ValidateConfigAndToken(config, token); - - const options = { - method: "put", - maxBodyLength: 2000, - url: new URL (`things/state/${thing_id}`, this.bootstraps_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - data: config, - }; - return axios.request(options) - .then((_response) => { - return "Configuration updated"; - }) - .catch((error) => { - if (error.response) { - return this.bootstrapError.HandleError( - this.bootstrapError.bootstraps.whitelist, - error.response.status - ); - }; - }); - } - - Update(config, thing_id, token){ - //Update a bootstrap configuration - /** - * @method Update - Allows a logged in user to update a bootstrap configuration. - * This can change the name of the config and metadata. - * @param {object} config - The configuration object. - * @param {string} token - The token to be used for authentication. - * @example - * const config = { - * "external_id": "345", - * "external_key": "012", - * "thing_id": "3d49a42f-63fd-491b-9784-adf4b64ef347", - * "name": "thing_name" - * } - */ - - if (typeof thing_id !== "string" || thing_id === null) { - throw new Error('Invalid thing_id parameter. Expected a string.'); - } - - this.ValidateConfigAndToken(config, token); - - const options = { - method: "put", - maxBodyLength: 2000, - url: new URL (`things/configs/${thing_id}`, this.bootstraps_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - data: config, - }; - return axios.request(options) - .then((_response) => { - return "Configuration updated"; - }) - .catch((error) => { - if (error.response) { - return this.bootstrapError.HandleError( - this.bootstrapError.bootstraps.update, - error.response.status - ); - }; - }); - } - - View(thing_id, token){ - //View a bootstrap configuration - /** - * @method View - Allows a logged in user to view a bootstrap configuration. - * Once provided with the thing_id and a valid token, it returns the configuration object. - * @param {string} thing_id - The thing_id of the configuration to be viewed. - * @param {string} token - The token to be used for authentication. - */ - - if (typeof thing_id !== "string" || thing_id === null) { - throw new Error('Invalid thing_id parameter. Expected a string.'); - } - - this.ValidateConfigAndToken({}, token); - - const options = { - method: "get", - maxBodyLength: 2000, - url: new URL (`things/${this.bootstrapsEndpoint}/${thing_id}`, this.bootstraps_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - } - }; - return axios.request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - if (error.response) { - return this.bootstrapError.HandleError( - this.bootstrapError.bootstraps.view, - error.response.status - ); - }; - }); - } - - UpdateCerts(config_id,client_cert,client_key, ca, token){ - //Update certs of a bootstrap configuration - /** - * @method UpdateCerts - Allows a logged in user to update the certs of a bootstrap configuration. - * Update is performed by replacing the current certificate data with values provided in a request payload. - * @param {string} config_id - The config_id of the configuration to be updated. This can also mean the thing_id. - * @param {string} client_cert - The client certificate to be used. - * @param {string} client_key - The client key to be used. - * @param {string} ca - The certificate authority to be used. - * @param {string} token - The token to be used for authentication. - * - */ - - if (typeof config_id !== "string" || - typeof client_cert !== "string" || - typeof client_key !== "string" || - typeof ca !== "string" || - typeof token !== "string" ) { - throw new Error('Invalid parameter types. Expected strings for config_id, client_cert, client_key, ca and token.'); - }; - - const payload = { - "client_cert": client_cert, - "client_key": client_key, - "ca_cert": ca, - } - const options = { - method: "patch", - maxBodyLength: 2000, - url: new URL(`configs/certs/${config_id}`, this.bootstraps_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - data: payload, - }; - return axios.request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - if (error.response) { - return this.bootstrapError.HandleError( - this.bootstrapError.bootstraps.updatecerts, - error.response.status - ); - }; - }); - } - - Remove(config_id, token){ - //Remove a bootstrap configuration - /** - * @method Remove - Allows a logged in user to delete a bootstrap configuration. - * @param {string} config_id - The config_id of the configuration to be deleted. - * This can also mean the thing_id. - * @param {string} token - The token to be used for authentication. - * - */ - - if (typeof config_id !== "string" || config_id === null) { - throw new Error('Invalid config_id parameter. Expected a string.'); - } - - this.ValidateConfigAndToken({}, token); - - const options = { - method: "delete", - maxBodyLength: 2000, - url: new URL (`things/${this.bootstrapsEndpoint}/${config_id}`, this.bootstraps_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - }; - return axios.request(options) - .then((_response) => { - return "Configuration removed"; - }) - .catch((error) => { - if (error.response) { - return this.bootstrapError.HandleError( - this.bootstrapError.bootstraps.remove, - error.response.status - ); - }; - }); - } - - Bootstrap(external_id, external_key){ - //Retrive a bootstrap configuration - /** - * @method Bootstrap - Retrieves a configuration with given external ID and encrypted external key. - * @param {string} external_id - The external ID of the configuration to be retrieved. - * @param {string} external_key - The encrypted external key of the configuration to be retrieved. - * @return {object} - Returns a config object. - */ - - if (typeof external_id !== "string" || typeof external_key !== "string") { - throw new Error('Invalid type of parameters. Expected strings for external_key and external_id.'); - } - - const options = { - method: "get", - maxBodyLength: 2000, - url: new URL (`things/bootstrap/${external_id}`, this.bootstraps_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Thing ${external_key}`, - }, - }; - return axios.request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - if (error.response) { - return this.bootstrapError.HandleError( - this.bootstrapError.bootstraps.bootstrap, - error.response.status - ); - }; - }); - } - - Bootstrap(external_id, external_key) { - //Retrive a bootstrap configuration - /** - * @method Bootstrap - Retrieves a configuration with given external ID and encrypted external key. - * @param {string} external_id - The external ID of the configuration to be retrieved. - * @param {string} external_key - The encrypted external key of the configuration to be retrieved. - * @return {object} - Returns a config object. - */ - const options = { - method: "get", - maxBodyLength: Infinity, - url: `${this.bootstraps_url}/things/bootstrap/${external_id}`, - headers: { - "Content-Type": this.content_type, - Authorization: `Thing ${external_key}`, - }, - }; - return axios - .request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - return error.response.data; - }); - } -} - -module.exports = Bootstrap; diff --git a/src/channels.js b/src/channels.js deleted file mode 100644 index bb82a16..0000000 --- a/src/channels.js +++ /dev/null @@ -1,343 +0,0 @@ -const axios = require("axios"); -const Errors = require("./errors"); - -class Channels { - //Channels API client - /** - * @class Channels - - * Channels API is used for managing Channels. It is used for creating new - * channels, retrieving them, updating them and disabling them - * @param {string} channels_url - URL to the Channels service - * @param {string} content_type - Content type for the requests which is an application - * json - * @param {string} channelsEndpoint - Endpoint for the channels' service. - * @returns {Object} -Channels object - * - */ - - constructor(channels_url) { - this.channels_url = new URL (channels_url); - this.content_type = "application/json"; - this.channelsEndpoint = "channels"; - } - ValidateChannelChannelIDAndToken(channel, channel_id, token) { - //Validate channel - if (typeof channel !== "object" || channel === null) { - throw new Error('Invalid channel parameter. Expected an object.'); - } - - // Validate channel_id - if (typeof channel_id !== "string" || channel_id === null) { - throw new Error('Invalid channel_id parameter. Expected a string.'); - } - - // Validate token - if (typeof token !== "string" || token === null) { - throw new Error('Invalid token parameter. Expected a string.'); - } - }; - - channelError = new Errors; - - Create(channel, token) { - //Creates a new channel - /** - * @method Create - Creates new channels when provided with a channel object - * with viable fresh information and a valid token. - * @param {Object} channel - Channel Object with a name and id. - * @param {String} token - An access token that is valid. - * @returns {Object} - User object. - * @example - * const channel = { - * "name": "channelName", - * "description": "long channel description", - * "parent_id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", - * "metadata": { - * "domain": "example.com" - * }, - * "status": "enabled", - * "owner_id": "bb7edb32-2eac-4aad-aebe-ed96fe073879" - * } - * - */ - - this.ValidateChannelChannelIDAndToken(channel, '', token); - - const options = { - method: "post", - maxBodyLength: 2000, - url: new URL (this.channelsEndpoint, this.channels_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - data: channel, - }; - return axios.request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - if (error.response) { - return this.channelError.HandleError( - this.channelError.channels.create, - error.response.status, - ); - }; - }); - } - - CreateBulk(channels, token) { - //Creates multiple channels. - /** - * @method Create_bulk - Creates multiple channels when provided with a channel object - * with viable fresh information and a valid token. - * @param {List} channels - Channel Object with a name and id. - * @param {String} token - An access token that is valid. - * @returns {Object} - User object. - * @example - * const channels = [ - * { "name": "channelA", "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879" }, - * { "name": "channelB", "id": "290b0f49-7a57-4b8c-9e4e-fbf17c6ab7d9" } - * ] - */ - - if (!Array.isArray(channels)) { - throw new Error('Invalid parameter. Expected an array for the "channels" parameter.'); - } - - this.ValidateChannelChannelIDAndToken({}, '', token); - - const options = { - method: "post", - maxBodyLength: 2000, - url: new URL (`${this.channelsEndpoint}/bulk`, this.channels_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - data: channels, - }; - return axios.request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - if (error.response) { - return this.channelError.HandleError( - this.channelError.channels.createbulk, - error.response.status, - ); - }; - }); - } - - Get(channel_id, token) { - //Retrieves channel with specified id. - /** - * @method Get - Retrieves channel with specified id and a valid token. - * @param {String} channel_id - Channel id. - * @param {String} token - An access token that is valid. - * @returns {Object} - Channel object. - */ - - this.ValidateChannelChannelIDAndToken({}, channel_id, token); - - const options = { - method: "get", - maxBodyLength: 2000, - url: new URL (`${this.channelsEndpoint}/${channel_id}`, this.channels_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - }; - return axios.request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - if (error.response) { - return this.channelError.HandleError( - this.channelError.channels.get, - error.response.status, - ); - }; - }); - } - - GetByThing(channel_id, query_params, token) { - //Retrieves list of things connected to specified channel with pagination metadata. - /** - * @method GetByThing - Retrieves list of things connected to specified channel with pagination metadata. - * @param {String} channel_id - Channel id. - * @param {Object} query_params - Query parameters for the request. - * @param {String} token - An access token that is valid. - * @returns {List} - Things list. - */ - - if (typeof query_params !== 'object' || query_params === null || Array.isArray(query_params)) { - throw new Error('Invalid query parameters. Expected an object.'); - }; - - this.ValidateChannelChannelIDAndToken({}, channel_id, token); - - const options = { - method: "get", - maxBodyLength: 2000, - url: new URL (`${this.channelsEndpoint}/${channel_id}/things?${new URLSearchParams(query_params).toString()}`, this.channels_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - }; - return axios.request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - if (error.response) { - return this.channelError.HandleError( - this.channelError.channels.getbything, - error.response.status, - ); - }; - }); - } - - GetAll(query_params, token) { - //Provides a list of all channels with pagination metadata. - /** - * @method GetAll - Provides a list of all channels with pagination metadata. - * @param {Object} query_params - Query parameters for the request. - * @param {String} token - An access token that is valid. - * @returns {Object} - Channel Object. - */ - - if (typeof query_params !== 'object' || query_params === null || Array.isArray(query_params)) { - throw new Error('Invalid query parameters. Expected an object.'); - }; - - this.ValidateChannelChannelIDAndToken({}, '', token); - - const options = { - method: "get", - maxBodyLength: 2000, - url: new URL (`${this.channelsEndpoint}?${new URLSearchParams(query_params).toString()}`, this.channels_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - }; - return axios.request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - if (error.response) { - return this.channelError.HandleError( - this.channelError.channels.getall, - error.response.status, - ); - }; - }); - } - - Update(channel_id, channel, token) { - //Updates channel with specified id. - /** - * @method Update - Updates channel with specified id. - * @param {Object} channel - Channel object with new information. - * @param {String} token - An access token that is valid. - * @returns {Object} - Channel Object. - */ - - this.ValidateChannelChannelIDAndToken(channel, channel_id, token); - - const options = { - method: "put", - maxBodyLength: 2000, - url: new URL (`${this.channelsEndpoint}/${channel_id}`, this.channels_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - data: channel, - }; - return axios.request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - if (error.response) { - return this.channelError.HandleError( - this.channelError.channels.update, - error.response.status, - ); - }; - }); - } - - Disable(channel_id, token) { - //Disables channel with specified id. - /** - * @method Disable - Disables channel with specified id. - * @param {Object} channel - Channel object with new information. - * @param {String} token - An access token that is valid. - * @returns {Object} - Channel Object. - */ - - this.ValidateChannelChannelIDAndToken({}, channel_id, token); - - const options = { - method: "post", - maxBodyLength: 2000, - url: new URL (`${this.channelsEndpoint}/${channel_id}/disable`, this.channels_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - }; - return axios.request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - if (error.response) { - return this.channelError.HandleError( - this.channelError.channels.disable, - error.response.status, - ); - }; - }); - } - - Disable(channel, token) { - //Disables channel with specified id. - /** - * @method Disable - Disables channel with specified id. - * @param {Object} channel - Channel object with new information. - * @param {String} token - An access token that is valid. - * @returns {Object} - Channel Object. - */ - const options = { - method: "post", - maxBodyLength: Infinity, - url: `${this.channels_url}/${this.channelsEndpoint}/${channel["id"]}/disable`, - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - }; - return axios - .request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - return error.response.data; - }); - } -} - -module.exports = Channels; diff --git a/src/channels.ts b/src/channels.ts new file mode 100644 index 0000000..1ab7d00 --- /dev/null +++ b/src/channels.ts @@ -0,0 +1,711 @@ +import Errors from './errors' + +import { + type Channel, + type GroupsPage, + type QueryParams, + type Permissions, + type Response, + type ChannelsPage, + type UsersPage, + type groupRelation +} from './defs' +export default class Channels { + // Channels API client + /** + * @class Channels - + * Channels API is used for managing Channels. It is used for creating new + * channels, retrieving them, updating them and disabling them + * @param {string} channels_url - URL to the Channels service + * @param {string} content_type - Content type for the requests which is an application + * json + * @param {string} channelsEndpoint - Endpoint for the channels' service. + * @returns {Object} -Channels object + * + */ + private readonly usersUrl?: URL + private readonly contentType: string + private readonly channelsEndpoint: string + private readonly channelError: Errors + private readonly thingsUrl: URL + public constructor ({ usersUrl, thingsUrl }: { usersUrl?: string, thingsUrl: string }) { + this.thingsUrl = new URL(thingsUrl) + if (usersUrl !== undefined) { + this.usersUrl = new URL(usersUrl) + } else { + this.usersUrl = new URL('') + } + this.contentType = 'application/json' + this.channelsEndpoint = 'channels' + this.channelError = new Errors() + } + + public async CreateChannel ( + channel: Channel, + token: string + ): Promise { + // Creates a new a channel + /** + * @method Create - Creates new channels when provided with a channel object + * with viable fresh information and a valid token. + * @param {Object} channel - Channel Object with a name and id. + * @param {String} token - An access token that is valid. + * @returns {Object} - Channel object. + * @example + * const channel = { + * "name": "channelName", + * "description": "long channel description", + * "parent_id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + * "metadata": { + * "domain": "example.com" + * }, + * "status": "enabled", + * "owner_id": "bb7edb32-2eac-4aad-aebe-ed96fe073879" + * } + * + */ + const options: RequestInit = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify(channel) + } + try { + const response = await fetch( + new URL(this.channelsEndpoint, this.thingsUrl).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const newChannel: Channel = await response.json() + return newChannel + } catch (error) { + throw error + } + } + + public async Channel (channelId: string, token: string): Promise { + // Retrieves channel with specified id. + /** + * @method Get - Retrieves channel with specified id and a valid token. + * @param {String} channel_id - Channel id. + * @param {String} token - An access token that is valid. + * @returns {Object} - Channel object. + */ + const options: RequestInit = { + method: 'GET', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + } + } + try { + const response = await fetch( + new URL(`${this.channelsEndpoint}/${channelId}`, this.thingsUrl).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const channel: Channel = await response.json() + return channel + } catch (error) { + throw error + } + } + + public async ChannelsByThing ( + thingID: string, + queryParams: QueryParams, + token: string + ): Promise { + // Retrieves list of things connected to specified channel with pagination metadata. + /** + * @method GetByThing - Retrieves list of things connected to specified channel with pagination metadata. + * @param {String} channel_id - Channel id. + * @param {Object} queryParams - Query parameters for the request. + * @param {String} token - An access token that is valid. + * @returns {List} - Channels Page. + */ + const stringParams: Record = Object.fromEntries( + Object.entries(queryParams).map(([key, value]) => [key, String(value)]) + ) + const options = { + method: 'GET', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + } + } + try { + const response = await fetch( + new URL( + `things/${thingID}/${this.channelsEndpoint}?${new URLSearchParams( + stringParams + ).toString()}`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const channels: ChannelsPage = await response.json() + return channels + } catch (error) { + throw error + } + } + + public async Channels ( + queryParams: QueryParams, + token: string + ): Promise { + // Provides a list of all channels with pagination metadata. + /** + * @method GetAll - Provides a list of all channels with pagination metadata. + * @param {Object} queryParams - Query parameters for the request. + * @param {String} token - An access token that is valid. + * @returns {Object} - returns Channels Page + */ + const stringParams: Record = Object.fromEntries( + Object.entries(queryParams).map(([key, value]) => [key, String(value)]) + ) + const options: RequestInit = { + method: 'GET', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + } + } + try { + const response = await fetch( + new URL( + `${this.channelsEndpoint}?${new URLSearchParams( + stringParams + ).toString()}`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const channels: ChannelsPage = await response.json() + return channels + } catch (error) { + throw error + } + } + + public async UpdateChannel ( + channel: Channel, + token: string + ): Promise { + // Updates channel with specified id. + /** + * @method Update - Updates channel with specified id. + * @param {Object} channel - Channel object with new information. + * @param {String} token - An access token that is valid. + * @returns {Object} - returns updated Channel. + */ + + const options: RequestInit = { + method: 'PUT', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify(channel) + } + try { + const response = await fetch( + new URL( + `channels/${channel.id}`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const updatedChannel: Channel = await response.json() + return updatedChannel + } catch (error) { + throw error + } + } + + public async Disable (channel: Channel, token: string): Promise { + // Disables channel with specified id. + /** + * @method Disable - Disables channel with specified id. + * @param {Object} channel - Channel object with new information. + * @param {String} token - An access token that is valid. + * @returns {Object} - Creturns Disabled channel. + */ + const options = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + } + } + try { + const response = await fetch( + new URL( + `${this.channelsEndpoint}/${channel.id}/disable`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const disabledChannel: Channel = await response.json() + return disabledChannel + } catch (error) { + throw error + } + } + + public async Enable (channel: Channel, token: string): Promise { + // Enables channel with specified id. + /** + * @method Enable - Enables channel with specified id. + * @param {Object} channel - Channel object with new information. + * @param {String} token - An access token that is valid. + * @returns {Object} - Returns Enabled Channel. + */ + const options = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + } + } + try { + const response = await fetch( + new URL( + `${this.channelsEndpoint}/${channel.id}/enable`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const enabledChannel: Channel = await response.json() + return enabledChannel + } catch (error) { + throw error + } + } + + public async ChannelPermissions ( + channelId: string, + token: string + ): Promise { + // Retrieves channel permissions. + /** + * @method ChannelPermission - Retrieves channel permissions with specified id.. + * @param {Object} + * @param {string} token - user token. + * @returns {object} - returns channel domain permissions eg: + * { permissions: [ 'admin', 'edit', 'view', 'membership' ] } + */ + const options: RequestInit = { + method: 'GET', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + } + } + try { + const response = await fetch( + new URL( + `${this.channelsEndpoint}/${channelId}/permissions`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const permissions: Permissions = await response.json() + return permissions + } catch (error) { + throw error + } + } + + public async AddUserToChannel ( + channelID: string, + userIDs: string[], + relation: groupRelation, + token: string + ): Promise { + // Adds user to channel. + /** + * @method AddUser - Adds user to channel when provided with a valid token, + * channel id and a user id. + * @param {string} user_id - User ID. + * @param {string} channel_id - Channel ID. + * @param {string} token - User token. + * @returns Response - 'User Added Successfully'. + * */ + const req = { user_ids: userIDs, relation } + const options: RequestInit = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify(req) + } + try { + const response = await fetch( + new URL( + `${this.channelsEndpoint}/${channelID}/users/assign`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const addUserResponse: Response = { status: response.status, message: 'User Added Successfully' } + return addUserResponse + } catch (error) { + throw error + } + } + + public async RemoveUserFromChannel ( + channelID: string, + userIDs: string[], + relation: groupRelation, + token: string + ): Promise { + // Removes user from channel. + /** + * @method RemoveUser - Removes user from channel when provided with a valid token, + * channel id and a user id. + * @param {string} + * @param {string} user_id - User ID. + * @param {string} channel_id - Channel ID. + * @param {string} token - User token. + * @returns Response - 'User Removed Successfully'. + * */ + const req = { user_ids: userIDs, relation } + const options: RequestInit = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify(req) + } + try { + const response = await fetch( + new URL( + `${this.channelsEndpoint}/${channelID}/users/unassign`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const removeUserResponse: Response = { status: response.status, message: 'User Removed Successfully' } + return removeUserResponse + } catch (error) { + throw error + } + } + + public async Delete (channel: Channel, token: string): Promise { + // Deletes channel with specified id. + /** + * @method Disable - Deletes channel with specified id. + * @param {Object} channel - Channel object with new information. + * @param {String} token - An access token that is valid. + * @returns {Object} - Returns response message. + */ + const options: RequestInit = { + method: 'DELETE', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify(channel) + } + try { + const response = await fetch( + new URL( + `/${this.channelsEndpoint}/${channel.id}/delete`, this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const deleteResponse: Response = { status: response.status, message: 'Channel Deleted' } + return deleteResponse + } catch (error) { + throw error + } + } + + public async ListChannelUsersGroups ( + channelId: string, + queryParams: QueryParams, + token: string + ): Promise { + // Lists groups in a channel. + /** + * @method ListChannelUsersGroups - Lists groups in a channel. + * @param {string} + * @returns {Object} - Groups Page. + * */ + const stringParams: Record = Object.fromEntries( + Object.entries(queryParams).map(([key, value]) => [key, String(value)]) + ) + const options: RequestInit = { + method: 'GET', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + } + } + try { + const response = await fetch( + new URL( + `channels/${channelId}/groups?${new URLSearchParams(stringParams).toString()}`, + this.usersUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const groupsPage: GroupsPage = await response.json() + return groupsPage + } catch (error) { + throw error + } + } + + public async ConnectThing ( + thingId: string, + channelId: string, + token: string + ): Promise { + // Connects thing to channel. + /** + * @method Connect - Connects thing to channel when provided with a valid token, + * channel id and a thing id. The thing must have an action that it can perform over + * the channel. + * @param {string} thing_id - Thing ID. + * @param {string} channel_id - Channel ID. + * @param {string} token - User token. + * + */ + const options = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify({ thing_id: thingId, channel_id: channelId }) + } + try { + const response = await fetch( + new URL(`${this.channelsEndpoint}/${channelId}/things/${thingId}/connect`, this.thingsUrl).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const connectThingResponse: Response = { status: response.status, message: 'Thing Connected Successfully' } + return connectThingResponse + } catch (error) { + throw error + } + } + + public async Connect ( + thingId: string, + channelId: string, + token: string + ): Promise { + // Connects thing to channel. + /** + * @method Connects - Connect thing to channel when provided with a valid token, + * channel id and thing id. + * @param thing_ids - thing ID. + * @param channel_ids - channel Is. + * @param {string} token - User token. + * @returns Response - 'Thing Connected Successfully'. + */ + const options = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify({ thing_id: thingId, channel_id: channelId }) + } + try { + const response = await fetch( + new URL('/connect', this.thingsUrl).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const connectResponse: Response = { status: response.status, message: 'Thing Connected Successfully' } + return connectResponse + } catch (error) { + throw error + } + } + + public async Disconnect ( + thingId: string, + channelId: string, + token: string + ): Promise { + // Disconnects thing from channel. + /** + * @method Disconnect - Disconnects thing from channel when provided with a valid token, + * channel id and a thing id. The thing must have an action that it can perform over + * the channel. + * @param {string} thing_id - Thing ID. + * @param {string} channel_id - Channel ID. + * @param {string} token - User token. + * + */ + const options: RequestInit = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify({ thing_id: thingId, channel_id: channelId }) + } + try { + const response = await fetch( + new URL( + '/disconnect', this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const disconnectResponse: Response = { status: response.status, message: 'Thing Disconnected Successfully' } + return disconnectResponse + } catch (error) { + throw error + } + } + + public async DisconnectThing ( + thingId: string, + channelId: string, + token: string + ): Promise { + // Disconnects thing from channel. + /** + * @method Disconnect - Disconnects thing from channel when provided with a valid token, + * channel id and a thing id. The thing must have an action that it can perform over + * the channel. + * @param {string} thing_id - Thing ID. + * @param {string} channel_id - Channel ID. + * @param {string} token - User token. + * + */ + const options = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify({ thing_id: thingId, channel_id: channelId }) + + } + try { + const response = await fetch( + new URL(`${this.channelsEndpoint}/${channelId}/things/${thingId}/disconnect`, this.thingsUrl).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const disconnectThingResponse: Response = { status: response.status, message: 'Thing Disconnected Successfully' } + return disconnectThingResponse + } catch (error) { + throw error + } + } + + public async ListChannelUsers ( + channelId: string, + queryParams: QueryParams, + token: string + ): Promise { + // Lists users in a channel. + /** + * @method ListChannelUsers - Lists users in a channel. + * @param {string} + * @returns {Object} - Users Page. + * */ + const stringParams: Record = Object.fromEntries( + Object.entries(queryParams).map(([key, value]) => [key, String(value)]) + ) + const options: RequestInit = { + method: 'GET', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + } + } + try { + const response = await fetch( + new URL( + `channels/${channelId}/users?${new URLSearchParams(stringParams).toString()}`, + this.usersUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.channelError.HandleError(errorRes.error, response.status) + } + const usersPage: UsersPage = await response.json() + return usersPage + } catch (error) { + throw error + } + } +} diff --git a/src/defs.ts b/src/defs.ts index ca70ec1..21b2731 100644 --- a/src/defs.ts +++ b/src/defs.ts @@ -16,7 +16,7 @@ export interface UsersPage { } interface credentials { - identity: string + identity?: string secret?: string } @@ -144,6 +144,8 @@ export interface Response { export type Relation = 'administrator' | 'editor' | 'viewer' | 'member' +export type groupRelation = 'administrator' | 'editor' | 'viewer' + type status = 'enabled' | 'disabled' export interface QueryParams { diff --git a/src/messages.js b/src/messages.js deleted file mode 100644 index f40a91f..0000000 --- a/src/messages.js +++ /dev/null @@ -1,128 +0,0 @@ -const axios = require('axios'); -const Errors = require('./errors'); - -class Messages { - //Messages API Client - /** - * @method Messages - Messages is used to manage messages. - * It provides methods for sending and reading messages. - * @param {string} readers_url - The url of the readers service. - * @param {string} httpadapter_url - The URL of the Magistrala Messages adapter. - * @param {string} content_type - The content type of the request. - * @returns {Messages} - Returns a Messages object. - */ - - constructor(readers_url, httpadapter_url){ - this.readers_url = new URL (readers_url); - this.httpadapter_url = new URL (httpadapter_url); - this.content_type = 'application/json'; - } - - messageError = new Errors; - - Send(channel_id, msg, thing_key){ - //Send a message - /** - * @method Send- Sends message to a given channel via HTTP protocol. Message is sent - * through a writer add-on such as timescale. Message is sent to a - * http port specific to the writer add-on. The thing and channel must be - * created before sending the message and connected. - * @param {string} channel_id - The channel_id of the channel to send the message to. - * @param {string} msg -message to send to the channel that should be in encoded into - * bytes format for example: - * [{"bn":"demo", "bu":"V", "n":"voltage", "u":"V", "v":5}] - * @param {string} thing_key - The secret of the thing sending the message. - */ - - if (typeof channel_id !== "string" || channel_id === null) { - throw new Error('Invalid channel_id parameter. Expected a string.'); - } - - if (typeof thing_key !== "string" || thing_key === null) { - throw new Error('Invalid thing_key parameter. Expected a string.'); - } - - if (!Array.isArray(msg)) { - throw new Error('Invalid msg parameter. Expected an array.'); - } - - const chan_name_parts = channel_id.split(".", 2); - const chan_id = chan_name_parts[0]; - let subtopic = ""; - - const options = { - method: "post", - maxBodyLength: 2000, - url: new URL (`http/channels/${chan_id}/messages/${subtopic}`, this.httpadapter_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Thing ${thing_key}`, - }, - data: new TextEncoder().encode(msg), - }; - return axios.request(options) - .then((_response) => { - return "Message Sent!"; - }) - .catch((error) => { - if (error.response){ - return this.messageError.HandleError( - this.messageError.messages.send, - error.response.status, - ); - }; - }); - } - - Read(channel_id, token){ - //Read messages - /** - * - * @method Read - Read messages from a given channel. Messages are read from a reader - * add-on such as timescale. Messages are read from a http port specific to the reader - * @param {string} channel_id - The channel_id of the channel to read the message from. - * @param {string} token - The token to be used for authentication. - */ - - if (typeof channel_id !== "string" || channel_id === null) { - throw new Error('Invalid channel_id parameter. Expected a string.'); - } - - if (typeof token !== "string" || token === null) { - throw new Error('Invalid token parameter. Expected a string.'); - } - - const chan_name_parts = channel_id.split(".", 2); - const chan_id = chan_name_parts[0]; - let subtopic = ""; - - if (chan_name_parts.length == 2) { - subtopic = chan_name_parts[1].replace(".", "/", -1); - } - - const options = { - method: "get", - maxBodyLength: 2000, - url: new URL (`channels/${chan_id}/messages`, this.readers_url), - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - params: {"subtopic": subtopic}, - }; - return axios.request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - if (error.response){ - return this.messageError.HandleError( - this.messageError.messages.read, - error.response.status, - ); - }; - }); - } -} - -module.exports = Messages; diff --git a/src/sdk.ts b/src/sdk.ts index f79d2a7..2837264 100644 --- a/src/sdk.ts +++ b/src/sdk.ts @@ -2,6 +2,8 @@ import Users from './users' import Domains from './domains' import Things from './things' import Groups from './groups' +import Channels from './channels' + export type { User, UsersPage, @@ -35,6 +37,7 @@ class SDK { domains: Domains things: Things groups: Groups + channels: Channels constructor ({ usersUrl = defaultUrl, @@ -44,8 +47,9 @@ class SDK { }: SDKConfig = {}) { this.users = new Users({ usersUrl, thingsUrl, hostUrl }) this.domains = new Domains({ domainsUrl, usersUrl }) - this.things = new Things(thingsUrl) + this.things = new Things({ thingsUrl, usersUrl }) this.groups = new Groups({ usersUrl, thingsUrl }) + this.channels = new Channels({ thingsUrl, usersUrl }) } } diff --git a/src/things.ts b/src/things.ts index 8867763..08cef8d 100644 --- a/src/things.ts +++ b/src/things.ts @@ -1,57 +1,326 @@ import Errors from './errors' -import { type Thing } from './defs' + +import { + type Thing, + type ThingsPage, + type Response, + type QueryParams, + type UsersPage, + type Permissions, + type Relation +} from './defs' export default class Things { // Things service client. /** - * @class Things - - * Things API is used for creating and managing things. - * It is used for creating, updating, deleting and retrieving things. - * @param {string} thingsUrl - Things service URL. - * @returns {Object} - Things service client. + @class Things + private things_url: URL; + content_type: string; + thingsEndpoint: string; + // + //Things API is used for creating and managing things. + //It is used for creating, updating, deleting and retrieving things. + //@param {string} things_url - Things service URL. + //@returns {Object} - Things service client. */ - private readonly thingsUrl: URL + private readonly usersUrl?: URL private readonly contentType: string private readonly thingsEndpoint: string private readonly thingError: Errors - public constructor (thingsUrl: string) { + public constructor ({ thingsUrl, usersUrl }: { thingsUrl: string, usersUrl?: string }) { this.thingsUrl = new URL(thingsUrl) + if (usersUrl !== undefined) { + this.usersUrl = new URL(usersUrl) + } else { + this.usersUrl = new URL('') + } this.contentType = 'application/json' - this.thingsEndpoint = 'users' + this.thingsEndpoint = 'things' this.thingError = new Errors() } public async Create (thing: Thing, token: string): Promise { - // Creates a new thing. + const options: RequestInit = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify(thing) + } + + try { + const response = await fetch( + new URL(this.thingsEndpoint, this.thingsUrl).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const thingData: Thing = await response.json() + return thingData + } catch (error) { + throw error + } + } + + public async CreateThings ( + things: Thing[], + token: string + ): Promise { + // Creates multiple things. + /** + * @method CreateThings - Creates multiple things. + * @param {Object} things - Array of things. + * @param {string} token - User token. + * @returns {Object} - Thing object. + * @example + * const things = [ + * { + * "name": "thing3", + * "tags": [ + * "tag1" + * ], + * */ + const options: RequestInit = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify(things) + } + try { + const response = await fetch( + new URL(`${this.thingsEndpoint}/bulk`, this.thingsUrl).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const thingData: ThingsPage = await response.json() + return thingData + } catch (error) { + throw error + } + } + + public async ThingsByChannel ( + channelID: string, + queryParams: QueryParams, + token: string + ): Promise { + // Retrieves list of channels connected to specified thing with pagination metadata. /** - * @method Create - Creates a new thing when provided with - * the things information and a valid token. + * @method GetByChannel - Retrieves list of channels connected to specified thing + * with pagination metadata. + * @param {string} thing_id - Thing ID. + * @param {Object} queryParams - Query parameters such as offset and limit. + * @returns {Object} - Channels list. + */ + + const stringParams: Record = Object.fromEntries( + Object.entries(queryParams).map(([key, value]) => [key, String(value)]) + ) + + const options: RequestInit = { + method: 'GET', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + } + } + + try { + const response = await fetch( + new URL( + `channels/${channelID}/${this.thingsEndpoint}?${new URLSearchParams( + stringParams + ).toString()}`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const ThingsData: ThingsPage = await response.json() + return ThingsData + } catch (error) { + throw error + } + } + + public async Disable (thing: Thing, token: string): Promise { + // Disables thing. + /** + * @method Disable - Deletes a thing when provided with a valid token and thing ID. + * @param {string} thing_id - Thing ID. + * @param {string} token - User token. + * @returns {Object} - Returns disabled thing + */ + + const options: RequestInit = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify(thing) + } + try { + const response = await fetch( + new URL( + `${this.thingsEndpoint}/${thing.id}/disable`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const disabledThing: Thing = await response.json() + return disabledThing + } catch (error) { + throw error + } + } + + public async UpdateThing (thing: Thing, token: string): Promise { + // Updates thing. + /** + * @method Update - Updates thing when provided with a valid token, + * thing ID and thing object. + * @param {string} thing_id - Thing ID. * @param {Object} thing - Thing object. * @param {string} token - User token. * @returns {Object} - Thing object. * @example * const thing = { - * "name": "string", + * "name": "thing3", * "tags": [ - * "tag1", - * "tag2" + * "tag1" * ], * "credentials": { * "identity": "thingidentity", - * "secret": "bb7edb32-2eac-4aad-aebe-ed96fe073879" + * "secret":"12345678" * }, * "owner": "bb7edb32-2eac-4aad-aebe-ed96fe073879", - * "metadata": { - * "domain": "example.com" + * "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + * } + */ + + const options: RequestInit = { + method: 'PATCH', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify(thing) + } + try { + const response = await fetch( + new URL( + `${this.thingsEndpoint}/${thing.id}`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const thingData: Thing = await response.json() + return thingData + } catch (error) { + throw error + } + } + + public async UpdateThingSecret (thing: Thing, token: string): Promise { + // Updates thing secret. + /** + * @method UpdateThingSecret - Updates thing secret when provided with a valid token, + * thing ID and thing object. + * @param {string} thing_id - Thing ID. + * @param {Object} thing - Thing object. + * @param {string} token - User token. + * @returns {Object} - Thing object. + * @example + * const thing = { + * "name": "thing3", + * "tags": [ + * "tag1" + * ], + * "credentials": { + * "identity": "thingidentity", + * "secret":"56788912" * }, - * "status": "enabled" + * "owner": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + * "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", * } */ const options: RequestInit = { - method: 'post', + method: 'PATCH', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify({ secret: thing.credentials?.secret }) + } + try { + const response = await fetch( + new URL( + `${this.thingsEndpoint}/${thing.id}/secret`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const thingData: Thing = await response.json() + return thingData + } catch (error) { + throw error + } + } + + public async UpdateThingTags (thing: Thing, token: string): Promise { + // Updates thing tags. + /** + * @method UpdateThingTags - Updates thing tags when provided with a valid token, + * thing ID and thing object. + * + * @param {string} thing_id - Thing ID. + * @param {Object} thing - Thing object. + * @param {string} token - User token. + * @returns {Object} - Thing object. + * @example + * const thing = { + * "name": "thing3", + * "tags": [ + * "tag1" + * ], + * "credentials": { + * "identity": "thingidentity", + * "secret":"56788912" + * }, + * "owner": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + * "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + * } + */ + + const options: RequestInit = { + method: 'PATCH', headers: { 'Content-Type': this.contentType, Authorization: `Bearer ${token}` @@ -61,17 +330,370 @@ export default class Things { try { const response = await fetch( - new URL(this.thingsEndpoint, this.thingsUrl), + new URL( + `${this.thingsEndpoint}/${thing.id}/tags`, + this.thingsUrl + ).toString(), options ) if (!response.ok) { const errorRes = await response.json() throw this.thingError.HandleError(errorRes.error, response.status) } - const thingData = await response.json() + const thingData: Thing = await response.json() return thingData } catch (error) { throw error } } + + public async Thing (thingId: string, token: string): Promise { + // Gets a user + /** + * Provides information about the user with provided ID. The user is + * retrieved using authorization user_token. + * @method User - Gets a user. + * @param {String} userId - User ID. + * @param {String} token - Access token. + * @returns {Object} - User object. + * @example + * const userId = "886b4266-77d1-4258-abae-2931fb4f16de" + * + */ + + const options: RequestInit = { + method: 'GET', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + } + } + + try { + const response = await fetch( + new URL(`${this.thingsEndpoint}/${thingId}`, this.thingsUrl).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const thingData: Thing = await response.json() + return thingData + } catch (error) { + throw error + } + } + + public async IdentifyThing (thingKey: string): Promise { + const options: RequestInit = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Thing ${thingKey}` + } + } + + try { + const response = await fetch( + new URL(this.thingsEndpoint, this.thingsUrl).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const thingData: Thing = await response.json() + return thingData + } catch (error) { + throw error + } + } + + public async ThingsPermissions ( + thingID: string, + token: string + ): Promise { + // Retrieves thing permissions. + /** + * @method Permissions - Retrieves thing permissions when provided with a valid token + * and thing ID. + * @param {string} + * @param {string} token - User token. + * @returns {Object} - Thing permissions. + * @example + * const thing_id = "bb7edb32-2eac-4aad-aebe-ed96fe073879" + * const token + * const permissions = Things.Permissions(thing_id, token) + * console.log(permissions) + * */ + + const options: RequestInit = { + method: 'GET', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + } + } + try { + const response = await fetch( + new URL( + `${this.thingsEndpoint}/${thingID}/permissions`, + this.thingsUrl + ).toString(), options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const thingData: Permissions = await response.json() + return thingData + } catch (error) { + throw error + } + } + + public async Enable (thing: Thing, token: string): Promise { + // Enables a thing. + /** + * @method Enable - Enables a thing when provided with a valid token and thing ID. + * @param {string} thing_id - Thing ID. + * @param {string} token - User token. + * @returns {Object} - Returns updated thing. + */ + + const options: RequestInit = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify(thing) + } + + try { + const response = await fetch( + new URL( + `${this.thingsEndpoint}/${thing.id}/enable`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const enabledThing: Thing = await response.json() + return enabledThing + } catch (error) { + throw error + } + } + + public async Things ( + queryParams: QueryParams, + token: string + ): Promise { + // Gets all things with pagination. + /** + * Provides information about all users. The users are retrieved using + * authorization user_token. + * + * @method Things - Gets all things with pagination. + * @param {Object} queryParams - Query parameters. + * @param {String} token - Access token. + * @returns {Object} - Thing object. + * @example + * const queryParams = { + * "offset": 0, + * "limit": 10 + * } + * + */ + + const stringParams: Record = Object.fromEntries( + Object.entries(queryParams).map(([key, value]) => [key, String(value)]) + ) + + const options: RequestInit = { + method: 'GET', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + } + } + + try { + const response = await fetch( + new URL( + `${this.thingsEndpoint}?${new URLSearchParams(stringParams).toString()}`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const thingsData: ThingsPage = await response.json() + return thingsData + } catch (error) { + throw error + } + } + + public async ListThingUsers ( + thingId: string, + queryParams: QueryParams, + token: string + ): Promise { + const stringParams: Record = Object.fromEntries( + Object.entries(queryParams).map(([key, value]) => [key, String(value)]) + ) + const options: RequestInit = { + method: 'GET', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + } + } + try { + const response = await fetch( + new URL( + `${this.thingsEndpoint}/${thingId}/users?${new URLSearchParams(stringParams).toString()}`, + this.usersUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const userData: UsersPage = await response.json() + return userData + } catch (error) { + throw error + } + } + + public async ShareThing ( + thingId: string, + Relation: Relation, + userIDs: string[], + token: string + ): Promise { + // Shares a thing with a user. + /** + * @method ShareThing - Shares a thing with a user. + * @param {string} thingId - Thing ID. + * @param {string} userId - User ID. + * @param {string} token - User token. + * @returns {Object} - Nothing + * + * */ + const req = { relation: Relation, user_ids: userIDs } + const options: RequestInit = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify(req) + + } + try { + const response = await fetch( + new URL( + `${this.thingsEndpoint}/${thingId}/share`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const shareResponse: Response = { status: response.status, message: 'Thing Shared Successfully' } + return shareResponse + } catch (error) { + throw error + } + } + + public async UnShareThing ( + thingId: string, + Relation: string, + userIDs: string[], + token: string + ): Promise { + // Shares a thing with a user. + /** + * @method UnShareThing - UnShares a thing with a user. + * @param {string} thing_id - Thing ID. + * @param {string} user_id - User ID. + * @param {string} token - User token. + * @returns {Object} - Nothing + * + * */ + const req = { relation: Relation, user_ids: userIDs } + const options: RequestInit = { + method: 'POST', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify(req) + } + try { + const response = await fetch( + new URL( + `${this.thingsEndpoint}/${thingId}/unshare`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const unshareResponse: Response = { status: response.status, message: 'Thing UnShared Successfully' } + return unshareResponse + } catch (error) { + throw error + } + } + + public async DeleteThing (thing: Thing, token: string): Promise { + // Deletes a thing. + /** + * @method DeleteThing - Deletes a thing. + * @param {string} + * */ + const options: RequestInit = { + method: 'DELETE', + headers: { + 'Content-Type': this.contentType, + Authorization: `Bearer ${token}` + }, + body: JSON.stringify(thing) + } + + try { + const response = await fetch( + new URL( + `${this.thingsEndpoint}/${thing.id}`, + this.thingsUrl + ).toString(), + options + ) + if (!response.ok) { + const errorRes = await response.json() + throw this.thingError.HandleError(errorRes.error, response.status) + } + const deleteResponse: Response = { status: response.status, message: 'Thing Deleted Successfully' } + return deleteResponse + } catch (error) { + throw error + } + } }