diff --git a/docs/api/accesscontrol.md b/docs/api/accesscontrol.md index 757e35cc..269f37ad 100644 --- a/docs/api/accesscontrol.md +++ b/docs/api/accesscontrol.md @@ -63,6 +63,16 @@ Sets the API token for the object, to request a token create an account in http | atokenpi | string | The API token to use to connect with TerminusX | +## setApiKey +##### accessControl.setApiKey(atokenpi) +Sets the API token for the object, to request a token create an account in https://terminusdb.com/ + + +| Param | Type | Description | +| --- | --- | --- | +| atokenpi | string | The API token to use to connect with TerminusX | + + ## getAPIUrl ##### accessControl.getAPIUrl(cloudAPIUrl) ⇒ string Get a API url from cloudAPIUrl @@ -80,10 +90,35 @@ Get all the system database roles types. **Returns**: Promise - A promise that returns the call response object, or an Error if rejected. +## getAllOrganizations +##### accessControl.getAllOrganizations() ⇒ Promise +This end point works only in basic authentication admin user +Get all the system organizations list + +**Returns**: Promise - A promise that returns the call response object, or an Error if rejected. + ## createOrganization ##### accessControl.createOrganization(orgName) ⇒ Promise -Any user can create their own organization. -IMPORTANT This does not work with the API-TOKEN. +This works only in the local database +TerminusX - Any user can create their own organization. - +TerminusX - IMPORTANT This does not work with the API-TOKEN. + +**Returns**: Promise - A promise that returns the call response object, or an Error if rejected. + +| Param | Type | Description | +| --- | --- | --- | +| orgName | string | The organization name to create | + +**Example** +```javascript +accessControl.createOrganization("my_org_name").then(result=>{ + console.log(result) +}) +``` + +## deleteOrganization +##### accessControl.deleteOrganization(orgName) ⇒ Promise +This api works only in the local installation **Returns**: Promise - A promise that returns the call response object, or an Error if rejected. @@ -271,6 +306,45 @@ accessControl.getTeamUserRole().then(result=>{ {"userRole":"Role/admin"} ``` +## getTeamUserRoles +##### accessControl.getTeamUserRoles([userName], [orgName]) ⇒ Promise +Get the user role for a given organization or the default organization, + +**Returns**: Promise - A promise that returns the call response object, or an Error if rejected. + +| Param | Type | Description | +| --- | --- | --- | +| [userName] | string | The organization name. | +| [orgName] | string | The organization name. | + +**Example** +```javascript +accessControl.getTeamUserRole("myUser").then(result=>{ + console.log(result) +}) + +//response object example +{ + "@id": "User/myUser", + "capability": [ + { + "@id":"Capability/server_access", + "@type":"Capability", + "role": [{ + "@id":"Role/reader", + "@type":"Role", + "action": [ + "instance_read_access", + ], + "name":"reader" + }], + "scope":"Organization/myteam" + } + ], + "name": "myUser" +} +``` + ## removeUserFromOrg ##### accessControl.removeUserFromOrg(userId, [orgName]) ⇒ Promise Remove an user from an organization, only an admin user can remove an user from an organization @@ -427,3 +501,106 @@ accessControl.deleteAccessRequest("djjdshhsuuwewueueuiHYHYYW.......").then(resul console.log(result) }) ``` + +## createRole +##### accessControl.createRole([name], [actions]) ⇒ Promise +Create a new role in the system database, (this api is enabled only in the local installation) + +**Returns**: Promise - A promise that returns the call response object, or an Error if rejected. + +| Param | Type | Description | +| --- | --- | --- | +| [name] | string | The role name. | +| [actions] | array | A list of actions | + +**Example** +```javascript +accessControl.createRole("Reader",[ACTIONS.INSTANCE_READ_ACCESS]).then(result=>{ + console.log(result) +}) +``` + +## deleteRole +##### accessControl.deleteRole([name]) ⇒ Promise +Delete role in the system database, (this api is enabled only in the local installation) + +**Returns**: Promise - A promise that returns the call response object, or an Error if rejected. + +| Param | Type | Description | +| --- | --- | --- | +| [name] | string | The role name. | + +**Example** +```javascript +accessControl.deleteRole("Reader").then(result=>{ + console.log(result) +}) +``` + +## getAllUsers +##### accessControl.getAllUsers() ⇒ Promise +Return the list of all the users (this api is enabled only in the local installation) + +**Returns**: Promise - A promise that returns the call response object, or an Error if rejected. +**Example** +```javascript +accessControl.getAllUsers().then(result=>{ + console.log(result) +}) +``` + +## deleteUser +##### accessControl.deleteUser(userId) ⇒ Promise +Remove the user from the system database (this api is enabled only in the local installation) + +**Returns**: Promise - A promise that returns the call response object, or an Error if rejected. + +| Param | Type | Description | +| --- | --- | --- | +| userId | string | the document user id | + +**Example** +```javascript +accessControl.deleteUser(userId).then(result=>{ + console.log(result) +}) +``` + +## createUser +##### accessControl.createUser(name, [password]) ⇒ Promise +Add the user into the system database (this api is enabled only in the local installation) + +**Returns**: Promise - A promise that returns the call response object, or an Error if rejected. + +| Param | Type | Description | +| --- | --- | --- | +| name | string | the user name | +| [password] | string | you need the password for basic authentication | + +**Example** +```javascript +accessControl.deleteUser(userId).then(result=>{ + console.log(result) +}) +``` + +## manageCapability +##### accessControl.manageCapability(userId, resourceId, rolesArr, operation) ⇒ Promise +Grant/Revoke Capability (this api is enabled only in the local installation) + +**Returns**: Promise - A promise that returns the call response object, or an Error if rejected. + +| Param | Type | Description | +| --- | --- | --- | +| userId | string | the document user id | +| resourceId | string | the resource id (database or team) | +| rolesArr | array | the roles list | +| operation | string | grant/revoke operation | + +**Example** +```javascript +{ "operation" : "grant", + "scope" : "Organization/myteam", + "user" : "User/myUser", + "roles" : ["Role/reader"] } +``` diff --git a/lib/accessControl.js b/lib/accessControl.js index d21551be..ff016d29 100644 --- a/lib/accessControl.js +++ b/lib/accessControl.js @@ -43,8 +43,10 @@ function AccessControl(cloudAPIUrl, params) { this.setJwtToken(params.jwt); } else if (params.token) { this.setApiToken(params.token); + } else if (params.key) { + this.setApiKey(params.key); + this.user = params.user; } - this.defaultOrganization = this.getDefaultOrganization(params); } @@ -68,7 +70,7 @@ AccessControl.prototype.setJwtToken = function (jwt) { throw new Error('TerminusX Access token required'); } - this.apiJwtToken = jwt; + this.apiKey = jwt; this.apiType = 'jwt'; }; @@ -81,10 +83,23 @@ AccessControl.prototype.setApiToken = function (token) { throw new Error('TerminusX Access token required'); } - this.apiToken = token; + this.apiKey = token; this.apiType = 'apikey'; }; +/** + * Sets the API token for the object, to request a token create an account in https://terminusdb.com/ + * @param {string} atokenpi - The API token to use to connect with TerminusX + */ +AccessControl.prototype.setApiKey = function (key) { + if (!key) { + throw new Error('TerminusDB bacis authentication key required'); + } + + this.apiKey = key; + this.apiType = 'basic'; +}; + /** * Get a API url from cloudAPIUrl * @param {string} cloudAPIUrl - The base url for cloud @@ -112,14 +127,11 @@ AccessControl.prototype.dispatch = function (requestUrl, action, payload) { ), ); } - - const apiToken = this.apiJwtToken || this.apiToken; - return DispatchRequest( requestUrl, action, payload, - { type: this.apiType, key: apiToken }, + { type: this.apiType, key: this.apiKey, user: this.user }, ); }; @@ -132,8 +144,19 @@ AccessControl.prototype.getAccessRoles = function () { }; /** - * Any user can create their own organization. - * IMPORTANT This does not work with the API-TOKEN. + * This end point works only in basic authentication admin user + * Get all the system organizations list + * @return {Promise} A promise that returns the call response object, or an Error if rejected. + */ + +AccessControl.prototype.getAllOrganizations = function () { + return this.dispatch(`${this.baseURL}/organizations`, CONST.GET); +}; + +/** + * This works only in the local database + * TerminusX - Any user can create their own organization. - + * TerminusX - IMPORTANT This does not work with the API-TOKEN. * @param {string} orgName - The organization name to create * @return {Promise} A promise that returns the call response object, or an Error if rejected. * @example @@ -142,20 +165,21 @@ AccessControl.prototype.getAccessRoles = function () { * }) */ AccessControl.prototype.createOrganization = function (orgName) { - if (!orgName) { - return Promise.reject( - new Error( - ErrorMessage.getInvalidParameterMessage( - 'POST', - 'Please provide a organization name', - ), - ), - ); - } + // maybe we have to review this + return this.dispatch(`${this.baseURL}/organizations/${UTILS.encodeURISegment(orgName)}`, CONST.POST, {}); +}; - return this.dispatch(`${this.baseURL}/private/organizations`, CONST.POST, { - organization: orgName, - }); +/** + * This api works only in the local installation + * @param {string} orgName - The organization name to create + * @return {Promise} A promise that returns the call response object, or an Error if rejected. + * @example + * accessControl.createOrganization("my_org_name").then(result=>{ + * console.log(result) + * }) + */ +AccessControl.prototype.deleteOrganization = function (orgName) { + return this.dispatch(`${this.baseURL}/organizations/${UTILS.encodeURISegment(orgName)}`, CONST.DELETE); }; /** @@ -433,6 +457,53 @@ AccessControl.prototype.getTeamUserRole = function (orgName) { return this.dispatch(`${this.baseURL}/organizations/${UTILS.encodeURISegment(org)}/role`, CONST.GET); }; +/** + * Get the user role for a given organization or the default organization, + * @param {string} [userName] - The organization name. + * @param {string} [orgName] - The organization name. + * @return {Promise} A promise that returns the call response object, or an Error if rejected. + * @example + * accessControl.getTeamUserRole("myUser").then(result=>{ + * console.log(result) + * }) + * + * //response object example + * { + * "@id": "User/myUser", + * "capability": [ + * { + * "@id":"Capability/server_access", + * "@type":"Capability", + * "role": [{ + * "@id":"Role/reader", + * "@type":"Role", + * "action": [ + * "instance_read_access", + * ], + * "name":"reader" + * }], + * "scope":"Organization/myteam" + * } + * ], + * "name": "myUser" + *} + */ + +AccessControl.prototype.getTeamUserRoles = function (userName, orgName) { + if (!orgName && !this.defaultOrganization) { + return Promise.reject( + new Error( + ErrorMessage.getInvalidParameterMessage( + 'GET', + 'Please provide a organization name', + ), + ), + ); + } + const org = orgName || this.defaultOrganization; + return this.dispatch(`${this.baseURL}/organizations/${UTILS.encodeURISegment(org)}/users/${UTILS.encodeURISegment(userName)}`, CONST.GET); +}; + /** * Remove an user from an organization, only an admin user can remove an user from an organization * @param {string} userId - The id of the user to be removed. (this is the document user's @id) @@ -693,4 +764,100 @@ AccessControl.prototype.deleteAccessRequest = function (acceId, orgName) { return this.dispatch(`${this.baseURL}/organizations/${UTILS.encodeURISegment(org)}/access_requests/${acceId}`, CONST.DELETE); }; +/** + * Create a new role in the system database, (this api is enabled only in the local installation) + * @param {string} [name] - The role name. + * @param {array} [actions] - A list of actions + * @return {Promise} A promise that returns the call response object, or an Error if rejected. + * @example + * accessControl.createRole("Reader",[ACTIONS.INSTANCE_READ_ACCESS]).then(result=>{ + * console.log(result) + * }) + * + */ +AccessControl.prototype.createRole = function (name, actions) { + const payload = { name, action: actions }; + return this.dispatch(`${this.baseURL}/roles`, CONST.POST, payload); +}; + +/** + * Delete role in the system database, (this api is enabled only in the local installation) + * @param {string} [name] - The role name. + * @return {Promise} A promise that returns the call response object, or an Error if rejected. + * @example + * accessControl.deleteRole("Reader").then(result=>{ + * console.log(result) + * }) + * + */ +AccessControl.prototype.deleteRole = function (name) { + return this.dispatch(`${this.baseURL}/roles/${UTILS.encodeURISegment(name)}`, CONST.DELETE); +}; + +/** + * Return the list of all the users (this api is enabled only in the local installation) + * @return {Promise} A promise that returns the call response object, or an Error if rejected. + * @example + * accessControl.getAllUsers().then(result=>{ + * console.log(result) + * }) + * + */ + +AccessControl.prototype.getAllUsers = function () { + return this.dispatch(`${this.baseURL}/users`, CONST.GET); +}; + +/** + * Remove the user from the system database (this api is enabled only in the local installation) + * @param {string} userId - the document user id + * @return {Promise} A promise that returns the call response object, or an Error if rejected. + * @example + * accessControl.deleteUser(userId).then(result=>{ + * console.log(result) + * }) + * + */ + +AccessControl.prototype.deleteUser = function (userId) { + return this.dispatch(`${this.baseURL}/users/${UTILS.encodeURISegment(userId)}`, CONST.DELETE); +}; + +/** + * Add the user into the system database (this api is enabled only in the local installation) + * @param {string} name - the user name + * @param {string} [password] - you need the password for basic authentication + * @return {Promise} A promise that returns the call response object, or an Error if rejected. + * @example + * accessControl.deleteUser(userId).then(result=>{ + * console.log(result) + * }) + * + */ + +AccessControl.prototype.createUser = function (name, password) { + const payload = { name, password }; + return this.dispatch(`${this.baseURL}/users`, CONST.POST, payload); +}; + +/** + * Grant/Revoke Capability (this api is enabled only in the local installation) + * @param {string} userId - the document user id + * @param {string} resourceId - the resource id (database or team) + * @param {array} rolesArr - the roles list + * @param {string} operation - grant/revoke operation + * @return {Promise} A promise that returns the call response object, or an Error if rejected. + * @example + { "operation" : "grant", + "scope" : "Organization/myteam", + "user" : "User/myUser", + "roles" : ["Role/reader"] } + */ +AccessControl.prototype.manageCapability = function (userId, resourceId, rolesArr, operation) { + const payload = { + operation, user: userId, roles: rolesArr, scope: resourceId, + }; + return this.dispatch(`${this.baseURL}/capabilities`, CONST.POST, payload); +}; + module.exports = AccessControl; diff --git a/lib/dispatchRequest.js b/lib/dispatchRequest.js index 7a8af41f..fc30dc3c 100644 --- a/lib/dispatchRequest.js +++ b/lib/dispatchRequest.js @@ -114,9 +114,9 @@ function DispatchRequest(url, action, payload, local_auth, remote_auth = null, c .delete(url, options) .then((response) => (getDataVersion ? getResultWithDataVersion(response) : response.data)) .catch((err) => { - const e = new Error(ErrorMessage.getAPIErrorMessage(url, options, err)); - if (err.response && err.response.data) e.data = err.response.data; - throw e; + // const e = new Error(ErrorMessage.getAPIErrorMessage(url, options, err)); + // if (err.response && err.response.data) e.data = err.response.data; + throw ErrorMessage.apiErrorFormatted(url, options, err); }); } case CONST.HEAD: { @@ -141,11 +141,7 @@ function DispatchRequest(url, action, payload, local_auth, remote_auth = null, c .get(url, options) .then((response) => (getDataVersion ? getResultWithDataVersion(response) : response.data)) .catch((err) => { - const e = new Error(ErrorMessage.getAPIErrorMessage(url, options, err)); - if (err.response && err.response.data) { - e.data = err.response.data; - } - throw e; + throw ErrorMessage.apiErrorFormatted(url, options, err); }); } case CONST.ADD_CSV: diff --git a/lib/errorMessage.js b/lib/errorMessage.js index 22103a06..e706efb1 100644 --- a/lib/errorMessage.js +++ b/lib/errorMessage.js @@ -91,7 +91,15 @@ function parseAPIError(response) { return err; } +function apiErrorFormatted(url, options, err) { + const e = new Error(getAPIErrorMessage(url, options, err)); + if (err.response && err.response.data) e.data = err.response.data; + if (err.response && err.response.status) e.status = err.response.status; + return e; +} + module.exports = { + apiErrorFormatted, getErrorAsMessage, getAPIErrorMessage, getAccessDeniedMessage, diff --git a/lib/query/woqlBuilder.js b/lib/query/woqlBuilder.js index 2d04dea6..7cc0cca7 100644 --- a/lib/query/woqlBuilder.js +++ b/lib/query/woqlBuilder.js @@ -158,39 +158,4 @@ WOQLQuery.prototype.insert = function (id, type, refGraph) { return this.add_triple(id, 'rdf:type', `@schema:${type}`); }; -/** - * @description Creates a pattern matching rule for a quad [Subject, Predicate, Object, Graph] - * or for a triple [Subject, Predicate, Object] - * add extra information about the type of the value object - * @param {string} subject - The IRI of a triple’s subject or a variable - * @param {string} predicate - The IRI of a property or a variable - * @param {string | number | boolean} objValue - an specific value - * @param {string} [graph] - specify a graph type, default is instance schema|instance - */ -WOQLQuery.prototype.value = function (subject, predicate, objValue, graph) { - if (typeof objValue === 'string') { - objValue = this.string(objValue); - } else if (typeof objValue === 'number') { - objValue = this.literal(objValue, 'xsd:decimal'); - } else if (typeof objValue === 'boolean') { - objValue = this.literal(objValue, 'xsd:boolean'); - } - if (graph) { - this.quad(subject, predicate, objValue, graph); - } else { - this.triple(subject, predicate, objValue); - } -}; - -WOQLQuery.prototype.link = function (a, b, c, g) { - if (typeof c === 'string') { - c = this.iri(c); - } - if (g) { - this.quad(a, b, c, g); - } else { - this.triple(a, b, c); - } -}; - module.exports = WOQLQuery; diff --git a/lib/query/woqlQuery.js b/lib/query/woqlQuery.js index 95eba50c..ea545afe 100644 --- a/lib/query/woqlQuery.js +++ b/lib/query/woqlQuery.js @@ -259,6 +259,39 @@ WOQLQuery.prototype.value = function (a, b, c) { return this; }; +/** + * @description Creates a pattern matching rule for a quad [Subject, Predicate, Object, Graph] + * or for a triple [Subject, Predicate, Object] + * add extra information about the type of the value object + * @param {string} subject - The IRI of a triple’s subject or a variable + * @param {string} predicate - The IRI of a property or a variable + * @param {string | number | boolean} objValue - an specific value + * @param {string} [graph] - specify a graph type, default is instance schema|instance + */ +/* WOQLQuery.prototype.value = function (subject, predicate, objValue, graph) { + if (typeof objValue === 'string') { + objValue = this.string(objValue); + } else if (typeof objValue === 'number') { + objValue = this.literal(objValue, 'xsd:decimal'); + } else if (typeof objValue === 'boolean') { + objValue = this.literal(objValue, 'xsd:boolean'); + } + if (graph) { + return this.quad(subject, predicate, objValue, graph); + } + return this.triple(subject, predicate, objValue); +}; + +WOQLQuery.prototype.link = function (a, b, c, g) { + if (typeof c === 'string') { + c = this.iri(c); + } + if (g) { + return this.quad(a, b, c, g); + } + return this.triple(a, b, c); +}; */ + WOQLQuery.prototype.quad = function (a, b, c, g) { if (this.cursor['@type']) this.wrapCursorWithAnd(); const args = this.triple(a, b, c); diff --git a/lib/utils.js b/lib/utils.js index 9e88c073..197de385 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -12,6 +12,26 @@ */ const Utils = {}; +Utils.ACTIONS = { + CREATE_DATABASE: 'create_database', + DELETE_DATABASE: 'delete_database', + SCHEMA_READ_ACCESS: 'schema_read_access', + SCHEMA_WRITE_ACCESS: 'schema_write_access', + INSTANCE_READ_ACCESS: 'instance_read_access', + INSTANCE_WRITE_ACCESS: 'instance_write_access', + COMMIT_READ_ACCESS: 'commit_read_access', + COMMIT_WRITE_ACCESS: 'commit_write_access', + META_READ_ACCESS: 'meta_read_access', + META_WRITE_ACCESS: 'meta_write_access', + CLASS_FRAME: 'class_frame', + BRANCH: 'branch', + CLONE: 'clone', + FETCH: 'fetch', + PUSH: 'push', + REBASE: 'rebase', + /* MANAGE_CAPABILITIES: 'manage_capabilities', */ +}; + // ˆˆˆˆˆ&&**(((()*(*#&#&&#$*#*(#(#(#)#)#)_ // 'Doc%2F%3D%26test' // diff --git a/lib/woqlClient.js b/lib/woqlClient.js index ed9aa17f..dff87e7c 100644 --- a/lib/woqlClient.js +++ b/lib/woqlClient.js @@ -1439,6 +1439,7 @@ WOQLClient.prototype.getPrefixes = function (dbId) { */ WOQLClient.prototype.getUserOrganizations = function () { // this will be change to give back only the organizations list + console.log('this.connectionConfig.userOrganizationsURL()', this.connectionConfig.userOrganizationsURL()); return this.dispatch( CONST.GET, this.connectionConfig.userOrganizationsURL(),