diff --git a/.vscode/launch.json b/.vscode/launch.json index 7d997bc..f9ba58b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -34,4 +34,4 @@ "runtimeExecutable": "npm" } ] -} \ No newline at end of file +} diff --git a/examples/examples.js b/examples/examples.js index aafe6fc..6580301 100644 --- a/examples/examples.js +++ b/examples/examples.js @@ -25,7 +25,7 @@ try { console.log(response); }) .catch(error => { - console.error(error.response.data); + console.error(error.response); }); } catch (error) { console.error(error.message); @@ -40,7 +40,7 @@ try { console.log(response); }) .catch(error => { - console.error(error.response.data); + console.error(error.response); }); } catch (error) { console.error(error.message); @@ -130,7 +130,7 @@ catch (error) { try { mySdk.things.UpdateThingTags( "", - { "tags": ["stheno", "euryale"] }, + { "tags": ["", ""] }, "" ) .then(response => { @@ -165,8 +165,8 @@ try { mySdk.things.Connect( "", "", - ["action"], - "token" + [""], + "" ) .then(response => { console.log(response); @@ -181,8 +181,8 @@ catch (error) { try { mySdk.things.Disconnect( - [""], - [""], + [""], + [""], "" ) .then(response => { @@ -232,9 +232,9 @@ catch (error) { } try { - mySdk.things.IdentifyThing({ - "secret": "" - }) + mySdk.things.IdentifyThing( + "" + ) .then(response => { console.log(response); }) @@ -313,7 +313,7 @@ try { try { mySdk.users.RefreshToken( - "", + {"id":"user_id"}, "" ) .then(response => { @@ -329,6 +329,7 @@ try { try { mySdk.users.Update( { "id": "", "name": "" }, + "", "" ) .then(response => { @@ -343,7 +344,8 @@ try { try { mySdk.users.UpdateUserIdentity( - { "id": "", "identity": "" }, + {"identity": ""}, + "", "" ) .then(response => { @@ -358,7 +360,8 @@ try { try { mySdk.users.UpdateUserTags( - { "id": "", "tags": ["foo", "bar"] }, + {"tags": ["foo", "bar"] }, + "", "" ) .then(response => { @@ -373,7 +376,8 @@ try { try { mySdk.users.UpdateUserOwner( - { "id": "", "owner": "" }, + { "owner": "" }, + "", "" ) .then(response => { @@ -389,6 +393,7 @@ try { try { mySdk.users.Disable( { "id": "" }, + "user_id", "" ) .then(response => { @@ -404,6 +409,7 @@ try { try { mySdk.users.Enable( { "id": "" }, + "", "" ) .then(response => { @@ -449,7 +455,7 @@ try { try { mySdk.users.Memberships( "", - { query_params }, + { "offset": 0, "limit": 10 }, "" ) .then(response => { @@ -484,8 +490,8 @@ try { try { mySdk.groups.Create( - { "name": "hatshepsut" }, - "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTczODcxNjgsImlhdCI6MTY5NzM4NjI2OCwiaWRlbnRpdHkiOiJhZG1pbkBleGFtcGxlLmNvbSIsImlzcyI6ImNsaWVudHMuYXV0aCIsInN1YiI6IjViNDA3MTgzLTEwNGYtNDc2NC04MDYyLTg3ZGQ2MTM5MTA0NiIsInR5cGUiOiJhY2Nlc3MifQ.kPctWq5eR1UdK1bEERlY42O2oqW1TNdA-N4IYQ24lLxdZ6HOGU7vR9FgtXdH0S2XXcSJR3flq8lmsPOB_s9zAA" + { "name": "" }, + "" ) .then(response => { console.log(response); @@ -530,6 +536,7 @@ try { try { mySdk.groups.Update( "", + {"name": ""}, "" ) .then(response => { @@ -578,7 +585,7 @@ try { mySdk.groups.Assign( "", "", - [""], + [""], "" ) .then(response => { @@ -723,7 +730,7 @@ catch (error) { try { mySdk.channels.Disable( - { "id": "" }, + "", "" ) .then(response => { @@ -848,6 +855,7 @@ try { "name": "" }, + "", "" ) .then(response => { @@ -863,9 +871,9 @@ try { try { mySdk.bootstrap.Update( { - "thing_id": "", - "name": "" + "name": "" }, + "", "" ) .then(response => { @@ -944,32 +952,32 @@ try { //Messages.js try { -mySdk.messages.Send( - "", - '', - "" -) - .then(response => { - console.log(response); - }) - .catch(error => { - console.error(error.response.data); - }); + mySdk.messages.Send( + "", + [''], + "" + ) + .then(response => { + console.log(response); + }) + .catch(error => { + console.error(error.response.data); + }); } catch (error) { console.error(error.message); } try { -mySdk.messages.Read( - "", - "" -) - .then(response => { - console.log(response); - }) - .catch(error => { - console.error(error.response.data); - }); + mySdk.messages.Read( + "", + "" + ) + .then(response => { + console.log(response); + }) + .catch(error => { + console.error(error.response.data); + }); } catch (error) { console.error(error.message); } diff --git a/mainflux/bootstrap.js b/mainflux/bootstrap.js index 704e74c..4330626 100644 --- a/mainflux/bootstrap.js +++ b/mainflux/bootstrap.js @@ -1,4 +1,5 @@ -const axios = require("axios"); +const axios = require('axios'); +const Errors = require('./errors'); class Bootstrap { //Bootstraps API Client @@ -31,25 +32,11 @@ class Bootstrap { * @returns {Bootstrap} - Returns a Bootstrap object. * */ - const options = { - method: "post", - maxBodyLength: Infinity, - url: `${this.bootstraps_url}/things/${this.bootstrapsEndpoint}`, - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - data: JSON.stringify(config), - }; - return axios - .request(options) - .then((_response) => { - return "Configuration added"; - }) - .catch((error) => { - return error.response.data; - }); - } + constructor(bootstraps_url){ + this.bootstraps_url = new URL (bootstraps_url); + this.content_type = "application/json"; + this.bootstrapsEndpoint = "configs"; + } ValidateConfigAndToken(config, token){ //Validate config @@ -63,6 +50,8 @@ class Bootstrap { } } + bootstrapError = new Errors; + Create(config, token){ //Create a bootstrap configuration /** @@ -86,23 +75,28 @@ class Bootstrap { const options = { method: "post", maxBodyLength: 2000, - url: `${this.bootstraps_url}/things/${this.bootstrapsEndpoint}`, + url: new URL (`things/${this.bootstrapsEndpoint}`, this.bootstraps_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(config), + data: config, }; return axios.request(options) .then((_response) => { return "Configuration added"; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.bootstrapError.HandleError( + this.bootstrapError.bootstraps.create, + error.response.status + ); + }; + }); } - Whitelist(config, token){ + Whitelist(config, thing_id, token){ //Update a bootstrap configuration /** * @method Whitelist - Allows a logged in user to update a bootstrap configuration. @@ -118,28 +112,37 @@ class Bootstrap { * } */ + 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: `${this.bootstraps_url}/things/state/${config["thing_id"]}`, + url: new URL (`things/state/${thing_id}`, this.bootstraps_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(config), + data: config, }; return axios.request(options) .then((_response) => { return "Configuration updated"; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.bootstrapError.HandleError( + this.bootstrapError.bootstraps.whitelist, + error.response.status + ); + }; + }); } - Update(config, token){ + Update(config, thing_id, token){ //Update a bootstrap configuration /** * @method Update - Allows a logged in user to update a bootstrap configuration. @@ -155,25 +158,34 @@ class Bootstrap { * } */ + 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: `${this.bootstraps_url}/things/configs/${config["thing_id"]}`, + url: new URL (`things/configs/${thing_id}`, this.bootstraps_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(config), + data: config, }; return axios.request(options) .then((_response) => { return "Configuration updated"; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.bootstrapError.HandleError( + this.bootstrapError.bootstraps.update, + error.response.status + ); + }; + }); } View(thing_id, token){ @@ -194,7 +206,7 @@ class Bootstrap { const options = { method: "get", maxBodyLength: 2000, - url: `${this.bootstraps_url}/things/${this.bootstrapsEndpoint}/${thing_id}`, + url: new URL (`things/${this.bootstrapsEndpoint}/${thing_id}`, this.bootstraps_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -205,8 +217,13 @@ class Bootstrap { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.bootstrapError.HandleError( + this.bootstrapError.bootstraps.view, + error.response.status + ); + }; + }); } UpdateCerts(config_id,client_cert,client_key, ca, token){ @@ -238,20 +255,25 @@ class Bootstrap { const options = { method: "patch", maxBodyLength: 2000, - url: `${this.bootstraps_url}/configs/certs/${config_id}`, + url: new URL(`configs/certs/${config_id}`, this.bootstraps_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.bootstrapError.HandleError( + this.bootstrapError.bootstraps.updatecerts, + error.response.status + ); + }; + }); } Remove(config_id, token){ @@ -273,7 +295,7 @@ class Bootstrap { const options = { method: "delete", maxBodyLength: 2000, - url: `${this.bootstraps_url}/things/${this.bootstrapsEndpoint}/${config_id}`, + url: new URL (`things/${this.bootstrapsEndpoint}/${config_id}`, this.bootstraps_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -284,8 +306,13 @@ class Bootstrap { return "Configuration removed"; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.bootstrapError.HandleError( + this.bootstrapError.bootstraps.remove, + error.response.status + ); + }; + }); } Bootstrap(external_id, external_key){ @@ -300,11 +327,11 @@ class Bootstrap { 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: `${this.bootstraps_url}/things/bootstrap/${external_id}`, + url: new URL (`things/bootstrap/${external_id}`, this.bootstraps_url), headers: { "Content-Type": this.content_type, Authorization: `Thing ${external_key}`, @@ -315,8 +342,13 @@ class Bootstrap { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.bootstrapError.HandleError( + this.bootstrapError.bootstraps.bootstrap, + error.response.status + ); + }; + }); } Bootstrap(external_id, external_key) { diff --git a/mainflux/certs.js b/mainflux/certs.js index 97acae0..d8bafc5 100644 --- a/mainflux/certs.js +++ b/mainflux/certs.js @@ -1,6 +1,5 @@ -// import Errors from "./errors.js"; - const axios = require("axios"); +const Errors = require("./errors"); class Certs { //Certs API Client @@ -27,7 +26,7 @@ class Certs { * @returns {Certs} - Returns a Certs object. */ constructor(certs_url) { - this.certs_url = certs_url; + this.certs_url = new URL(certs_url); this.content_type = "application/json"; this.certsEndpoint = "certs"; } @@ -40,6 +39,8 @@ class Certs { } } + certsError = new Errors; + Issue(thing_id , valid, token) { //Issue a certificate /** @@ -63,20 +64,25 @@ class Certs { const options = { method: "post", maxBodyLength: 2000, - url: `${this.certs_url}/${this.certsEndpoint}`, + url: new URL (this.certsEndpoint, this.certs_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.certsError.HandleError( + this.certsError.certs.issue, + error.response.status, + ); + }; + }); } ViewByThing(thing_id, token) { @@ -95,7 +101,7 @@ class Certs { const options = { method: "get", maxBodyLength: 2000, - url: `${this.certs_url}/serials/${thing_id}`, + url: new URL (`serials/${thing_id}`, this.certs_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -106,8 +112,13 @@ class Certs { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.certsError.HandleError( + this.certsError.certs.viewbything, + error.response.status, + ); + }; + }); } ViewBySerial(cert_id, token) { @@ -129,7 +140,7 @@ class Certs { const options = { method: "get", maxBodyLength: 2000, - url: `${this.certs_url}/${this.certsEndpoint}/${cert_id}`, + url: new URL (`${this.certsEndpoint}/${cert_id}`, this.certs_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -140,8 +151,13 @@ class Certs { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.certsError.HandleError( + this.certsError.certs.viewbyserial, + error.response.status, + ); + }; + }); } Revoke(thing_id, token) { @@ -158,7 +174,7 @@ class Certs { const options = { method: "delete", maxBodyLength: 2000, - url: `${this.certs_url}/${this.certsEndpoint}/${thing_id}`, + url: new URL (`${this.certsEndpoint}/${thing_id}`, this.certs_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -169,8 +185,13 @@ class Certs { return "DELETED"; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.certsError.HandleError( + this.certsError.certs.revoke, + error.response.status, + ); + }; + }); } Revoke(thing_id, token) { diff --git a/mainflux/channels.js b/mainflux/channels.js index efcc714..197fca8 100644 --- a/mainflux/channels.js +++ b/mainflux/channels.js @@ -1,5 +1,5 @@ -// import fetch from "node-fetch"; const axios = require("axios"); +const Errors = require("./errors"); class Channels { //Channels API client @@ -31,7 +31,7 @@ class Channels { * */ constructor(channels_url) { - this.channels_url = channels_url; + this.channels_url = new URL (channels_url); this.content_type = "application/json"; this.channelsEndpoint = "channels"; } @@ -52,6 +52,8 @@ class Channels { } }; + channelError = new Errors; + Create(channel, token) { //Creates a new channel /** @@ -79,20 +81,25 @@ class Channels { const options = { method: "post", maxBodyLength: 2000, - url: `${this.channels_url}/${this.channelsEndpoint}`, + url: new URL (this.channelsEndpoint, this.channels_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(channel), + data: channel, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.channelError.HandleError( + this.channelError.channels.create, + error.response.status, + ); + }; + }); } CreateBulk(channels, token) { @@ -119,20 +126,25 @@ class Channels { const options = { method: "post", maxBodyLength: 2000, - url: `${this.channels_url}/${this.channelsEndpoint}/bulk`, + url: new URL (`${this.channelsEndpoint}/bulk`, this.channels_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(channels), + data: channels, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.channelError.HandleError( + this.channelError.channels.createbulk, + error.response.status, + ); + }; + }); } Get(channel_id, token) { @@ -149,7 +161,7 @@ class Channels { const options = { method: "get", maxBodyLength: 2000, - url: `${this.channels_url}/${this.channelsEndpoint}/${channel_id}`, + url: new URL (`${this.channelsEndpoint}/${channel_id}`, this.channels_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -160,8 +172,13 @@ class Channels { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.channelError.HandleError( + this.channelError.channels.get, + error.response.status, + ); + }; + }); } GetByThing(channel_id, query_params, token) { @@ -183,7 +200,7 @@ class Channels { const options = { method: "get", maxBodyLength: 2000, - url: `${this.channels_url}/${this.channelsEndpoint}/${channel_id}/things?${new URLSearchParams(query_params).toString()}`, + 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}`, @@ -194,8 +211,13 @@ class Channels { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.channelError.HandleError( + this.channelError.channels.getbything, + error.response.status, + ); + }; + }); } GetAll(query_params, token) { @@ -216,7 +238,7 @@ class Channels { const options = { method: "get", maxBodyLength: 2000, - url: `${this.channels_url}/${this.channelsEndpoint}?${new URLSearchParams(query_params).toString()}`, + url: new URL (`${this.channelsEndpoint}?${new URLSearchParams(query_params).toString()}`, this.channels_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -227,8 +249,13 @@ class Channels { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.channelError.HandleError( + this.channelError.channels.getall, + error.response.status, + ); + }; + }); } Update(channel_id, channel, token) { @@ -245,20 +272,25 @@ class Channels { const options = { method: "put", maxBodyLength: 2000, - url: `${this.channels_url}/${this.channelsEndpoint}/${channel_id}`, + url: new URL (`${this.channelsEndpoint}/${channel_id}`, this.channels_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(channel), + data: channel, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.channelError.HandleError( + this.channelError.channels.update, + error.response.status, + ); + }; + }); } Disable(channel_id, token) { @@ -275,7 +307,7 @@ class Channels { const options = { method: "post", maxBodyLength: 2000, - url: `${this.channels_url}/${this.channelsEndpoint}/${channel_id}/disable`, + url: new URL (`${this.channelsEndpoint}/${channel_id}/disable`, this.channels_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -286,8 +318,13 @@ class Channels { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.channelError.HandleError( + this.channelError.channels.disable, + error.response.status, + ); + }; + }); } Disable(channel, token) { @@ -318,5 +355,4 @@ class Channels { } } -// export default Channels; module.exports = Channels; diff --git a/mainflux/errors.js b/mainflux/errors.js index 5349706..e161420 100644 --- a/mainflux/errors.js +++ b/mainflux/errors.js @@ -1,11 +1,11 @@ class Errors { - HandleError(error_dict, status_code) { - if (error_dict.hasOwnProperty(status_code)) { - return error_dict[status_code]; - } else { - return errors[status_code]; + HandleError(error_dict, status_code) { + if (error_dict.hasOwnProperty(status_code)) { + return error_dict[status_code]; + } else { + return this.errors[status_code]; + } } - } errors = { 400: "Failed due to malformed JSON.", @@ -20,13 +20,14 @@ class Errors { users = { get : { - 401: "Missing or invalid access token provided.", + 401: "Missing or invalid access token provided.", 404: "A non-existent entity request.", 400: "Failed due to malformed query parameters.", }, create: { 409: "Entity already exists.", 401: "Missing or invalid access token provided.", + 400: "Failed due to malformed JSON.", }, login: { 404: "A non-existent entity request.", @@ -35,13 +36,13 @@ class Errors { 404: "A non-existent entity request.", }, update: { - 404: "Failed due to a non-existing user.", 401: "Missing or invalid access token provided.", + 404: "Failed due to a non-existing user.", 400: "Failed due to malformed JSON.", }, updateusertags:{ 401: "Missing or invalid access token provided.", - 400: "Failed due to malformed JSON.", + 404: "A non-existent entity request.", }, updateuserpassword:{ 500: "Unexpected server-side error occurred.", @@ -69,6 +70,7 @@ class Errors { 401: "Missing or invalid access token provided.", }, memberships:{ + 500: "Unexpected serverside error occurred.", 401: "Missing or invalid access token provided.", 400: "Failed due to malformed query parameters.", }, @@ -81,7 +83,11 @@ class Errors { groups= { get : { 401: "Missing or invalid access token provided.", - 404: "A non-existent entity request.", + 404: "Group does not exist.", + 400: "Failed due to malformed query parameters.", + }, + getall : { + 401: "Missing or invalid access token provided.", 400: "Failed due to malformed query parameters.", }, create : { @@ -91,12 +97,15 @@ class Errors { }, children : { 401: "Missing or invalid access token provided.", + 400: "Failed due to malformed query parameters.", }, parents : { 401: "Missing or invalid access token provided.", + 400: "Failed due to malformed query parameters.", }, update : { 401: "Missing or invalid access token provided.", + 404: "Group does not exist.", }, assign : { 500: "Unexpected server-side error occurred.", @@ -116,10 +125,11 @@ class Errors { things ={ create : { - 409: "Entity already exists.", + 500: "Unexpected server-side error occurred.", 401: "Missing or invalid access token provided.", }, createbulk : { + 500: "Unexpected server-side error occurred.", 400: "Failed due to malformed JSON.", 401: "Missing or invalid access token provided.", }, @@ -128,6 +138,7 @@ class Errors { 400: "Failed due to malformed query parameters.", }, disable : { + 500: "Unexpected server-side error occurred.", 400: "Failed due to malformed JSON.", 401: "Missing or invalid access token provided.", }, @@ -140,60 +151,55 @@ class Errors { 401: "Missing or invalid access token provided.", }, update : { + 500: "Unexpected server-side error occurred.", 401: "Missing or invalid access token provided.", 400: "Failed due to malformed JSON.", 404: "Failed due to a non-existing thing.", }, updatethingsecret : { + 409: "Entity already exists.", 401: "Missing or invalid access token provided.", 400: "Failed due to malformed JSON.", - 404: "Failed due to a non-existing thing.", + 404: "Failed due to a non-existing thing.", }, updatethingtags : { - 401: "Missing or invalid access token provided.", - 400: "Failed due to malformed JSON.", + 500: "Unexpected server-side error occurred.", 404: "Failed due to a non-existing thing.", }, updatethingowner : { - 401: "Missing or invalid access token provided.", - 400: "Failed due to malformed JSON.", + 500: "Unexpected server-side error occurred.", 404: "Failed due to a non-existing thing.", }, connects : { - 401: "Missing or invalid access token provided.", - 400: "Failed due to malformed JSON.", - }, - authorisething : { + 500: "Unexpected server-side error occurred.", 401: "Missing or invalid access token provided.", 400: "Failed due to malformed JSON.", }, identifything : { + 404: "A non-existent entity request.", 415: "Missing or invalid content type.", }, get :{ 401: "Missing or invalid access token provided.", }, - get_all :{ + getall :{ + 500: "Unexpected server-side error occurred.", 400: "Failed due to malformed query parameters.", - 500: "Unexpected serverside error occurred.", 401: "Missing or invalid access token provided.", - } + }, } certs ={ issue : { 500: "Unexpected server-side error occurred.", 401: "Missing or invalid access token provided.", - 400: "Failed due to malformed JSON.", }, - view_by_serial :{ + viewbyserial :{ 500: "Unexpected server-side error occurred.", - 404: "Failed to retrieve corresponding certificate.", 401: "Missing or invalid access token provided.", }, - view_by_thing :{ + viewbything :{ 500: "Unexpected server-side error occurred.", - 404: "Failed to revoke corresponding certificate.", 401: "Missing or invalid access token provided.", }, revoke : { @@ -210,6 +216,7 @@ class Errors { }, get : { 401: "Missing or invalid access token provided.", + 404: "Channel does not exist.", }, getall : { 401: "Missing or invalid access token provided.", @@ -218,10 +225,10 @@ class Errors { createbulk : { 401: "Missing or invalid access token provided.", 400: "Failed due to malformed JSON.", + 409: "Entity already exists.", }, getbything : { - 401: "Missing or invalid access token provided.", - 400: "Failed due to malformed query parameters.", + 500: "Unexpected server-side error occurred.", }, update : { 401: "Missing or invalid access token provided.", @@ -230,7 +237,6 @@ class Errors { }, disable : { 401: "Missing or invalid access token provided.", - 400: "Failed due to malformed JSON.", 404: "Failed due to a non-existing channel.", }, } @@ -259,8 +265,7 @@ class Errors { }, update : { 401 : "Missing or invalid access token provided.", - 404 : " Config does not exist.", - 400 : "Failed due to malformed JSON.", + 404 : "Config does not exist.", }, remove : { 401 : "Missing or invalid access token provided.", @@ -277,7 +282,6 @@ class Errors { }, bootstrap : { 401 : "Missing or invalid external key provided.", - 400 : "Failed due to malformed JSON.", }, } } diff --git a/mainflux/groups.js b/mainflux/groups.js index 797db8f..121c640 100644 --- a/mainflux/groups.js +++ b/mainflux/groups.js @@ -1,5 +1,5 @@ -// import Errors from "./errors.js"; const axios = require("axios"); +const Errors = require("./errors"); class Groups { //Groups API client. @@ -29,7 +29,7 @@ class Groups { * @returns {Groups} - Returns a Groups object. */ constructor(groups_url) { - this.groups_url = groups_url; + this.groups_url = new URL (groups_url); this.content_type = "application/json"; this.groupsEndpoint = "groups"; } @@ -46,6 +46,8 @@ class Groups { } } + groupError = new Errors; + Create(group, token) { // Create a new group. /** @@ -72,24 +74,29 @@ class Groups { const options = { method: "post", maxBodyLength: 2000, - url: `${this.groups_url}/${this.groupsEndpoint}`, + url: new URL (this.groupsEndpoint, this.groups_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(group), + data: group, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response){ + return this.groupError.HandleError( + this.groupError.groups.create, + error.response.status + ); + }; }); } Get(group_id, token) { - //Get a group. + //Get information about a group. /** * @method Get - Provide a group's information once given the group ID and a valid token. * @param {string} group_id - The group's ID. @@ -109,7 +116,7 @@ class Groups { const options = { method: "get", maxBodyLength: 2000, - url: `${this.groups_url}/${this.groupsEndpoint}/${group_id}`, + url: new URL (`${this.groupsEndpoint}/${group_id}`, this.groups_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -120,8 +127,13 @@ class Groups { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.groupError.HandleError( + this.groupError.groups.get, + error.response.status + ); + }; + }); } GetAll(query_params, token) { @@ -148,7 +160,7 @@ class Groups { const options = { method: "get", maxBodyLength: 2000, - url: `${this.groups_url}/${this.groupsEndpoint}?${new URLSearchParams(query_params).toString()}`, + url: new URL (`${this.groupsEndpoint}?${new URLSearchParams(query_params).toString()}`, this.groups_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -159,8 +171,13 @@ class Groups { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.groupError.HandleError( + this.groupError.groups.getall, + error.response.status + ); + }; + }); } Update(group_id, group, token) { @@ -188,20 +205,25 @@ class Groups { const options = { method: "put", maxBodyLength: 2000, - url: `${this.groups_url}/${this.groupsEndpoint}/${group_id}`, + url: new URL (`${this.groupsEndpoint}/${group_id}`, this.groups_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(group), + data: group, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.groupError.HandleError( + this.groupError.groups.update, + error.response.status + ); + }; + }); } Children(group_id, query_params, token) { @@ -228,7 +250,7 @@ class Groups { const options = { method: "get", maxBodyLength: 2000, - url: `${this.groups_url}/${this.groupsEndpoint}/${group_id}/children?${new URLSearchParams(query_params).toString()}`, + url: new URL (`${this.groupsEndpoint}/${group_id}/children?${new URLSearchParams(query_params).toString()}`, this.groups_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -239,8 +261,13 @@ class Groups { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.groupError.HandleError( + this.groupError.groups.children, + error.response.status + ); + }; + }); } Parents(group_id, query_params, token) { @@ -268,7 +295,7 @@ class Groups { const options = { method: "get", maxBodyLength: 2000, - url: `${this.groups_url}/${this.groupsEndpoint}/${group_id}/parents?${new URLSearchParams(query_params).toString()}`, + url: new URL(`${this.groupsEndpoint}/${group_id}/parents?${new URLSearchParams(query_params).toString()}`, this.groups_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -279,8 +306,13 @@ class Groups { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.groupError.HandleError( + this.groupError.groups.parents, + error.response.status + ); + }; + }); } Assign(group_id, member_id, member_type, token) { @@ -311,20 +343,25 @@ class Groups { const options = { method: "post", maxBodyLength: 2000, - url: `${this.groups_url}/policies`, + url: new URL (`policies`, this.groups_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }; return axios.request(options) .then((_response) => { return "Policy created"; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.groupError.HandleError( + this.groupError.groups.assign, + error.response.status + ); + }; + }); } Unassign(member_id, group_id, token) { @@ -348,20 +385,25 @@ class Groups { const options = { method: "delete", maxBodyLength: 2000, - url: `${this.groups_url}/policies/${member_id}/${group_id}`, + url: new URL (`policies/${member_id}/${group_id}`, this.groups_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }; return axios.request(options) .then((_response) => { return "Policy deleted"; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.groupError.HandleError( + this.groupError.groups.unassign, + error.response.status + ); + }; + }); } Disable(group_id, token) { @@ -383,7 +425,7 @@ class Groups { const options = { method: "post", maxBodyLength: 2000, - url: `${this.groups_url}/${this.groupsEndpoint}/${group_id}/disable`, + url: new URL (`${this.groupsEndpoint}/${group_id}/disable`, this.groups_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -394,8 +436,13 @@ class Groups { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.groupError.HandleError( + this.groupError.groups.disable, + error.response.status + ); + }; + }); } Members(group_id, query_params, token) { @@ -422,7 +469,7 @@ class Groups { const options = { method: "get", maxBodyLength: 2000, - url: `${this.groups_url}/${this.groupsEndpoint}/${group_id}/members?${new URLSearchParams(query_params).toString()}`, + url: new URL (`${this.groupsEndpoint}/${group_id}/members?${new URLSearchParams(query_params).toString()}`, this.groups_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -433,8 +480,13 @@ class Groups { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.groupError.HandleError( + this.groupError.groups.members, + error.response.status + ); + }; + }); } } diff --git a/mainflux/messages.js b/mainflux/messages.js index d198f0d..d3467dd 100644 --- a/mainflux/messages.js +++ b/mainflux/messages.js @@ -1,4 +1,5 @@ -const axios = require("axios"); +const axios = require('axios'); +const Errors = require('./errors'); class Messages { //Messages API Client @@ -24,14 +25,14 @@ class Messages { * @param {string} readers_url - The url of the readers service. * @returns {Messages} - Returns a Messages object. */ - 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); + 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 /** @@ -78,7 +79,7 @@ class Messages { const options = { method: "post", maxBodyLength: 2000, - url: `${this.httpadapter_url}/http/channels/${chan_id}/messages/${subtopic}`, + url: new URL (`http/channels/${chan_id}/messages/${subtopic}`, this.httpadapter_url), headers: { "Content-Type": this.content_type, Authorization: `Thing ${thing_key}`, @@ -90,8 +91,13 @@ class Messages { return "Message Sent!"; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.messageError.HandleError( + this.messageError.messages.send, + error.response.status, + ); + }; + }); } Read(channel_id, token){ @@ -111,7 +117,7 @@ class Messages { 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 = ""; @@ -123,7 +129,7 @@ class Messages { const options = { method: "get", maxBodyLength: 2000, - url: `${this.readers_url}/channels/${chan_id}/messages`, + url: new URL (`channels/${chan_id}/messages`, this.readers_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -135,8 +141,13 @@ class Messages { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response){ + return this.messageError.HandleError( + this.messageError.messages.read, + error.response.status, + ); + }; + }); } } diff --git a/mainflux/things.js b/mainflux/things.js index e6d94e5..77547b5 100644 --- a/mainflux/things.js +++ b/mainflux/things.js @@ -1,4 +1,5 @@ const axios = require("axios"); +const Errors = require("./errors"); class Things { // Things service client. @@ -10,7 +11,7 @@ class Things { * @returns {Object} - Things service client. */ constructor(things_url) { - this.things_url = things_url; + this.things_url = new URL (things_url); this.content_type = "application/json"; this.thingsEndpoint = "things"; } @@ -32,6 +33,8 @@ class Things { } } + thingError = new Errors; + Create(thing, token) { //Creates a new thing. /** @@ -64,12 +67,12 @@ class Things { const options = { method: "post", maxBodyLength: 2000, - url: `${this.things_url}/${this.thingsEndpoint}`, + url: new URL(this.thingsEndpoint, this.things_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(thing), + data: thing, }; return axios .request(options) @@ -77,7 +80,12 @@ class Things { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.create, + error.response.status + ); + }; }); } @@ -109,12 +117,12 @@ class Things { const options = { method: "post", maxBodyLength: 2000, - url: `${this.things_url}/${this.thingsEndpoint}/bulk`, + url: new URL (`${this.thingsEndpoint}/bulk`, this.things_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(things), + data: things, }; return axios .request(options) @@ -122,7 +130,12 @@ class Things { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.createbulk, + error.response.status + ); + }; }); } @@ -144,7 +157,7 @@ class Things { const options = { method: "get", maxBodyLength: 2000, - url: `${this.things_url}/${this.thingsEndpoint}/${thing_id}`, + url: new URL(`${this.thingsEndpoint}/${thing_id}`, this.things_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -156,7 +169,12 @@ class Things { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.get, + error.response.status + ); + }; }); } @@ -179,7 +197,7 @@ class Things { const options = { method: "get", maxBodyLength: 2000, - url: `${this.things_url}/${this.thingsEndpoint}/${thing_id}/channels?${new URLSearchParams(query_params).toString()}`, + url: new URL (`${this.thingsEndpoint}/${thing_id}/channels?${new URLSearchParams(query_params).toString()}`, this.things_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -191,7 +209,12 @@ class Things { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.getbychannel, + error.response.status + ); + }; }); } @@ -214,7 +237,7 @@ class Things { const options = { method: "get", maxBodyLength: 2000, - url: `${this.things_url}/${this.thingsEndpoint}?${new URLSearchParams(query_params).toString()}`, + url: new URL (`${this.thingsEndpoint}?${new URLSearchParams(query_params).toString()}`, this.things_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -226,7 +249,12 @@ class Things { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.getall, + error.response.status + ); + }; }); } @@ -244,7 +272,7 @@ class Things { const options = { method: "post", maxBodyLength: 2000, - url: `${this.things_url}/${this.thingsEndpoint}/${thing_id}/disable`, + url: new URL (`${this.thingsEndpoint}/${thing_id}/disable`, this.things_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -256,7 +284,12 @@ class Things { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.disable, + error.response.status + ); + }; }); } @@ -289,12 +322,12 @@ class Things { const options = { method: "patch", maxBodyLength: 2000, - url: `${this.things_url}/${this.thingsEndpoint}/${thing_id}`, + url: new URL (`${this.thingsEndpoint}/${thing_id}`, this.things_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(thing), + data: thing, }; return axios .request(options) @@ -302,7 +335,12 @@ class Things { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.update, + error.response.status + ); + }; }); } @@ -335,12 +373,12 @@ class Things { const options = { method: "patch", maxBodyLength: 2000, - url: `${this.things_url}/${this.thingsEndpoint}/${thing_id}/secret`, + url: new URL (`${this.thingsEndpoint}/${thing_id}/secret`, this.things_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(thing), + data: thing, }; return axios .request(options) @@ -348,7 +386,12 @@ class Things { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.updatethingsecret, + error.response.status + ); + }; }); } @@ -382,12 +425,12 @@ class Things { const options = { method: "patch", maxBodyLength: 2000, - url: `${this.things_url}/${this.thingsEndpoint}/${thing_id}/tags`, + url: new URL (`${this.thingsEndpoint}/${thing_id}/tags`, this.things_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(thing), + data: thing, }; return axios .request(options) @@ -395,7 +438,12 @@ class Things { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.updatethingtags, + error.response.status + ); + }; }); } @@ -428,12 +476,12 @@ class Things { const options = { method: "patch", maxBodyLength: 2000, - url: `${this.things_url}/${this.thingsEndpoint}/${thing_id}/owner`, + url: new URL (`${this.thingsEndpoint}/${thing_id}/owner`, this.things_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(thing), + data: thing, }; return axios .request(options) @@ -441,11 +489,16 @@ class Things { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.updatethingowner, + error.response.status + ); + }; }); } - Connect(thing_id, channel_id, action, token) { + Connect(thing_id, channel_id, actions, token) { //Connects thing to channel. /** * @method Connect - Connects thing to channel when provided with a valid token, @@ -453,7 +506,7 @@ class Things { * the channel. * @param {string} thing_id - Thing ID. * @param {string} channel_id - Channel ID. - * @param {list} action - Action for example: ["m_read", "m_write"]. + * @param {list} actions - Action for example: ["m_read", "m_write"]. * @param {string} token - User token. * */ @@ -461,30 +514,35 @@ class Things { throw new Error('Invalid channel_id parameter. Expected a string.'); }; - if (!Array.isArray(action)) { + if (!Array.isArray(actions)) { throw new Error('Invalid parameter. Expected an array for action.'); }; this.ValidateThingIdThingAndToken(thing_id, {}, token); - const payload = { subject: thing_id, object: channel_id, action: action }; + const payload = { "subject": thing_id, "object": channel_id, "actions": actions } const options = { method: "post", maxBodyLength: 2000, - url: `${this.things_url}/policies`, + url: new URL (`connect`, this.things_url.toString()), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }; - return axios - .request(options) + console.log(options.url.toString()) + return axios.request(options) .then((_response) => { return "Policy created."; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.connect, + error.response.status + ); + }; }); } @@ -511,50 +569,59 @@ class Things { const options = { method: "post", maxBodyLength: 2000, - url: `${this.things_url}/connect`, + url: new URL (`connect`, this.things_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }; - return axios - .request(options) + console.log(options.url.toString()); + return axios.request(options) .then((_response) => { return "Policy created."; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.connects, + error.response.status + ); + }; }); } - Disconnect(thing_id, channel_id, token) { + Disconnect(thing_ids, channel_ids, token) { //Disconnects thing from channel. /** * @method Disconnect - Disconnects thing from channel when provided with a valid token, * channel id and a thing id. - * @param {list} thing_id - Thing ID. - * @param {list} channel_id - Channel ID. + * @param {list} thing_ids - Thing ID. + * @param {list} channel_ids - Channel ID. * @param {string} token - User token. * */ - if (typeof channel_id !== 'string' || channel_id === null) { - throw new Error('Invalid channel_id parameter. Expected a string.'); + if (!Array.isArray(channel_ids)) { + throw new Error('Invalid parameter. Expected an array for channel_id.'); }; - this.ValidateThingIdThingAndToken(thing_id, {}, token); + if (!Array.isArray(thing_ids)) { + throw new Error('Invalid parameter. Expected an array for thing_id.'); + }; + + this.ValidateThingIdThingAndToken('', {}, token); - const payload = { "subjects": thing_id, "objects": channel_id } + const payload = { "subjects": thing_ids, "objects": channel_ids } const options = { method: "post", maxBodyLength: 2000, - url: `${this.things_url}/disconnect`, + url: new URL (`disconnect`, this.things_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }; return axios .request(options) @@ -562,7 +629,12 @@ class Things { return "Policy deleted."; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.disconnect, + error.response.status + ); + }; }); } @@ -583,19 +655,24 @@ class Things { const options = { method: "post", maxBodyLength: 2000, - url: `${this.things_url}/identify`, + url: new URL(`identify`, this.things_url.toString()), headers: { "Content-Type": this.content_type, Authorization: `Thing ${thing_key}`, }, }; - return axios - .request(options) + console.log(options.url.toString()); + return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.thingError.HandleError( + this.thingError.things.identifything, + error.response.status + ); + }; }); } @@ -607,7 +684,7 @@ class Things { * @param {string} thing_id - Thing ID. * @param {string} channel_id - Channel ID. * @param {string} action - Action for example: ["m_read", "m_write"]. - * @param {string} entity_type - Type of the thing class for example: "client" + * @param {string} entity_type - Type of the thing class for example: "group". * @param {string} token - User token. * @return {Object} - True if thing is authorised, false if not. */ @@ -629,15 +706,15 @@ class Things { const options = { method: "post", maxBodyLength: 2000, - url: `${this.things_url}/channels/object/access`, + url: new URL (this.things_url + `channels/object/access`), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(access_request), + data: access_request, }; - return axios - .request(options) + console.log(options.url.toString()); + return axios.request(options) .then((_response) => { return true; }) diff --git a/mainflux/users.js b/mainflux/users.js index 2e9e67a..82443d2 100644 --- a/mainflux/users.js +++ b/mainflux/users.js @@ -1,23 +1,22 @@ -const axios = require("axios"); +const axios = require('axios'); +const Errors = require("./errors"); class Users { - // Users API client - /** - * @class Users - - * Users API is used for creating and managing users. - * It is used for creating new users, logging in, refreshing tokens, - * getting user information, updating user information, disabling - * and enabling users. - * @param {String} users_url - URL to the Users service. - * @param {String} content_type - Content type for the requests. - * @param {String} usersEndpoint - Endpoint for the users service. - * @returns {Object} - Users object. - */ - constructor(users_url) { - this.users_url = users_url; - this.content_type = "application/json"; - this.usersEndpoint = "users"; - } + // Users API client + /** + * @class Users - + * Users API is used for creating and managing users. + * It is used for creating new users, logging in, refreshing tokens, + * getting user information, updating user information, disabling + * and enabling users. + * @param {String} users_url - URL to the Users service. + * @returns {Object} - Users object. + */ + constructor(users_url) { + this.users_url = new URL (users_url); + this.content_type = "application/json"; + this.usersEndpoint = "users"; + } Create(user, token) { // Creates a new user @@ -42,6 +41,8 @@ class Users { } } + userError = new Errors; + Create(user, token) { // Creates a new user /** @@ -56,7 +57,6 @@ class Users { * "password": "12345678" * } * } - * */ this.ValidateUserAndToken(user, token); @@ -64,58 +64,64 @@ class Users { const options = { method: "post", maxBodyLength: 2000, - url: `${this.users_url}/${this.usersEndpoint}`, + url: new URL (this.usersEndpoint, this.users_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; - }) + if (error.response) { + return this.userError.HandleError( + this.userError.users.create, + error.response.status + ); + }; + }); } - const options = { - method: "post", - maxBodyLength: Infinity, - url: `${this.users_url}/${this.usersEndpoint}/tokens/issue`, - headers: { - "Content-Type": this.content_type, - }, - data: JSON.stringify(user), - }; - return axios - .request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - return error; - }); - } - - this.ValidateUserAndToken(user); + Login(user) { + // Issue Access and Refresh Token used for authenticating into the system + /** + * @method Login - Issue Access and Refresh Token used for authenticating into the system. + * @param {Object} user - User object. + * @returns {Object} - Access and Refresh Token. + * @example + * const user = { + * "credentials": { + * "identity": "admin@example.com", + * "password": "12345678" + * } + * } + */ + + this.ValidateUserAndToken(user, ''); const options = { method: "post", maxBodyLength: 2000, - url: `${this.users_url}/${this.usersEndpoint}/tokens/issue`, + url: new URL (`${this.usersEndpoint}/tokens/issue`, this.users_url), headers: { "Content-Type": this.content_type, }, - data: JSON.stringify(user), + data: user, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error; + if (error.response) { + return this.userError.HandleError( + this.userError.users.login, + error.response.status + ); + }; }); } @@ -139,27 +145,32 @@ class Users { if (typeof refresh_token !== 'string') { throw new Error('Invalid token parameter. Expected a string.'); }; - + const options = { method: "post", maxBodyLength: 2000, - url: `${this.users_url}/${this.usersEndpoint}/tokens/refresh`, + url: new URL (`${this.usersEndpoint}/tokens/refresh`, this.users_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${refresh_token}`, }, - data: JSON.stringify(user), + data: user, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error; + if (error.response) { + return this.userError.HandleError( + this.userError.users.refreshtoken, + error.response.status + ); + }; }); } - Update(user, token) { + Update(user, user_id, token) { // Update a user /** * @method Update - Update a user. Updates a user's name and metadata. @@ -174,28 +185,37 @@ class Users { * */ - this.ValidateUserAndToken(user, token); + this.ValidateUserAndToken({}, token); + + if (typeof user_id !== 'string' || user_id === null) { + throw new Error('Invalid user_id parameter. Expected a string.'); + } const options = { method: "patch", - url: `${this.users_url}/${this.usersEndpoint}/${user["id"]}`, + url: new URL (`${this.usersEndpoint}/${user_id}`, this.users_url), maxBodyLength: 2000, headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.userError.HandleError( + this.userError.users.update, + error.response.status + ); + }; }); } - UpdateUserIdentity(user, token) { + UpdateUserIdentity(user, user_id, token) { // Update a user identity /** * @method UpdateUserIdentity - Update a user identity for a currently logged in user. @@ -214,27 +234,36 @@ class Users { */ this.ValidateUserAndToken(user, token); + + if (typeof user_id !== 'string' || user_id === null) { + throw new Error('Invalid user_id parameter. Expected a string.'); + } const options = { method: "patch", - url: `${this.users_url}/${this.usersEndpoint}/${user["id"]}/identity`, + url: new URL (`${this.usersEndpoint}/${user_id}/identity`, this.users_url), maxBodyLength: 2000, headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.userError.HandleError( + this.userError.users.updateuseridentity, + error.response.status + ); + }; }); } - UpdateUserTags(user, token) { + UpdateUserTags(user,user_id, token) { // Update a user's tags. /** * Updates tags of the user with provided ID. Tags is updated using @@ -259,105 +288,88 @@ class Users { */ this.ValidateUserAndToken(user, token); + + if (typeof user_id !== 'string' || user_id === null) { + throw new Error('Invalid user_id parameter. Expected a string.'); + } const options = { method: "patch", - url: `${this.users_url}/${this.usersEndpoint}/${user["id"]}/tags`, + url: new URL(`${this.usersEndpoint}/${user_id}/tags`, this.users_url), maxBodyLength: 2000, headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }; - UpdateUserOwner(user, token) { - // Update a user's owner. - /** - * Updates owner of the user with provided ID. The owner is updated using - * authorization user_tokeN. - * @method UpdateUserOwner - Update a user's owner. - * @param {Object} user - User object. - * @param{String} token - Access token. - * @returns {Object} - User object. - * @example - * const user = { - * "name": "example", - * "id": "886b4266-77d1-4258-abae-2931fb4f16de" - * "tags": [ - * "back", - * "end" - * ] - * "metadata": { - * "foo": "bar" - * } - * "owner":"886b4266-77d1-4258-abae-2931fb4f16de" - * } - * - */ - const options = { - method: "patch", - url: `${this.users_url}/${this.usersEndpoint}/${user["id"]}/owner`, - maxBodyLength: Infinity, - headers: { - "Content-Type": this.content_type, - Authorization: `Bearer ${token}`, - }, - data: JSON.stringify(user), - }; - return axios - .request(options) - .then((response) => { - return response.data; - }) - .catch((error) => { - return error.response.data; - }); - } - - UpdateUserOwner(user, token) { + return axios.request(options) + .then((response) => { + return response.data; + }) + .catch((error) => { + if (error.response) { + return this.userError.HandleError( + this.userError.users.updateusertags, + error.response.status + ); + }; + }); + } + + UpdateUserOwner(user, user_id, token) { // Update a user's owner. - /** - * Updates owner of the user with provided ID. The owner is updated using - * authorization user_tokeN. - * @method UpdateUserOwner - Update a user's owner. - * @param {Object} user - User object. - * @param{String} token - Access token. - * @returns {Object} - User object. - * @example - * const user = { - * "name": "example", - * "id": "886b4266-77d1-4258-abae-2931fb4f16de" - * "tags": [ - * "back", - * "end" - * ] - * "metadata": { - * "foo": "bar" - * } - * "owner":"886b4266-77d1-4258-abae-2931fb4f16de" - * } - * - */ + /** + * Updates owner of the user with provided ID. The owner is updated using + * authorization user_tokeN. + * @method UpdateUserOwner - Update a user's owner. + * @param {Object} user - User object. + * @param{String} token - Access token. + * @returns {Object} - User object. + * @example + * const user = { + * "name": "example", + * "id": "886b4266-77d1-4258-abae-2931fb4f16de" + * "tags": [ + * "back", + * "end" + * ] + * "metadata": { + * "foo": "bar" + * } + * "owner":"886b4266-77d1-4258-abae-2931fb4f16de" + * } + * + */ this.ValidateUserAndToken(user, token); + if (typeof user_id !== 'string' || user_id === null) { + throw new Error('Invalid user_id parameter. Expected a string.'); + } + const options = { method: "patch", - url: `${this.users_url}/${this.usersEndpoint}/${user["id"]}/owner`, + url: new URL(`${this.usersEndpoint}/${user_id}/owner`, this.users_url), maxBodyLength: 2000, headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.userError.HandleError( + this.userError.users.updateuserowner, + error.response.status + ); + }; }); } @@ -381,20 +393,25 @@ class Users { const secret = { old_secret: old_secret, new_secret: new_secret } const options = { method: "patch", - url: `${this.users_url}/${this.usersEndpoint}/secret`, + url: new URL (`${this.usersEndpoint}/secret`, this.users_url), maxBodyLength: 2000, headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(secret), + data: secret, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.userError.HandleError( + this.userError.users.updateuserpassword, + error.response.status + ); + }; }); } @@ -421,7 +438,7 @@ class Users { const options = { method: "get", maxBodyLength: 2000, - url: `${this.users_url}/${this.usersEndpoint}/${user_id}`, + url: new URL (`${this.usersEndpoint}/${user_id}`, this.users_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -432,7 +449,12 @@ class Users { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.userError.HandleError( + this.userError.users.get, + error.response.status + ); + }; }); } @@ -463,7 +485,7 @@ class Users { const options = { method: "get", maxBodyLength: 2000, - url: `${this.users_url}/${this.usersEndpoint}?${new URLSearchParams(query_params).toString()}`, + url: new URL (`${this.usersEndpoint}?${new URLSearchParams(query_params).toString()}`, this.users_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, @@ -474,22 +496,16 @@ class Users { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.userError.HandleError( + this.userError.users.getall, + error.response.status + ); + }; }); - // return fetch(url , options) - // .then((response) => { - // if (!response.ok) { - // return this.userError.HandleError(this.userError.errors, response.status); - // // throw new Error(`HTTP error! Status: ${response.status}`); - // } - // return response.json(); - // }) - // .catch((error) => { - // console.error('Fetch error:', error); - // }); } - Disable(user, token) { + Disable(user, user_id, token) { // Disable a user /** * Disables a user with provided ID and valid token. @@ -506,26 +522,35 @@ class Users { this.ValidateUserAndToken(user, token); + if (typeof user_id !== 'string' || user_id === null) { + throw new Error('Invalid user_id parameter. Expected a string.'); + } + const options = { method: "post", maxBodyLength: 2000, - url: `${this.users_url}/${this.usersEndpoint}/${user["id"]}/disable`, + url: new URL (`${this.usersEndpoint}/${user_id}/disable`, this.users_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.userError.HandleError( + this.userError.users.disable, + error.response.status + ); + }; }); } - Enable(user, token) { + Enable(user, user_id, token) { // Enable a user. /** * Enables a previously disabled user when provided with token and valid ID. @@ -546,19 +571,24 @@ class Users { const options = { method: "post", maxBodyLength: 2000, - url: `${this.users_url}/${this.usersEndpoint}/${user["id"]}/enable`, + url: new URL (`${this.usersEndpoint}/${user_id}/enable`, this.users_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.userError.HandleError( + this.userError.users.enable, + error.response.status + ); + }; }); } @@ -586,19 +616,23 @@ class Users { const options = { method: "get", maxBodyLength: 2000, - url: `${this.users_url}/${this.usersEndpoint}/${member_id}/memberships?${new URLSearchParams(query_params).toString()}`, + url: new URL (`${this.usersEndpoint}/${member_id}/memberships?${new URLSearchParams(query_params).toString()}`, this.users_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - params: query_params, }; return axios.request(options) .then((response) => { return response.data; }) .catch((error) => { - return error.response.data; + if (error.response) { + return this.userError.HandleError( + this.userError.users.memberships, + error.response.status + ); + }; }); } @@ -616,10 +650,10 @@ class Users { */ if ( - typeof user_id !== 'string' || - typeof group_id !== 'string' || - typeof action !== 'string' || - typeof entity_type !== 'string' || + typeof user_id !== 'string' || + typeof group_id !== 'string' || + typeof action !== 'string' || + typeof entity_type !== 'string' || typeof token !== 'string') { throw new Error('Invalid parameter types. Expected strings for user_id, group_id, action, entity_type, and token.'); }; @@ -633,12 +667,12 @@ class Users { const options = { method: "post", maxBodyLength: 2000, - url: `${this.users_url}/authorize`, + url: new URL(`authorize`, this.users_url), headers: { "Content-Type": this.content_type, Authorization: `Bearer ${token}`, }, - data: JSON.stringify(access_request), + data: access_request, }; return axios.request(options) .then((_response) => { diff --git a/package-lock.json b/package-lock.json index 447199c..e689086 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,16 @@ { "name": "mainflux-sdk", - "version": "0.14.33", + "version": "0.14.37", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mainflux-sdk", - "version": "0.14.33", + "version": "0.14.37", "license": "Apache-2.0", "dependencies": { - "axios": "^1.5.1", - "browser-resolve": "^2.0.0", - "mainflux-sdk": "^0.14.26", + "axios": "^1.5.0", + "mainflux-sdk": "^0.14.37", "node-fetch": "^3.3.2" }, "devDependencies": { @@ -173,12 +172,12 @@ "dev": true }, "node_modules/@babel/generator": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz", - "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "dependencies": { - "@babel/types": "^7.22.15", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -213,13 +212,13 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -428,9 +427,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", - "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -660,19 +659,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.20.tgz", - "integrity": "sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.22.15", + "@babel/generator": "^7.23.0", "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.22.5", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.16", - "@babel/types": "^7.22.19", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -681,13 +680,13 @@ } }, "node_modules/@babel/types": { - "version": "7.22.19", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.19.tgz", - "integrity": "sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.19", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -4118,9 +4117,9 @@ } }, "node_modules/mainflux-sdk": { - "version": "0.14.33", - "resolved": "https://registry.npmjs.org/mainflux-sdk/-/mainflux-sdk-0.14.33.tgz", - "integrity": "sha512-2v1ByIqB9/+K+0Y2zz99UNYquWMn9t9r1490fd6SNFRy9TtO61KoObOA5Igl94ZKz0cjngYFr55irUbxqgQuHA==", + "version": "0.14.37", + "resolved": "https://registry.npmjs.org/mainflux-sdk/-/mainflux-sdk-0.14.37.tgz", + "integrity": "sha512-RXXFGC7UOiLvdZhK+SehC2PaDOhKIUyNPQjwMsD0/nzYbqpH3t9I7L4u4mvQE1joncqaGPHLu75lh/dd+/WwKA==", "dependencies": { "axios": "^1.5.0", "node-fetch": "^3.3.2" @@ -5777,12 +5776,12 @@ } }, "@babel/generator": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz", - "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "requires": { - "@babel/types": "^7.22.15", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -5808,13 +5807,13 @@ "dev": true }, "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { @@ -5971,9 +5970,9 @@ } }, "@babel/parser": { - "version": "7.22.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", - "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -6134,31 +6133,31 @@ } }, "@babel/traverse": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.20.tgz", - "integrity": "sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dev": true, "requires": { "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.22.15", + "@babel/generator": "^7.23.0", "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.22.5", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.16", - "@babel/types": "^7.22.19", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.22.19", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.19.tgz", - "integrity": "sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.19", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -8814,9 +8813,9 @@ } }, "mainflux-sdk": { - "version": "0.14.33", - "resolved": "https://registry.npmjs.org/mainflux-sdk/-/mainflux-sdk-0.14.33.tgz", - "integrity": "sha512-2v1ByIqB9/+K+0Y2zz99UNYquWMn9t9r1490fd6SNFRy9TtO61KoObOA5Igl94ZKz0cjngYFr55irUbxqgQuHA==", + "version": "0.14.37", + "resolved": "https://registry.npmjs.org/mainflux-sdk/-/mainflux-sdk-0.14.37.tgz", + "integrity": "sha512-RXXFGC7UOiLvdZhK+SehC2PaDOhKIUyNPQjwMsD0/nzYbqpH3t9I7L4u4mvQE1joncqaGPHLu75lh/dd+/WwKA==", "requires": { "axios": "^1.5.0", "node-fetch": "^3.3.2" diff --git a/package.json b/package.json index 58963f2..88a14c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mainflux-sdk", - "version": "0.14.33", + "version": "0.14.37", "description": "Official Mainflux Javascript sdk", "main": "index.js", "engines": { @@ -34,9 +34,8 @@ }, "homepage": "https://github.com/mainflux/sdk-js#readme", "dependencies": { - "axios": "^1.5.1", - "browser-resolve": "^2.0.0", - "mainflux-sdk": "^0.14.26", + "axios": "^1.5.0", + "mainflux-sdk": "^0.14.37", "node-fetch": "^3.3.2" }, "devDependencies": { diff --git a/tests/bootstraps.test.js b/tests/bootstraps.test.js index f2fddaa..e0da309 100644 --- a/tests/bootstraps.test.js +++ b/tests/bootstraps.test.js @@ -145,20 +145,45 @@ describe("Bootstraps", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(config), + data: config, }); expect(result).toEqual('Configuration added'); }); }); - }); - test("Bootstrap should retrieve a config and return success", () => { - axios.request.mockResolvedValueOnce({ data: config }); + test( 'Create should handle a conflict error', ()=>{ + const errorResponse = { + response: { + status: 401, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); - const expectedUrl = `${bootstraps_url}/things/bootstrap/${external_id}`; + const expectedUrl = `${bootstraps_url}/things/configs`; const sdk = new mfsdk({bootstrapsUrl : bootstraps_url}); - return sdk.bootstrap.Whitelist(config, token).then(result => { + return sdk.bootstrap.Create(config, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: 'post', + maxBodyLength: 2000, + url: expectedUrl, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + data: config, + }); + expect(result).toBe("Missing or invalid access token provided."); + }); + }); + + test( 'Whitelist should update a config and return success', ()=>{ + axios.request.mockResolvedValueOnce({data: 'Configuration updated'}); + + const expectedUrl = `${bootstraps_url}/things/state/${thing_id}`; + + const sdk = new mfsdk({bootstrapsUrl : bootstraps_url}); + return sdk.bootstrap.Whitelist(config, thing_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ method: 'put', maxBodyLength: 2000, @@ -167,19 +192,46 @@ describe("Bootstraps", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(config), + data: config, }); - expect(result).toEqual('Configuration updated'); + expect(result).toBe("Missing or invalid access token provided."); + }); + }); + + test( 'Whitelist should handle a conflict error', ()=>{ + const errorResponse = { + response: { + status: 401, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + + const expectedUrl = `${bootstraps_url}/things/state/${thing_id}`; + + const sdk = new mfsdk({bootstrapsUrl : bootstraps_url}); + return sdk.bootstrap.Whitelist(config, thing_id, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: 'put', + maxBodyLength: 2000, + url: expectedUrl, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + data: config, + }); + expect(result).toBe("Missing or invalid access token provided."); }); }); test( 'Update should update a config and return success', ()=>{ axios.request.mockResolvedValueOnce({data: 'Configuration updated'}); - const expectedUrl = `${bootstraps_url}/things/configs/${config["thing_id"]}`; + const expectedUrl = `${bootstraps_url}/things/configs/${thing_id}`; const sdk = new mfsdk({bootstrapsUrl : bootstraps_url}); - return sdk.bootstrap.Update(config, token).then(result => { + return sdk.bootstrap.Update(config, thing_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ method: 'put', maxBodyLength: 2000, @@ -188,12 +240,38 @@ describe("Bootstraps", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(config), + data: config, }); expect(result).toEqual('Configuration updated'); }); }); + test( 'Update should handle a conflict error', ()=>{ + const errorResponse = { + response: { + status: 401, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + const expectedUrl = `${bootstraps_url}/things/configs/${thing_id}`; + + const sdk = new mfsdk({bootstrapsUrl : bootstraps_url}); + return sdk.bootstrap.Update(config, thing_id, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: 'put', + maxBodyLength: 2000, + url: expectedUrl, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + data: config, + }); + expect(result).toBe("Missing or invalid access token provided."); + }); + }); + test( 'View should get a config and return success', ()=>{ axios.request.mockResolvedValueOnce({data: config}); @@ -214,6 +292,31 @@ describe("Bootstraps", () => { }); }); + test( 'View should handle a conflict error', ()=>{ + const errorResponse = { + response: { + status: 401, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + const expectedUrl = `${bootstraps_url}/things/configs/${thing_id}`; + + const sdk = new mfsdk({bootstrapsUrl : bootstraps_url}); + return sdk.bootstrap.View(thing_id, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: 'get', + maxBodyLength: 2000, + url: expectedUrl, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + }); + expect(result).toBe("Missing or invalid access token provided."); + }); + }); + test( 'UpdateCerts should update a config and return success', ()=>{ axios.request.mockResolvedValueOnce({data: config}); @@ -233,12 +336,42 @@ describe("Bootstraps", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }); expect(result).toEqual(config); }); }); + test( 'UpdateCerts should handle a conflict error', ()=>{ + const errorResponse = { + response: { + status: 401, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + const expectedUrl = `${bootstraps_url}/configs/certs/${config_id}`; + const payload = { + "client_cert": client_cert, + "client_key": client_key, + "ca_cert": ca, + }; + const sdk = new mfsdk({bootstrapsUrl : bootstraps_url}); + return sdk.bootstrap.UpdateCerts(config_id,client_cert,client_key, ca, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: 'patch', + maxBodyLength: 2000, + url: expectedUrl, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + data: payload, + }); + expect(result).toBe("Missing or invalid access token provided."); + }); + }); + test( 'Remove should delete a config and return success', ()=>{ axios.request.mockResolvedValueOnce({data: 'Configuration removed'}); @@ -259,6 +392,31 @@ describe("Bootstraps", () => { }); }); + test( 'Remove should handle a conflict error', ()=>{ + const errorResponse = { + response: { + status: 401, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + const expectedUrl = `${bootstraps_url}/things/configs/${config_id}`; + + const sdk = new mfsdk({bootstrapsUrl : bootstraps_url}); + return sdk.bootstrap.Remove(config_id, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: 'delete', + maxBodyLength: 2000, + url: expectedUrl, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + }); + expect(result).toBe("Missing or invalid access token provided."); + }); + }); + test( 'Bootstrap should retrieve a config and return success', ()=>{ axios.request.mockResolvedValueOnce({data: config}); @@ -279,4 +437,29 @@ describe("Bootstraps", () => { }); }); + test( 'Bootstrap should handle a conflict error', ()=>{ + const errorResponse = { + response: { + status: 401, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + const expectedUrl = `${bootstraps_url}/things/bootstrap/${external_id}`; + + const sdk = new mfsdk({bootstrapsUrl : bootstraps_url}); + return sdk.bootstrap.Bootstrap(external_id, external_key).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: 'get', + maxBodyLength: 2000, + url: expectedUrl, + headers: { + 'Content-Type': 'application/json', + Authorization: `Thing ${external_key}`, + }, + }); + expect(result).toBe("Missing or invalid external key provided."); + }); + }); + }); diff --git a/tests/certs.test.js b/tests/certs.test.js index 8e79caf..0c2f384 100644 --- a/tests/certs.test.js +++ b/tests/certs.test.js @@ -3,30 +3,27 @@ const mfsdk = require("mainflux-sdk"); jest.mock("axios"); -describe("Certs", () => { - const certs_url = "http://localhost"; - const certs = { - cert_serial: "22:16:df:60:c2:99:bc:c4:9b:1d:fd:71:5e:e9:07:d9:1b:3c:85:1d", - client_cert: - "-----BEGIN CERTIFICATE-----\nMIIEATCCAumgAwIBAgIUIhbfYMKZvMSbHf1xXukH2Rs8hR0wDQYJKoZIhvcNAQEL1k\n-----END CERTIFICATE-----", - client_key: - "-----BEGIN RSA PRIVATE KEY-----\nMIIEoQIBAAKCAQEAy9gF84a5s6jlX6hkAPXrLYqvdhe6uygdr6eHfd5erdcdxfgc\n-----END RSA PRIVATE KEY-----", - expiration: "2023-09-20T10:02:48Z", - thing_id: "3d49a42f-63fd-491b-9784-adf4b64ef347", - }; - const cert_id = "22:16:df:60:c2:99:bc:c4:9b:1d:fd:71:5e:e9:07:d9:1b:3c:85:1d"; - const thing_id = "3d49a42f-63fd-491b-9784-adf4b64ef347"; - const token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9"; - const valid = "10h"; - const cert_serial = [ - "22:16:df:60:c2:99:bc:c4:9b:1d:fd:71:5e:e9:07:d9:1b:3c:85:1d", - ]; - test("Issue should add a cert and return success", () => { - axios.request.mockResolvedValueOnce({ data: certs }); +describe('Certs', () => { + const certs_url = 'http://localhost'; + const certs = { + "cert_serial": "22:16:df:60:c2:99:bc:c4:9b:1d:fd:71:5e:e9:07:d9:1b:3c:85:1d", + "client_cert": "-----BEGIN CERTIFICATE-----\nMIIEATCCAumgAwIBAgIUIhbfYMKZvMSbHf1xXukH2Rs8hR0wDQYJKoZIhvcNAQEL1k\n-----END CERTIFICATE-----", + "client_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEoQIBAAKCAQEAy9gF84a5s6jlX6hkAPXrLYqvdhe6uygdr6eHfd5erdcdxfgc\n-----END RSA PRIVATE KEY-----", + "expiration": "2023-09-20T10:02:48Z", + "thing_id": "3d49a42f-63fd-491b-9784-adf4b64ef347" + }; + const cert_id = "22:16:df:60:c2:99:bc:c4:9b:1d:fd:71:5e:e9:07:d9:1b:3c:85:1d"; + const thing_id = "3d49a42f-63fd-491b-9784-adf4b64ef347"; + const token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9"; + const valid = "10h"; + const cert_serial = ["22:16:df:60:c2:99:bc:c4:9b:1d:fd:71:5e:e9:07:d9:1b:3c:85:1d"]; + + test('Issue should add a cert and return success', () => { + axios.request.mockResolvedValueOnce({ data: certs }); const expectedUrl = `${certs_url}/certs`; - const payload = {"thing_id": thing_id, "ttl": valid} - const sdk = new mfsdk({certsUrl : certs_url}); + const payload = { "thing_id": thing_id, "ttl": valid } + const sdk = new mfsdk({ certsUrl: certs_url }); return sdk.certs.Issue(thing_id, valid, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ method: 'post', @@ -36,19 +33,44 @@ describe("Certs", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }); expect(result).toEqual(certs); }); }); - }); - test("ViewByThing should retrieve cert and return success", () => { - axios.request.mockResolvedValueOnce({ data: cert_serial }); + test('Issue should handle a conflict error', () => { + const errorResponse = { + response: { + status: 500, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + const expectedUrl = `${certs_url}/certs`; + const payload = { "thing_id": thing_id, "ttl": valid } + const sdk = new mfsdk({ certsUrl: certs_url }); + return sdk.certs.Issue(thing_id, valid, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: 'post', + maxBodyLength: 2000, + url: expectedUrl, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + data: payload, + }); + expect(result).toBe("Unexpected server-side error occurred."); + }); + }); + + test('ViewByThing should retrieve cert and return success', () => { + axios.request.mockResolvedValueOnce({ data: cert_serial }); const expectedUrl = `${certs_url}/serials/${thing_id}`; - const sdk = new mfsdk({certsUrl : certs_url}); + const sdk = new mfsdk({ certsUrl: certs_url }); return sdk.certs.ViewByThing(thing_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, @@ -62,14 +84,38 @@ describe("Certs", () => { expect(result).toEqual(cert_serial); }); }); - }); - test("ViewBySerial should retrieve cert and return success", () => { - axios.request.mockResolvedValueOnce({ data: certs }); + test('ViewByThing should handle a conflict error', () => { + const errorResponse = { + response: { + status: 500, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + const expectedUrl = `${certs_url}/serials/${thing_id}`; + + const sdk = new mfsdk({ certsUrl: certs_url }); + return sdk.certs.ViewByThing(thing_id, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + url: expectedUrl, + maxBodyLength: 2000, + method: 'get', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + }); + expect(result).toBe("Unexpected server-side error occurred."); + }); + }); + + test('ViewBySerial should retrieve cert and return success', () => { + axios.request.mockResolvedValueOnce({ data: certs }); const expectedUrl = `${certs_url}/certs/${cert_id}`; - const sdk = new mfsdk({certsUrl : certs_url}); + const sdk = new mfsdk({ certsUrl: certs_url }); return sdk.certs.ViewBySerial(cert_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ method: 'get', @@ -83,14 +129,38 @@ describe("Certs", () => { expect(result).toEqual(certs); }); }); - }); + + test('ViewBySerial should handle a conflict error', () => { + const errorResponse = { + response: { + status: 500, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + const expectedUrl = `${certs_url}/certs/${cert_id}`; + + const sdk = new mfsdk({ certsUrl: certs_url }); + return sdk.certs.ViewBySerial(cert_id, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: 'get', + maxBodyLength: 2000, + url: expectedUrl, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + }); + expect(result).toBe("Unexpected server-side error occurred."); + }); + }); test("Revoke should delete cert and return success", () => { axios.request.mockResolvedValueOnce("DELETED"); const expectedUrl = `${certs_url}/certs/${thing_id}`; - const sdk = new mfsdk({certsUrl : certs_url}); + const sdk = new mfsdk({ certsUrl: certs_url }); return sdk.certs.Revoke(thing_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ method: 'delete', @@ -104,5 +174,30 @@ describe("Certs", () => { expect(result).toEqual("DELETED"); }); }); - }); + + test('Revoke should handle a conflict error', () => { + const errorResponse = { + response: { + status: 500, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + const expectedUrl = `${certs_url}/certs/${thing_id}`; + + const sdk = new mfsdk({ certsUrl: certs_url }); + return sdk.certs.Revoke(thing_id, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: 'delete', + maxBodyLength: 2000, + url: expectedUrl, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + }); + expect(result).toBe("Unexpected server-side error occurred."); + }); + }); + }); diff --git a/tests/channels.test.js b/tests/channels.test.js index 6931d50..e8929e6 100644 --- a/tests/channels.test.js +++ b/tests/channels.test.js @@ -74,7 +74,7 @@ describe("Channels", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(channel), + data: channel, }); expect(result).toEqual(channel); }); @@ -100,9 +100,9 @@ describe("Channels", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(channel), + data: channel, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); }); @@ -146,7 +146,7 @@ describe("Channels", () => { Authorization: `Bearer ${token}`, }, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); }); @@ -173,7 +173,7 @@ describe("Channels", () => { test('Get by thing should handle a conflict error', () => { const errorResponse = { response: { - status: 401, + status: 500, }, }; axios.request.mockRejectedValueOnce(errorResponse); @@ -191,7 +191,7 @@ describe("Channels", () => { Authorization: `Bearer ${token}`, }, }); - console.log(result); + expect(result).toEqual("Unexpected server-side error occurred."); }); }); @@ -236,9 +236,9 @@ describe("Channels", () => { Authorization: `Bearer ${token}`, }, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); + }); }); - }); test("Get should retrieve a channel and return success", () => { axios.request.mockResolvedValueOnce({ data: channel }); @@ -255,7 +255,7 @@ describe("Channels", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(channels), + data: channels, }); expect(result).toEqual(channels); }); @@ -280,12 +280,11 @@ describe("Channels", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(channels), + data: channels, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); }); - }); test("Get_by_thing should retrieve things a channel is connected to and return success", () => { axios.request.mockResolvedValueOnce({ data: things }); @@ -302,13 +301,11 @@ describe("Channels", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(channel), + data: channel, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); - expect(result).toEqual(things); - }); - }); + }); test("Get by thing should handle a conflict error", () => { const errorResponse = { @@ -330,7 +327,7 @@ describe("Channels", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(channel), + data: channel, }); expect(result).toEqual(channel); }); @@ -402,7 +399,7 @@ describe("Channels", () => { Authorization: `Bearer ${token}`, }, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); }); }); diff --git a/tests/groups.test.js b/tests/groups.test.js index ffda703..99488f4 100644 --- a/tests/groups.test.js +++ b/tests/groups.test.js @@ -3,32 +3,27 @@ const mfsdk = require("mainflux-sdk"); jest.mock("axios"); -describe("Groups", () => { - const groups_url = "http://localhost"; - const group = { - name: "group_test", - id: "290b0f49-7a57-4b8c-9e4e-fbf17c6ab7d9", - parent_id: "290b0f49-7a57-4b8c-9e4e-fbf17c6ab7d9", - status: "enabled", - owner_id: "bb7edb32-2eac-4aad-aebe-ed96fe073879", - }; - const group_id = "290b0f49-7a57-4b8c-9e4e-fbf17c6ab7d9"; - const token = - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NjU3OTMwNjksImlhdCI6"; - const query_params = { - offset: 0, - limit: 10, - }; - const groups = [ - { name: "groupA", id: "bb7edb32-2eac-4aad-aebe-ed96fe073879" }, - { name: "groupB", id: "bb7edb32-2eac-4aad-aebe-ed96fe073879" }, - ]; - const member_id = "bb7edb32-2eac-4aad-aebe-ed96fe073879"; - const member_type = "m_read"; - const members_ids = [ - "bb7edb32-2eac-4aad-aebe-ed96fe073879", - "bb7edb32-2eac-4aad-aebe-ed96fe073879", - ]; +describe('Groups', () => { + const groups_url = "http://localhost"; + const group = { + "name": "group_test", + "id": "290b0f49-7a57-4b8c-9e4e-fbf17c6ab7d9", + "parent_id": "290b0f49-7a57-4b8c-9e4e-fbf17c6ab7d9", + "status": "enabled", + "owner_id": "bb7edb32-2eac-4aad-aebe-ed96fe073879" + }; + const group_id = "290b0f49-7a57-4b8c-9e4e-fbf17c6ab7d9"; + const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NjU3OTMwNjksImlhdCI6"; + const query_params = { + "offset": 0, "limit": 10 + }; + const groups = [ + { "name": "groupA", "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879" }, + { "name": "groupB", "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879" } + ]; + const member_id = "bb7edb32-2eac-4aad-aebe-ed96fe073879"; + const member_type = ["m_read", "m_write"]; + const members_ids = ["bb7edb32-2eac-4aad-aebe-ed96fe073879", "bb7edb32-2eac-4aad-aebe-ed96fe073879"]; test("Create should create a group and return success", () => { axios.request.mockResolvedValueOnce({ data: group }); @@ -122,7 +117,7 @@ describe("Groups", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(group), + data: group, }); expect(result).toEqual(group); }); @@ -146,9 +141,9 @@ describe("Groups", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(group), + data: group, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); }); }); @@ -197,7 +192,7 @@ describe("Groups", () => { Authorization: `Bearer ${token}`, }, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); }); }); @@ -248,7 +243,7 @@ describe("Groups", () => { Authorization: `Bearer ${token}`, }, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); }); }); @@ -275,7 +270,7 @@ describe("Groups", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(group), + data: group, }); expect(result).toEqual(group); }); @@ -299,9 +294,9 @@ describe("Groups", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(group), + data: group, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); }); }); @@ -355,7 +350,7 @@ describe("Groups", () => { Authorization: `Bearer ${token}`, }, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); expect(result).toEqual("Policy created"); }); @@ -431,7 +426,7 @@ describe("Groups", () => { Authorization: `Bearer ${token}`, }, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); }); }); @@ -451,7 +446,7 @@ describe("Groups", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }); expect(result).toEqual("Policy created"); }); @@ -478,9 +473,9 @@ describe("Groups", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); }); }); @@ -501,7 +496,7 @@ describe("Groups", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }); expect(result).toEqual("Policy deleted"); }); @@ -529,9 +524,9 @@ describe("Groups", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); }); @@ -576,7 +571,7 @@ describe("Groups", () => { Authorization: `Bearer ${token}`, }, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); }); @@ -621,9 +616,7 @@ describe("Groups", () => { Authorization: `Bearer ${token}`, }, }); - console.log(result); - // expect(result.error.status).toBe(1); - // expect(result.error.message).toBe('Missing or invalid access token provided.'); + expect(result).toEqual("Missing or invalid access token provided."); }); }); }); diff --git a/tests/messages.test.js b/tests/messages.test.js index e951e12..3e34a78 100644 --- a/tests/messages.test.js +++ b/tests/messages.test.js @@ -14,7 +14,7 @@ describe("Messages", () => { const httpadapter_url = 'http://localhost'; const readers_url = 'http://localhost'; const channel_id = "2b86beba-83dd-4b39-8165-4dda4e6eb4ad"; - const msg = '[{"bn":"demo", "bu":"V", "n":"voltage", "u":"V", "v":5}]'; + const msg = [{"bn":"demo", "bu":"V", "n":"voltage", "u":"V", "v":5}]; const token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9"; const thing_key = "fc68b31b-d7fd-4879-b3a7-0baf4580c5b1"; const chan_name_parts = channel_id.split(".", 2); @@ -44,7 +44,32 @@ describe("Messages", () => { expect(result).toEqual('Message Sent!'); }); }); - }); + + test('Send should handle a conflict error', () => { + const errorResponse = { + response: { + status: 400, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + const expectedUrl = `${httpadapter_url}/http/channels/${chan_id}/messages/${subtopic}`; + + const sdk = new mfsdk({ httpadapterUrl: httpadapter_url }); + return sdk.messages.Send(channel_id, msg, thing_key).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + url: expectedUrl, + method: 'post', + maxBodyLength: 2000, + headers: { + 'Content-Type': 'application/json', + Authorization: `Thing ${thing_key}`, + }, + data: new TextEncoder().encode(msg), + }); + expect(result).toBe('Message discarded due to its malformed content.'); + }); + }); test("Read should read a message and return success", () => { axios.request.mockResolvedValueOnce({ data: msg }); @@ -66,5 +91,31 @@ describe("Messages", () => { expect(result).toEqual(msg); }); }); - }); -}); + + test('Read should handle a conflict error', () => { + const errorResponse = { + response: { + status: 401, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + const expectedUrl = `${readers_url}/channels/${chan_id}/messages`; + + const sdk = new mfsdk({ readersUrl: readers_url }); + return sdk.messages.Read(channel_id, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + url: expectedUrl, + method: 'get', + maxBodyLength: 2000, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + params: {"subtopic": subtopic}, + }); + expect(result).toBe("Missing or invalid access token provided."); + }); + }); + +}) diff --git a/tests/things.test.js b/tests/things.test.js index 7fb1824..8163f64 100644 --- a/tests/things.test.js +++ b/tests/things.test.js @@ -3,366 +3,42 @@ const mfsdk = require("mainflux-sdk"); jest.mock("axios"); -describe("Things", () => { - const things_url = "http://localhost:9000"; - const thing = { - name: "thingName", - tags: ["tag1", "tag2"], - credentials: { - identity: "thingidentity", - secret: "bb7edb32-2eac-4aad-aebe-ed96fe073879", - }, - owner: "bb7edb32-2eac-4aad-aebe-ed96fe073879", - metadata: { - domain: "example.com", - }, - status: "enabled", - }; - const thing_id = "bb7edb32-2eac-4aad-aebe-ed96fe073879"; - const channel_id = "bb7edb32-2eac-4aad-aebe-ed96fe073879"; - const thing_ids = [ - "6cba4ea5-5820-4419-b389-86984309ad35", - "2bb290ff-0cb1-4f06-9da3-aff91c1d039", - ]; - const channel_ids = [ - "2bb290ff-0cb1-4f06-9da3-aff91c1d039", - "6cba4ea5-5820-4419-b389-86984309ad35", - ]; - const actions = ["m_read", "m_write"]; - const thing_key = "12345678"; - const action = ["m_read", "m_write"]; - const channels = [ - { name: "channel1", id: "bb7edb32-2eac-4aad-aebe-ed96fe073879" }, - { name: "channel2", id: "bb7edb32-2eac-4aad-aebe-ed96fe073879" }, - ]; - const entity_type = "group"; - const token = - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NjU3OTMwNjksImlhdCI6"; - const things = [ - { name: "thing1", id: "bb7edb32-2eac-4aad-aebe-ed96fe073879" }, - { name: "thing2", id: "bb7edb32-2eac-4aad-aebe-ed96fe073879" }, - ]; - const query_params = { - offset: 0, - limit: 10, - }; - - test("Create should create a thing and return success", () => { - axios.request.mockResolvedValue({ data: thing }); - - const expectedUrl = `${things_url}/things`; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things.Create(thing, token).then((result) => { - expect(result).toEqual(thing); - expect(axios.request).toHaveBeenCalledWith({ - method: "post", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, +describe('Things', () => { + const things_url = "http://localhost:9000"; + const thing = { + "name": "thingName", + "tags": [ + "tag1", + "tag2" + ], + "credentials": { + "identity": "thingidentity", + "secret": "bb7edb32-2eac-4aad-aebe-ed96fe073879" }, - data: JSON.stringify(thing), - }); - }); - }); - - test("Create should handle a conflict error", () => { - const errorResponse = { - response: { - status: 401, - }, - }; - axios.request.mockRejectedValue(errorResponse); - - const expectedUrl = `${things_url}/things`; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things.Create(thing, token).catch((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "post", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - data: JSON.stringify(thing), - }); - console.log(result); - }); - }); - - test("CreateBulk should create multiple things and return success", () => { - axios.request.mockResolvedValue({ data: things }); - - const expectedUrl = `${things_url}/things/bulk`; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things.CreateBulk(things, token).then((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "post", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - data: JSON.stringify(things), - }); - expect(result).toEqual(things); - }); - }); - - test("Update should update a thing and return success", () => { - axios.request.mockResolvedValue({ data: thing }); - - const expectedUrl = `${things_url}/things/${thing_id}`; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things.Update(thing_id, thing, token).then((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "patch", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - data: JSON.stringify(thing), - }); - expect(result).toEqual(thing); - }); - }); - - test("Get should give a thing and return success", () => { - axios.request.mockResolvedValue({ data: thing }); - - const expectedUrl = `${things_url}/things/${thing_id}`; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things.Get(thing_id, token).then((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "get", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - }); - expect(result).toEqual(thing); - }); - }); - - test("Get by channel return a channel a thing is connected and return success", () => { - axios.request.mockResolvedValue({ data: channels }); - - const expectedUrl = `${things_url}/things/${thing_id}/channels?${new URLSearchParams( - query_params, - ).toString()}`; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things - .GetByChannel(thing_id, query_params, token) - .then((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "get", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - }); - expect(result).toEqual(channels); - }); - }); - - test("GetAll should return all things and return success", () => { - axios.request.mockResolvedValue({ data: things }); - - const expectedUrl = `${things_url}/things?${new URLSearchParams( - query_params, - ).toString()}`; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things.GetAll(query_params, token).then((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "get", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - }); - expect(result).toEqual(things); - }); - }); - - test("Disable should delete a thing and return success", () => { - axios.request.mockResolvedValue({ data: thing }); - - const expectedUrl = `${things_url}/things/${thing_id}/disable`; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things.Disable(thing_id, token).then((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "post", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - }); - expect(result).toEqual(thing); - }); - }); - - test("Update should update a thing and return success", () => { - axios.request.mockResolvedValue({ data: thing }); - - const expectedUrl = `${things_url}/things/${thing_id}`; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things.Update(thing_id, thing, token).then((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "patch", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, + "owner": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + "metadata": { + "domain": "example.com" }, - data: JSON.stringify(thing), - }); - expect(result).toEqual(thing); - }); - }); - - test("Update thing secret should update a thing secret and return success", () => { - axios.request.mockResolvedValue({ data: thing }); - - const expectedUrl = `${things_url}/things/${thing_id}/secret`; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things - .UpdateThingSecret(thing_id, thing, token) - .then((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "patch", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - data: JSON.stringify(thing), - }); - expect(result).toEqual(thing); - }); - }); - - test("Update thing tags should update a thing tags and return success", () => { - axios.request.mockResolvedValue({ data: thing }); - - const expectedUrl = `${things_url}/things/${thing_id}/tags`; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things.UpdateThingTags(thing_id, thing, token).then((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "patch", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - data: JSON.stringify(thing), - }); - expect(result).toEqual(thing); - }); - }); - - test("Update thing owner should update a thing owner and return success", () => { - axios.request.mockResolvedValue({ data: thing }); - - const expectedUrl = `${things_url}/things/${thing_id}/owner`; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things - .UpdateThingOwner(thing_id, thing, token) - .then((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "patch", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - data: JSON.stringify(thing), - }); - expect(result).toEqual(thing); - }); - }); - - test("Update should update a thing and return success", () => { - axios.request.mockResolvedValue({ data: thing }); - - const expectedUrl = `${things_url}/things/${thing_id}`; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things.Update(thing_id, thing, token).then((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "patch", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - data: JSON.stringify(thing), - }); - expect(result).toEqual(thing); - }); - }); - - test("Connect should connect a thing and return success", () => { - axios.request.mockResolvedValue("Policy created."); - - const expectedUrl = `${things_url}/policies`; - const payload = { subject: thing_id, object: channel_id, action: action }; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things - .Connect(thing_id, channel_id, action, token) - .then((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "post", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - data: JSON.stringify(payload), - }); - expect(result).toEqual("Policy created."); - }); - }); - - test("Connects should connect things and return success", () => { - axios.request.mockResolvedValue("Policy created."); - - const expectedUrl = `${things_url}/connect`; - const payload = { - subjects: thing_ids, - objects: channel_ids, - actions: actions, + "status": "enabled" + }; + const thing_id = "bb7edb32-2eac-4aad-aebe-ed96fe073879"; + const channel_id = "bb7edb32-2eac-4aad-aebe-ed96fe073879"; + const thing_ids = ["6cba4ea5-5820-4419-b389-86984309ad35","2bb290ff-0cb1-4f06-9da3-aff91c1d039"]; + const channel_ids = ["2bb290ff-0cb1-4f06-9da3-aff91c1d039","6cba4ea5-5820-4419-b389-86984309ad35"]; + const actions = ["m_read", "m_write"]; + const thing_key= "12345678"; + const action = "m_read"; + const channels = [{"name": "channel1", "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879"}, + {"name": "channel2", "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879"} + ]; + const entity_type = "group"; + const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NjU3OTMwNjksImlhdCI6"; + const things = [ + {"name": "thing1", "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879"}, + {"name": "thing2", "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879"}, + ]; + const query_params = { + "offset": 0, "limit": 10 }; @@ -374,7 +50,7 @@ describe("Things", () => { const sdk = new mfsdk({thingsUrl: things_url}); return sdk.things.Create(thing, token).then(result => { - expect(result).toEqual(thing); + expect(axios.request).toHaveBeenCalledWith({ method: "post", maxBodyLength: 2000, @@ -383,39 +59,21 @@ describe("Things", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(thing), + data: thing, }); + expect(result).toEqual(thing); }); - expect(result).toEqual("Policy created."); - }); - }); - - test("Disconnect should disconnect things and return success", () => { - axios.request.mockResolvedValue("Policy deleted."); - - const expectedUrl = `${things_url}/disconnect`; - const payload = { subjects: thing_id, objects: channel_id }; - - const sdk = new mfsdk({ thingsUrl: things_url }); - return sdk.things.Disconnect(thing_id, channel_id, token).then((result) => { - expect(axios.request).toHaveBeenCalledWith({ - method: "post", - maxBodyLength: Infinity, - url: expectedUrl, - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - data: JSON.stringify(payload), - }); - expect(result).toEqual("Policy deleted."); }); - }); - test("Identify thing should identify a thing and return success", () => { - axios.request.mockResolvedValue({ data: thing }); + test('Create should handle a conflict error', ()=>{ + const errorResponse = { + response: { + status: 500, + }, + }; + axios.request.mockRejectedValue(errorResponse); - const expectedUrl = `${things_url}/identify`; + const expectedUrl = `${things_url}/things`; const sdk = new mfsdk({thingsUrl: things_url}); return sdk.things.Create(thing, token).catch(result => { @@ -427,11 +85,11 @@ describe("Things", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(thing), + data: thing, }); - console.log(result); + expect(result.error.status).toBe(1); + expect(result.error.message).toBe('Unexpected server-side error occurred.'); }); - }); test('CreateBulk should create multiple things and return success', ()=>{ @@ -449,12 +107,38 @@ describe("Things", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(things), + data: things, }); expect(result).toEqual(things); }); }); + test('CreateBulk should handle a conflict error', ()=>{ + const errorResponse = { + response: { + status: 500, + }, + }; + axios.request.mockRejectedValue(errorResponse); + + const expectedUrl = `${things_url}/things/bulk`; + + const sdk = new mfsdk({thingsUrl: things_url}); + return sdk.things.CreateBulk(things, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: "post", + maxBodyLength: 2000, + url: expectedUrl, + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + data: things, + }); + expect(result).toEqual("Unexpected server-side error occurred."); + }); + }); + test('Update should update a thing and return success', ()=>{ axios.request.mockResolvedValue({ data: thing}); @@ -470,12 +154,38 @@ describe("Things", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(thing), + data: thing, }); expect(result).toEqual(thing); }); }); + test('Update should handle a conflict error', ()=>{ + const errorResponse = { + response: { + status: 500, + }, + }; + axios.request.mockRejectedValue(errorResponse); + + const expectedUrl = `${things_url}/things/${thing_id}`; + + const sdk = new mfsdk({thingsUrl: things_url}); + return sdk.things.Update(thing_id, thing, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: "patch", + maxBodyLength: 2000, + url: expectedUrl, + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + data: thing, + }); + expect(result).toEqual("Unexpected server-side error occurred."); + }); + }); + test('Get should give a thing and return success', ()=>{ axios.request.mockResolvedValue({ data: thing}); @@ -496,6 +206,31 @@ describe("Things", () => { }); }); + test('Get should handle a conflict error', ()=>{ + const errorResponse = { + response: { + status: 401, + }, + }; + axios.request.mockRejectedValue(errorResponse); + + const expectedUrl = `${things_url}/things/${thing_id}`; + + const sdk = new mfsdk({thingsUrl: things_url}); + return sdk.things.Get(thing_id, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: "get", + maxBodyLength: 2000, + url: expectedUrl, + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + expect(result).toEqual("Missing or invalid access token provided."); + }); + }); + test('Get by channel return a channel a thing is connected and return success', ()=>{ axios.request.mockResolvedValue({ data: channels}); @@ -516,6 +251,31 @@ describe("Things", () => { }); }); + test('Get by channel should handle aconflict error', ()=>{ + const errorResponse = { + response: { + status: 401, + }, + }; + axios.request.mockRejectedValue(errorResponse); + + const expectedUrl = `${things_url}/things/${thing_id}/channels?${new URLSearchParams(query_params).toString()}`; + + const sdk = new mfsdk({thingsUrl: things_url}); + return sdk.things.GetByChannel(thing_id, query_params, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + method: "get", + maxBodyLength: 2000, + url: expectedUrl, + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + expect(result).toEqual("Missing or invalid access token provided."); + }); + }); + test('GetAll should return all things and return success', ()=>{ axios.request.mockResolvedValue({ data: things}); @@ -576,9 +336,9 @@ describe("Things", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(thing), + data: thing, }); - console.log(result); + expect(result).toEqual("Missing or invalid access token provided."); }); }); @@ -597,7 +357,7 @@ describe("Things", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(thing), + data: thing, }); expect(result).toEqual(thing); }); @@ -618,7 +378,7 @@ describe("Things", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(thing), + data: thing, }); expect(result).toEqual(thing); }); @@ -639,7 +399,7 @@ describe("Things", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(thing), + data: thing, }); expect(result).toEqual(thing); }); @@ -665,7 +425,7 @@ describe("Things", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(thing), + data: thing, }); console.log(result); }); @@ -675,10 +435,10 @@ describe("Things", () => { axios.request.mockResolvedValue("Policy created."); const expectedUrl = `${things_url}/policies`; - const payload = { "subject": thing_id, "object": channel_id, "action": action }; + const payload = { "subject": thing_id, "object": channel_id, "actions": actions }; const sdk = new mfsdk({thingsUrl: things_url}); - return sdk.things.Connect(thing_id, channel_id, action, token).then(result => { + return sdk.things.Connect(thing_id, channel_id, actions, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ method: "post", maxBodyLength: 2000, @@ -687,7 +447,7 @@ describe("Things", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }); expect(result).toEqual("Policy created."); }); @@ -709,7 +469,7 @@ describe("Things", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }); expect(result).toEqual("Policy created."); }); @@ -719,10 +479,10 @@ describe("Things", () => { axios.request.mockResolvedValue("Policy deleted."); const expectedUrl = `${things_url}/disconnect`; - const payload = { "subjects": thing_id, "objects": channel_id }; + const payload = { "subjects": thing_ids, "objects": channel_ids }; const sdk = new mfsdk({thingsUrl: things_url}); - return sdk.things.Disconnect(thing_id, channel_id, token).then(result => { + return sdk.things.Disconnect(thing_ids, channel_ids, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ method: "post", maxBodyLength: 2000, @@ -731,7 +491,7 @@ describe("Things", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(payload), + data: payload, }); expect(result).toEqual("Policy deleted."); }); @@ -778,7 +538,7 @@ describe("Things", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(access_request), + data: access_request, }); expect(result).toEqual(true); }); diff --git a/tests/users.test.js b/tests/users.test.js index 4b71826..97d049c 100644 --- a/tests/users.test.js +++ b/tests/users.test.js @@ -20,22 +20,42 @@ describe("Users", () => { status: "enabled", }; const user_id = "886b4266-77d1-4258-abae-2931fb4f16de"; - const token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9"; - const old_secret = "12345678"; - const new_secret = "87654321"; - const payload = { - old_secret: old_secret, - new_secret: new_secret, - }; - const access_request = { - subject: user_id, - object: "886b4266-77d1-4258-abae-2931fb4f16de", - action: "m_read", - entity_type: "client", + const token = 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9'; + const old_secret = '12345678'; + const new_secret = '87654321'; + const tokens = { + 'access_token': 'eyJhbGciOiJIUzUxMiIsInR5cCI6IJhZG1pbkBleGFtcGxlLmNvbSIsA', + 'refresh_token': 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTc3OD', + 'access_type': 'Bearer'}; + const users = [ + { + "name":'sekhmet', + "id": '886b4266-77d1-4258-abae-2931fb4f16de', + "credentials": { + "identity": 'sekhmet@email.com' + } + }, + { + "name":'bastet', + "id": '886b4266-77d1-4258-abae-2931fb4f16de', + "credentials": { + "identity": 'bastet@email.com' + } + }, + ]; + const member_id = '886b4266-77d1-4258-abae-2931fb4f16de'; + const memberships = [ + {"name":"vhagar"}, + {"name":"balerion"}, + ]; + const group_id = '886b4266-77d1-4258-abae-2931fb4f16de'; + const action= 'm_read'; + const entity_type = 'client'; + const query_params = { + "offset": 0, + "limit": 10, }; - const group_id = "886b4266-77d1-4258-abae-2931fb4f16de"; - const action = "m_read"; - const entity_type = "client"; + test("Create should create a user and return success", () => { axios.request.mockResolvedValueOnce({ data: user }); @@ -52,7 +72,7 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); expect(result).toEqual(user); }); @@ -77,17 +97,15 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); expect(result.error.status).toBe(1); - expect(result.error.message).toBe( - "Failed due to using an existing identity.", - ); + expect(result.error.message).toBe('Entity already exists.'); }); }); - test("Login should create a token for a user and return success", () => { - axios.request.mockResolvedValueOnce({ data: user }); + test('Login should create a token for a user and return success', () => { + axios.request.mockResolvedValueOnce({ data: tokens }); const expectedUrl = `${users_url}/users/tokens/issue`; @@ -100,16 +118,16 @@ describe("Users", () => { headers: { "Content-Type": "application/json", }, - data: JSON.stringify(user), + data: user, }); - expect(result).toEqual(user); + expect(result).toEqual(tokens); }); }); test("Login should handle a conflict error", () => { const errorResponse = { response: { - status: 401, + status: 404, }, }; axios.request.mockRejectedValueOnce(errorResponse); @@ -125,9 +143,9 @@ describe("Users", () => { headers: { "Content-Type": "application/json", }, - data: JSON.stringify(user), + data: user, }); - console.log(result); + expect(result).toBe('A non-existent entity request.'); }); }); @@ -162,17 +180,62 @@ describe("Users", () => { const expectedUrl = `${users_url}/users/${user_id}`; const sdk = new mfsdk({ usersUrl: users_url }); - return sdk.users.Get(user_id, token).then((result) => { + return sdk.users.Get(user_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, method: 'get', maxBodyLength: 2000, headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}` + }, + }); + expect(result).toBe("Missing or invalid access token provided."); + }); + }); + + test('GetAll should get a list of users and return success', () => { + axios.request.mockResolvedValueOnce({ data: users }); + + const expectedUrl = `${users_url}/users?${new URLSearchParams(query_params).toString()}`; + + const sdk = new mfsdk({ usersUrl: users_url }); + return sdk.users.GetAll(query_params, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + url: expectedUrl, + method: 'get', + maxBodyLength: 2000, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + }); + expect(result).toEqual(users); + }); + }); + + test('GetAll should handle a conflict error', () => { + const errorResponse = { + response: { + status: 401, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + const expectedUrl = `${users_url}/users?${new URLSearchParams(query_params).toString()}`; + + const sdk = new mfsdk({ usersUrl: users_url }); + return sdk.users.GetAll(query_params, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + url: expectedUrl, + method: 'get', + maxBodyLength: 2000, + headers: { + 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, }); - console.log(result); + expect(result).toBe("Missing or invalid access token provided."); }); }); @@ -182,7 +245,7 @@ describe("Users", () => { const expectedUrl = `${users_url}/users/${user_id}`; const sdk = new mfsdk({ usersUrl: users_url }); - return sdk.users.Update(user, token).then((result) => { + return sdk.users.Update(user, user_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, method: 'patch', @@ -191,7 +254,7 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); expect(result).toEqual(user); }); @@ -208,7 +271,7 @@ describe("Users", () => { const expectedUrl = `${users_url}/users/${user_id}`; const sdk = new mfsdk({ usersUrl: users_url }); - return sdk.users.Update(user, token).then((result) => { + return sdk.users.Update(user, user_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, method: 'patch', @@ -217,9 +280,9 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); - console.log(result); + expect(result).toBe("Missing or invalid access token provided."); }); }); @@ -229,7 +292,7 @@ describe("Users", () => { const expectedUrl = `${users_url}/users/${user_id}/identity`; const sdk = new mfsdk({ usersUrl: users_url }); - return sdk.users.UpdateUserIdentity(user, token).then((result) => { + return sdk.users.UpdateUserIdentity(user, user_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, method: 'patch', @@ -238,7 +301,7 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); expect(result).toEqual(user); }); @@ -255,7 +318,7 @@ describe("Users", () => { const expectedUrl = `${users_url}/users/${user_id}/identity`; const sdk = new mfsdk({ usersUrl: users_url }); - return sdk.users.UpdateUserIdentity(user, token).then((result) => { + return sdk.users.UpdateUserIdentity(user, user_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, method: 'patch', @@ -264,9 +327,9 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); - console.log(result); + expect(result).toBe("Missing or invalid access token provided."); }); }); @@ -276,7 +339,7 @@ describe("Users", () => { const expectedUrl = `${users_url}/users/${user_id}/tags`; const sdk = new mfsdk({ usersUrl: users_url }); - return sdk.users.UpdateUserTags(user, token).then((result) => { + return sdk.users.UpdateUserTags(user, user_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, method: 'patch', @@ -285,7 +348,7 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); expect(result).toEqual(user); }); @@ -302,7 +365,7 @@ describe("Users", () => { const expectedUrl = `${users_url}/users/${user_id}/tags`; const sdk = new mfsdk({ usersUrl: users_url }); - return sdk.users.UpdateUserTags(user, token).then((result) => { + return sdk.users.UpdateUserTags(user, user_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, method: 'patch', @@ -311,9 +374,9 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); - console.log(result); + expect(result).toBe("Missing or invalid access token provided."); }); }); @@ -323,7 +386,7 @@ describe("Users", () => { const expectedUrl = `${users_url}/users/${user_id}/owner`; const sdk = new mfsdk({ usersUrl: users_url }); - return sdk.users.UpdateUserOwner(user, token).then((result) => { + return sdk.users.UpdateUserOwner(user, user_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, method: 'patch', @@ -332,7 +395,7 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); expect(result).toEqual(user); }); @@ -349,7 +412,7 @@ describe("Users", () => { const expectedUrl = `${users_url}/users/${user_id}/owner`; const sdk = new mfsdk({ usersUrl: users_url }); - return sdk.users.UpdateUserOwner(user, token).then((result) => { + return sdk.users.UpdateUserOwner(user, user_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, method: 'patch', @@ -358,9 +421,9 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); - console.log(result); + expect(result).toBe("Missing or invalid access token provided."); }); }); @@ -383,8 +446,10 @@ describe("Users", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(secret), + data: secret, }); + expect(result).toEqual(user); + }); }); test("UpdateUserPassword should handle a conflict error", () => { @@ -410,8 +475,10 @@ describe("Users", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(secret), + data: secret, }); + expect(result).toBe("Missing or invalid access token provided."); + }); }); test("Disable should disable user and return success", () => { @@ -420,7 +487,7 @@ describe("Users", () => { const expectedUrl = `${users_url}/users/${user_id}/disable`; const sdk = new mfsdk({ usersUrl: users_url }); - return sdk.users.Disable(user, token).then((result) => { + return sdk.users.Disable(user, user_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, method: 'post', @@ -429,7 +496,7 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); expect(result).toEqual(user); }); @@ -446,7 +513,7 @@ describe("Users", () => { const expectedUrl = `${users_url}/users/${user_id}/disable`; const sdk = new mfsdk({ usersUrl: users_url }); - return sdk.users.Disable(user, token).then((result) => { + return sdk.users.Disable(user, user_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, method: 'post', @@ -455,9 +522,9 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); - console.log(result); + expect(result).toBe("Missing or invalid access token provided."); }); }); @@ -467,7 +534,7 @@ describe("Users", () => { const expectedUrl = `${users_url}/users/${user_id}/enable`; const sdk = new mfsdk({ usersUrl: users_url }); - return sdk.users.Enable(user, token).then((result) => { + return sdk.users.Enable(user,user_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, method: 'post', @@ -476,7 +543,7 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); expect(result).toEqual(user); }); @@ -493,7 +560,7 @@ describe("Users", () => { const expectedUrl = `${users_url}/users/${user_id}/enable`; const sdk = new mfsdk({ usersUrl: users_url }); - return sdk.users.Enable(user, token).then((result) => { + return sdk.users.Enable(user, user_id, token).then(result => { expect(axios.request).toHaveBeenCalledWith({ url: expectedUrl, method: 'post', @@ -502,9 +569,9 @@ describe("Users", () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - data: JSON.stringify(user), + data: user, }); - console.log(result); + expect(result).toBe("Missing or invalid access token provided."); }); }); @@ -529,8 +596,10 @@ describe("Users", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(access_request), + data: access_request, }); + expect(result).toEqual(true); + }); }); test("Authorise User should handle a conflict error", () => { @@ -558,7 +627,54 @@ describe("Users", () => { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, - data: JSON.stringify(access_request), + data: access_request, + }); + expect(result).toBe(false); + }); + }); + + test('Memberships should get a list of groups associated with users and return success', () => { + axios.request.mockResolvedValueOnce({ data: memberships }); + + const expectedUrl = `${users_url}/users/${member_id}/memberships?${new URLSearchParams(query_params).toString()}`; + + const sdk = new mfsdk({ usersUrl: users_url }); + return sdk.users.Memberships(member_id, query_params, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + url: expectedUrl, + method: 'get', + maxBodyLength: 2000, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, }); + expect(result).toEqual(memberships); + }); + }); + + test('Memberships should handle a conflict error', () => { + const errorResponse = { + response: { + status: 401, + }, + }; + axios.request.mockRejectedValueOnce(errorResponse); + + const expectedUrl = `${users_url}/users/${member_id}/memberships?${new URLSearchParams(query_params).toString()}`; + + const sdk = new mfsdk({ usersUrl: users_url }); + return sdk.users.Memberships(member_id, query_params, token).then(result => { + expect(axios.request).toHaveBeenCalledWith({ + url: expectedUrl, + method: 'get', + maxBodyLength: 2000, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + }); + expect(result).toBe("Missing or invalid access token provided."); + }); }); });