ciam-client
Advanced tools
Comparing version
import axios from 'axios'; | ||
import 'ciam-commons'; | ||
const idReg = /[a-f0-9]{24}/; | ||
import { Check } from 'ciam-commons'; | ||
function cast(obj) { | ||
@@ -8,6 +7,3 @@ return obj ? obj : undefined; | ||
class Ciam { | ||
token; | ||
baseUrl; | ||
api; | ||
constructor(token, baseUrl = 'https://ciam.centralmind.net') { | ||
constructor(token, baseUrl) { | ||
this.token = token; | ||
@@ -31,3 +27,3 @@ this.baseUrl = baseUrl; | ||
if (message.startsWith('Missing permissions')) { | ||
return Promise.reject('message'); | ||
return Promise.reject(message); | ||
} | ||
@@ -45,40 +41,208 @@ else { | ||
} | ||
async getUser(id) { | ||
Check.id(id); | ||
return cast(await this.api.get(`/user/${id}`)); | ||
/** | ||
* Get a role by its roleId | ||
* | ||
* @permissions `ciam.role.get.ROLE_ID` | ||
* @param roleId the id of the role to get | ||
* @returns A {@link Model.Role}, or undefined | ||
* @throws if {@link roleId} is not a valid objectId | ||
*/ | ||
async getRole(roleId) { | ||
Check.objectId(roleId); | ||
return cast(await this.api.get(`/role/${roleId}`)); | ||
} | ||
async deleteUser(id) { | ||
Check.id(id); | ||
return cast(await this.api.delete(`/role/${id}`)); | ||
/** | ||
* Delete a role by its roleId | ||
* | ||
* @permissions `ciam.role.delete.ROLE_ID` | ||
* @param roleId the id of the role to delete | ||
* @returns the deleted {@link Model.Role}, or undefined | ||
* @throws if {@link roleId} is not a valid objectId | ||
*/ | ||
async deleteRole(roleId) { | ||
Check.objectId(roleId); | ||
return cast(await this.api.delete(`/role/${roleId}`)); | ||
} | ||
async createUser(name, roles, permissions) { | ||
/** | ||
* Create a new role | ||
* | ||
* @permissions `ciam.role.create` | ||
* @param name the name of this role | ||
* @param description the description of this role | ||
* @param permissions the permissions of this role | ||
* @returns the new {@link Model.Role}, or undefined | ||
* @throws if {@link name} is empty | ||
* @throws if {@link description} is empty | ||
* @throws if {@link permissions} contains invalid flags | ||
*/ | ||
async createRole(name, description, permissions) { | ||
Check.notEmpty(name, 'name'); | ||
Check.notEmpty(description, 'description'); | ||
permissions.forEach(f => Check.flag(f)); | ||
const obj = { | ||
name: name, | ||
roles: roles, | ||
description: description, | ||
permissions: permissions | ||
}; | ||
return cast(await this.api.post('/user/create', obj)); | ||
return cast(await this.api.post('/role/create', obj)); | ||
} | ||
async listUsers() { | ||
return cast(await this.api.get('/user/list')); | ||
/** | ||
* Update an existing role | ||
* | ||
* @permissions `ciam.role.update.ROLE_ID` | ||
* @param role the role to update, with its fields modified to the desired values. Empty fields remain unchanged | ||
* @returns the updated {@link Model.Role}, or undefined | ||
* @throws if {@link role}._id is not a valid objectId | ||
* @throws if {@link role}.name exists and is empty | ||
* @throws if {@link role}.description exists and is empty | ||
* @throws if {@link role}.permissions contains invalid stict permission flags | ||
*/ | ||
async updateRole(role) { | ||
Check.objectId(role._id); | ||
role.permissions?.forEach(p => Check.flag(p)); | ||
if (role.name) | ||
Check.notEmpty(role.name, 'role.name'); | ||
if (role.description) | ||
Check.notEmpty(role.name, 'role.description'); | ||
return cast(await this.api.post('/role/update', role)); | ||
} | ||
async getRole(id) { | ||
Check.id(id); | ||
return cast(await this.api.get(`/role/${id}`)); | ||
/** | ||
* List roles | ||
* | ||
* @permissions `ciam.role.list` | ||
* @param skip number of roles to skip | ||
* @param limit maximum number of roles to return in one request | ||
* @returns an array of {@link Model.Role}, or undefined | ||
* @throws if {@link skip} is less than 0 | ||
* @throws if {@link limit} is not in the range 1..100 | ||
*/ | ||
async listRoles(skip = 0, limit = 100) { | ||
Check.min(skip, 0, 'skip'); | ||
Check.inRange(limit, 1, 100, 'limit'); | ||
return cast(await this.api.get(`/role/list?skip=${skip}&limit=${limit}`)); | ||
} | ||
async deleteRole(id) { | ||
Check.id(id); | ||
return cast(await this.api.delete(`/role/${id}`)); | ||
} | ||
async createRole(name, description, permissions) { | ||
/** | ||
* Create a new user | ||
* | ||
* @permissions `ciam.user.create` | ||
* @param name the name of this user | ||
* @param roles the roles of this user | ||
* @param permissions the permissions of this user | ||
* @param discord the discord object of this user | ||
* @returns the newly created {@link Model.User}, or unefined | ||
* @throws if {@link name} is empty | ||
* @throws if {@link discord}.id is not a valid discord id | ||
* @throws if {@link roles} contain invalid objectIds | ||
* @throws if {@link permissions} contains invalid flags | ||
*/ | ||
async createUser(name, roles, permissions, discord) { | ||
Check.notEmpty(name, 'name'); | ||
Check.notEmpty(description, 'description'); | ||
if (discord) | ||
Check.discordId(discord.id, 'discord.id'); | ||
roles.forEach(r => Check.objectId(r)); | ||
permissions.forEach(p => Check.flag(p)); | ||
const obj = { | ||
name: name, | ||
description: description, | ||
permissions: permissions | ||
roles: roles, | ||
permissions: permissions, | ||
discord: discord | ||
}; | ||
return cast(await this.api.post('/role/create', obj)); | ||
return cast(await this.api.post('/user/create', obj)); | ||
} | ||
/** | ||
* Get a user by their id | ||
* | ||
* @permissins `ciam.user.get.USER_ID` | ||
* @param userId the id of the user to get | ||
* @returns the {@link Model.User}, or undefined | ||
* @throws if {@link userId} is not a valid objectId | ||
*/ | ||
async getUser(userId) { | ||
Check.objectId(userId); | ||
return cast(await this.api.get(`/user/${userId}`)); | ||
} | ||
/** | ||
* Delete a user by their id | ||
* | ||
* @permissions `ciam.user.delete.USER_ID` | ||
* @param userId id of the user to delete | ||
* @returns the deleted {@link Model.User}, or undefined | ||
* @throws if {@link userId} is not a valid objectId | ||
*/ | ||
async deleteUser(userId) { | ||
Check.objectId(userId); | ||
return cast(await this.api.delete(`/role/${userId}`)); | ||
} | ||
/** | ||
* Update a user | ||
* | ||
* @permissions `ciam.user.update.USER_ID` | ||
* @param user the user to update, with their fields modified to the desired values. Empty fields remain unchanged | ||
* @returns the updated {@link Model.User}, or undefined | ||
* @throws if {@link user}._id is not a valid objectId | ||
* @throws if {@link user}.name exists and is empty | ||
* @throws if {@link user}.discord.id is not a valid discord id | ||
* @throws if {@link user}.roles contain invalid objectIds | ||
* @throws if {@link user}.permissions contains invalid flags | ||
*/ | ||
async updateUser(user) { | ||
Check.objectId(user._id); | ||
if (user.discord) | ||
Check.discordId(user.discord?.id, 'discord.id'); | ||
user.roles?.forEach(r => Check.objectId(r)); | ||
user.permissions?.forEach(p => Check.flag(p)); | ||
if (user.name) | ||
Check.notEmpty(user.name, 'user.name'); | ||
return cast(await this.api.post('/user/update')); | ||
} | ||
/** | ||
* Check if the current token is valid | ||
* | ||
* @returns true if the current ciam token is valid | ||
*/ | ||
async valid() { | ||
return this.api.get('/user/valid') | ||
.then(res => true) | ||
.catch(err => false); | ||
} | ||
// TODO: not yet implemented on backend | ||
async listUsers() { | ||
return cast(await this.api.get('/user/list')); | ||
} | ||
/** | ||
* Get a permission by its flag | ||
* | ||
* @permissions `ciam.permission.get.FLAG` | ||
* @param flag the flag to get permissions for | ||
* @returns the {@link Model.Permission} for this flag, or undefined | ||
* @throws if {@link flag} is not a valid strict flag | ||
*/ | ||
async getPermission(flag) { | ||
Check.strictFlag(flag); | ||
return cast(await this.api.get(`/permission/${flag}`)); | ||
} | ||
/** | ||
* Delete a permission by its flag | ||
* | ||
* @permissions `ciam.permission.delete.FLAG` | ||
* @param flag the flag to delete | ||
* @returns the deleted {@link Model.Permission}, or undefined | ||
* @throws if {@link flag} is not a valid strict flag | ||
*/ | ||
async deletePermission(flag) { | ||
Check.strictFlag(flag); | ||
return cast(await this.api.delete(`/permission/${flag}`)); | ||
} | ||
/** | ||
* Create a new permission | ||
* | ||
* @permissions `ciam.permission.create.FLAG` | ||
* @param name the name of this permission | ||
* @param description the description of this permission | ||
* @param flag the flag of this permission | ||
* @returns the new {@link Model.Permission}, or undefined | ||
* @throws if {@link name} is empty | ||
* @throws if {@link description} is empty | ||
* @throws if {@link flag} is not a valid strict flag | ||
*/ | ||
async createPermission(name, description, flag) { | ||
@@ -95,6 +259,84 @@ Check.notEmpty(name, 'name'); | ||
} | ||
/** | ||
* Update a permission | ||
* | ||
* @permissions `ciam.permission.update.FLAG` | ||
* @param permission the permission to update, with its fields modified to the desired values. Empty fields remain unchanged | ||
* @returns the updated {@link Model.Permission}, or undefined | ||
* @throws if {@link permission}.flag is not a valid strict flag | ||
* @throws if {@link permission}.name exists and is empty | ||
* @throws if {@link permission}.description exists and is empty | ||
*/ | ||
async updatePermission(permission) { | ||
Check.strictFlag(permission.flag); | ||
if (permission.name) | ||
Check.notEmpty(permission.name, 'permission.description'); | ||
if (permission.description) | ||
Check.notEmpty(permission.description, 'permission.description'); | ||
return cast(await this.api.post('/permission/update', permission)); | ||
} | ||
/** | ||
* Get a list of your own permissions | ||
* | ||
* @permissions `ciam.permission.me` | ||
* @param skip number of permissions to skip | ||
* @param limit maximum number of permissions to return | ||
* @returns an array of {@link Model.Permission}, or undefined | ||
* @throws if {@link skip} is less than 0 | ||
* @throws if {@link limit} is not in the range 1..100 | ||
*/ | ||
async ownPermissions(skip = 0, limit = 100) { | ||
Check.min(skip, 0, 'skip'); | ||
Check.inRange(limit, 1, 100, 'limit'); | ||
return cast(await this.api.get(`/permission/me?skip=${skip}&limit=${limit}`)); | ||
} | ||
/** | ||
* Get a list of permissions | ||
* | ||
* @permissions `ciam.permission.list` | ||
* @param skip number of permissions to skip | ||
* @param limit maximum number of permissions to return | ||
* @returns an array of {@link Model.Permission}, or undefined | ||
* @throws if {@link skip} is less than 0 | ||
* @throws if {@link limit} is not in the range 1..100 | ||
*/ | ||
async listPermissions(skip = 0, limit = 100) { | ||
Check.min(skip, 0, 'skip'); | ||
Check.inRange(limit, 1, 100, 'limit'); | ||
return cast(await this.api.get(`/permission/list?skip=${skip}&limit=${limit}`)); | ||
} | ||
/** | ||
* Check a users, or roles permissions | ||
* | ||
* @permissions [...`ciam.permission.has.EACH_REQUIRED_FLAG`] | ||
* @param type the type of {@link id} | ||
* @param id the id of the subject to check permissions for | ||
* @param required the required permission flags | ||
* @param additional additional flags to give to the subject temporarily | ||
* @param includeMissing if the response should include the missing permissions | ||
* @returns a {@link Model.CheckResult}, or undefined | ||
* @throws if {@link type} is not one of `user`, `role`, or `discordUser` | ||
* @throws if {@link type} is `user` or `role` and {@link id} is not a valid objectId | ||
* @throws if {@link type} is `discordUser` and {@link id} is not a valid discordId | ||
* @throws if {@link required} contains invalid flags | ||
* @throws if {@link additional} contains invalid flags | ||
*/ | ||
async checkPermissions(type, id, required, additional = [], includeMissing = false) { | ||
Check.oneOf(type, ['user', 'role', 'discordUser'], 'type'); | ||
if (type == 'user' || type == 'role') | ||
Check.objectId(id, 'id'); | ||
else if (type == 'discordUser') | ||
Check.discordId(id); | ||
Check.notEmpty(required, 'required'); | ||
required.forEach(f => Check.flag(f)); | ||
additional?.forEach(f => Check.flag(f)); | ||
return cast(await this.api.post('/permission/has', { | ||
type: type, | ||
id: id, | ||
required: required, | ||
additional: additional, | ||
includeMissing: includeMissing | ||
})); | ||
} | ||
} | ||
export { Ciam }; |
{ | ||
"name": "ciam-client", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "type": "module", |
{ | ||
"compilerOptions": { | ||
"target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ | ||
"moduleResolution": "node", | ||
"module": "esnext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ | ||
"outDir": "dist", /* Redirect output structure to the directory. */ | ||
"strict": true, /* Enable all strict type-checking options. */ | ||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ | ||
"skipLibCheck": true, /* Skip type checking of declaration files. */ | ||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ | ||
} | ||
"compilerOptions": { | ||
"target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ | ||
"moduleResolution": "node", | ||
"module": "esnext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ | ||
"outDir": "dist", /* Redirect output structure to the directory. */ | ||
"strict": true, /* Enable all strict type-checking options. */ | ||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ | ||
"skipLibCheck": true, /* Skip type checking of declaration files. */ | ||
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */ | ||
"declaration": true | ||
} | ||
} |
37003
106.03%893
98.44%