diff --git a/api/public/swagger.yaml b/api/public/swagger.yaml index 4fec97d..fd9aa21 100644 --- a/api/public/swagger.yaml +++ b/api/public/swagger.yaml @@ -473,7 +473,7 @@ components: - setting type: object additionalProperties: false - PermissionPayload: + RegisterPermissionPayload: properties: uri: type: string @@ -497,6 +497,16 @@ components: - principalId type: object additionalProperties: false + UpdatePermissionPayload: + properties: + setting: + type: string + description: 'The indication of whether (and to what extent) access is provided' + example: Grant + required: + - setting + type: object + additionalProperties: false securitySchemes: bearerAuth: type: http @@ -1424,7 +1434,41 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PermissionPayload' + $ref: '#/components/schemas/RegisterPermissionPayload' + '/SASjsApi/permission/{permissionId}': + patch: + operationId: UpdatePermission + responses: + '200': + description: Ok + content: + application/json: + schema: + $ref: '#/components/schemas/PermissionDetailsResponse' + examples: + 'Example 1': + value: {permissionId: 123, uri: /SASjsApi/code/execute, setting: Grant, user: {id: 1, username: johnSnow01, displayName: 'John Snow'}} + summary: 'Update permission setting.' + tags: + - Permission + security: + - + bearerAuth: [] + parameters: + - + description: 'The permission''s identifier' + in: path + name: permissionId + required: true + schema: + format: double + type: number + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdatePermissionPayload' servers: - url: / diff --git a/api/src/controllers/permission.ts b/api/src/controllers/permission.ts index 8ea77d7..f1e8bf3 100644 --- a/api/src/controllers/permission.ts +++ b/api/src/controllers/permission.ts @@ -6,6 +6,7 @@ import { Example, Get, Post, + Patch, Delete, Body } from 'tsoa' @@ -17,7 +18,7 @@ import Client from '../model/Client' import { UserResponse } from './user' import { GroupResponse } from './group' -interface PermissionPayload { +interface RegisterPermissionPayload { /** * Name of affected resource * @example "/SASjsApi/code/execute" @@ -40,6 +41,14 @@ interface PermissionPayload { principalId: any } +interface UpdatePermissionPayload { + /** + * The indication of whether (and to what extent) access is provided + * @example "Grant" + */ + setting: string +} + interface PermissionDetailsResponse { permissionId: number uri: string @@ -98,10 +107,29 @@ export class PermissionController { }) @Post('/') public async createPermission( - @Body() body: PermissionPayload + @Body() body: RegisterPermissionPayload ): Promise { return createPermission(body) } + + /** + * @summary Update permission setting. + * @param permissionId The permission's identifier + * @example userId "1234" + */ + @Example({ + permissionId: 123, + uri: '/SASjsApi/code/execute', + setting: 'Grant', + user: { id: 1, username: 'johnSnow01', displayName: 'John Snow' } + }) + @Patch('{permissionId}') + public async updatePermission( + @Path() permissionId: number, + @Body() body: UpdatePermissionPayload + ): Promise { + return updatePermission(permissionId, body) + } } const getAllPermissions = async (): Promise => @@ -127,7 +155,7 @@ const createPermission = async ({ setting, principalType, principalId -}: PermissionPayload): Promise => { +}: RegisterPermissionPayload): Promise => { const permission = new Permission({ uri, setting @@ -174,3 +202,34 @@ const createPermission = async ({ clientId: !!client ? client.clientId : undefined } } + +const updatePermission = async ( + id: number, + data: UpdatePermissionPayload +): Promise => { + const { setting } = data + + const updatedPermission = (await Permission.findOneAndUpdate( + { permissionId: id }, + { setting }, + { new: true } + ) + .select({ + _id: 0, + permissionId: 1, + uri: 1, + setting: 1 + }) + .populate({ path: 'user', select: 'id username displayName -_id' }) + .populate({ + path: 'group', + select: 'groupId name description -_id' + }) + .populate({ + path: 'client', + select: 'clientId -_id' + })) as unknown as PermissionDetailsResponse + if (!updatedPermission) throw new Error('Unable to update permission') + + return updatedPermission +} diff --git a/api/src/routes/api/permission.ts b/api/src/routes/api/permission.ts index fc83462..224c329 100644 --- a/api/src/routes/api/permission.ts +++ b/api/src/routes/api/permission.ts @@ -1,7 +1,10 @@ import express from 'express' import { PermissionController } from '../../controllers/' import { authenticateAccessToken, verifyAdmin } from '../../middlewares' -import { registerPermissionValidation } from '../../utils' +import { + registerPermissionValidation, + updatePermissionValidation +} from '../../utils' const permissionRouter = express.Router() const controller = new PermissionController() @@ -32,4 +35,22 @@ permissionRouter.post( } ) +permissionRouter.patch( + '/:permissionId', + authenticateAccessToken, + verifyAdmin, + async (req: any, res) => { + const { permissionId } = req.params + + const { error, value: body } = updatePermissionValidation(req.body) + if (error) return res.status(400).send(error.details[0].message) + + try { + const response = await controller.updatePermission(permissionId, body) + res.send(response) + } catch (err: any) { + res.status(403).send(err.toString()) + } + } +) export default permissionRouter diff --git a/api/src/utils/validation.ts b/api/src/utils/validation.ts index cbdd23d..a9d35c2 100644 --- a/api/src/utils/validation.ts +++ b/api/src/utils/validation.ts @@ -82,6 +82,11 @@ export const registerPermissionValidation = (data: any): Joi.ValidationResult => principalId: Joi.any().required() }).validate(data) +export const updatePermissionValidation = (data: any): Joi.ValidationResult => + Joi.object({ + setting: Joi.string().required() + }).validate(data) + export const deployValidation = (data: any): Joi.ValidationResult => Joi.object({ appLoc: Joi.string().pattern(/^\//).required().min(2),