Skip to content

Commit

Permalink
feat: k1ch/ introduce POST:/clients/{client_id}/permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
k1ch committed Oct 31, 2024
1 parent 63dd5c4 commit b87c64c
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 2 deletions.
39 changes: 38 additions & 1 deletion database/layer/admin-permission.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,53 @@ const getPermissionsByRoleKey = async (roleKey) => {
return await usherDb('permissions')
.join('rolepermissions', 'permissions.key', '=', 'rolepermissions.permissionkey')
.where({ 'rolepermissions.rolekey': roleKey })
.select('permissions.*');
.select('permissions.*')
} catch (err) {
throw pgErrorHandler(err)
}
}

/**
* Insert a new permission
*
* @param {Object} permissionObject - The data for the new permission
* @param {string} permissionObject.name - The name of permission
* @param {number} permissionObject.clientkey - A valid client key
* @param {string} permissionObject.description - A description of the permission
* @returns {Promise<Object>} - A promise that resolves to the inserted permission object
*/
const insertPermission = async (permissionObject) => {
try {
const [permission] = await usherDb('permissions').insert(permissionObject).returning('*')
return permission
} catch (err) {
throw pgErrorHandler(err);
}
}

/**
* Get permissions by name and clientKey
*
* @param {string} name - The name of the permission
* @param {number} clientKey - The client key
* @returns {Promise<Array<Object>>} - A promise that resolves to an array of permissions
*/
const getPermissionsByNameClientKey = async (name, clientKey) => {
try {
const permissions = await usherDb('permissions')
.where({ name, clientkey: clientKey })
return permissions
} catch (err) {
throw pgErrorHandler(err)
}
}

module.exports = {
insertPermissionByClientId,
updatePermissionByPermissionname,
deletePermissionByPermissionname,
getPermission,
getPermissionsByRoleKey,
insertPermission,
getPermissionsByNameClientKey,
}
32 changes: 32 additions & 0 deletions server/src/api_endpoints/clients/permissions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const createError = require('http-errors')
const dbAdminPermission = require('database/layer/admin-permission')
const { checkClientExists, checkPermissionNameUniqueness } = require('./utils')

/**
* HTTP Request handler
* Create a permission
*
* @param {Object} req - The request object
* @param {Object} res - The response object to send 201 statusCode and the cerated permission on success
* @param {Function} next - The next middleware function
* @returns {Promise<void>} - A Promise that resolves to void when the permission is created
*/
const createPermission = async (req, res, next) => {
try {
const { client_id: clientId } = req.params
const client = await checkClientExists(clientId)
const payload = {
...req.body,
clientkey: client.key,
}
await checkPermissionNameUniqueness(payload)
const permission = await dbAdminPermission.insertPermission(payload)
res.status(201).send(permission)
} catch ({ httpStatusCode = 500, message }) {
return next(createError(httpStatusCode, { message }))
}
}

module.exports = {
createPermission,
}
29 changes: 28 additions & 1 deletion server/src/api_endpoints/clients/utils.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
const dbAdminRole = require('database/layer/admin-client')
const dbAdminPermission = require('database/layer/admin-permission')

const checkClientExists = async (clientId) => {
try {
await dbAdminRole.getClient(clientId);
return await dbAdminRole.getClient(clientId);
} catch {
throw {
httpStatusCode: 404,
Expand All @@ -11,6 +12,32 @@ const checkClientExists = async (clientId) => {
}
}

/**
* Checks the uniqueness of a permission name for a given client key.
*
* This function queries the database to retrieve permissions by name and client key.
* If any permissions are found, it throws an error indicating the name is already taken.
*
* @async
* @function checkPermissionNameUniqueness
* @param {Object} params - The parameters for checking uniqueness.
* @param {string} params.name - The name of the permission to check.
* @param {string} params.clientkey - The client key associated with the permission.
* @throws {Object} Throws an error with HTTP status code 409 if the permission name is not unique.
* @throws {number} error.httpStatusCode - The HTTP status code indicating conflict (409).
* @throws {string} error.message - The error message indicating the permission name is taken.
*/
const checkPermissionNameUniqueness = async ({ name, clientkey: clientKey }) => {
const permissions = await dbAdminPermission.getPermissionsByNameClientKey(name, clientKey);
if (permissions?.length) {
throw {
httpStatusCode: 409,
message: 'The permission name is taken!'
};
}
};

module.exports = {
checkClientExists,
checkPermissionNameUniqueness,
}
45 changes: 45 additions & 0 deletions server/the-usher-openapi-spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,50 @@ paths:
404:
$ref: '#/components/responses/NotFound'

/clients/{client_id}/permissions:
parameters:
- $ref: '#/components/parameters/clientIdPathParam'
post:
'x-swagger-router-controller': 'clients/permissions'
summary: Create a new permission for the given client
operationId: createPermission
tags:
- Client Admin APIs
security:
- bearerAdminAuth: []
- bearerClientAdminAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
$ref: '#/components/schemas/EntityNameDef'
description:
$ref: '#/components/schemas/EntityDescriptionDef'
required:
- name
additionalProperties: false
responses:
201:
description: Returns the created permission
content:
application/json:
schema:
$ref: "#/components/schemas/PermissionObject"
400:
$ref: '#/components/responses/BadRequest'
404:
$ref: '#/components/responses/NotFound'
409:
$ref: '#/components/responses/Conflict'
500:
$ref: '#/components/responses/InternalError'
503:
$ref: '#/components/responses/ServiceUnavailableError'

/sessions:
delete:
operationId: invalidateSession
Expand Down Expand Up @@ -1269,6 +1313,7 @@ components:
$ref: '#/components/schemas/EntityNameDef'
description:
$ref: '#/components/schemas/EntityDescriptionDef'
nullable: true
created_at:
type: string
format: date-time
Expand Down

0 comments on commit b87c64c

Please sign in to comment.