Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(adminform): extract get collaborators #1762

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -8052,7 +8052,7 @@ describe('admin-form.controller', () => {
} as IPopulatedForm
const MOCK_COLLABORATORS = [
{
email: `[email protected]`,
email: `fakeuser@test.gov.sg`,
write: false,
},
]
Expand Down Expand Up @@ -8214,4 +8214,162 @@ describe('admin-form.controller', () => {
).not.toHaveBeenCalled()
})
})

describe('handleGetFormCollaborators', () => {
const MOCK_FORM_ID = new ObjectId().toHexString()
const MOCK_USER_ID = new ObjectId().toHexString()
const MOCK_USER = {
_id: MOCK_USER_ID,
email: '[email protected]',
} as IPopulatedUser
const MOCK_REQ = expressHandler.mockRequest({
params: {
formId: MOCK_FORM_ID,
},
session: {
user: MOCK_USER,
},
})

const MOCK_COLLABORATORS = [
{
email: `[email protected]`,
write: false,
},
]
const MOCK_FORM = {
admin: MOCK_USER,
_id: MOCK_FORM_ID,
permissionList: MOCK_COLLABORATORS,
} as IPopulatedForm

beforeEach(() => {
// Mock various services to return expected results.
MockUserService.getPopulatedUserById.mockReturnValue(okAsync(MOCK_USER))
MockAuthService.getFormAfterPermissionChecks.mockReturnValue(
okAsync(MOCK_FORM),
)
})

it('should return 200 with the collaborators when the request is successful', async () => {
// Arrange
const mockRes = expressHandler.mockResponse()

// Act
await AdminFormController.handleGetFormCollaborators(
MOCK_REQ,
mockRes,
jest.fn(),
)

// Assert
expect(mockRes.status).toBeCalledWith(StatusCodes.OK)
expect(mockRes.send).toBeCalledWith(MOCK_COLLABORATORS)
})

it('should return 403 when the user does not have sufficient permissions to retrieve collaborators', async () => {
// Arrange
const ERROR_MESSAGE = 'all your base are belong to us'
MockAuthService.getFormAfterPermissionChecks.mockReturnValueOnce(
errAsync(new ForbiddenFormError(ERROR_MESSAGE)),
)
const mockRes = expressHandler.mockResponse()
const expectedResponse = { message: ERROR_MESSAGE }

// Act
await AdminFormController.handleGetFormCollaborators(
MOCK_REQ,
mockRes,
jest.fn(),
)

// Assert
expect(mockRes.status).toBeCalledWith(StatusCodes.FORBIDDEN)
expect(mockRes.json).toBeCalledWith(expectedResponse)
})

it('should return 404 when the form could not be found', async () => {
// Arrange
const ERROR_MESSAGE = 'all your base are belong to us'
MockAuthService.getFormAfterPermissionChecks.mockReturnValueOnce(
errAsync(new FormNotFoundError(ERROR_MESSAGE)),
)
const mockRes = expressHandler.mockResponse()
const expectedResponse = { message: ERROR_MESSAGE }

// Act
await AdminFormController.handleGetFormCollaborators(
MOCK_REQ,
mockRes,
jest.fn(),
)

// Assert
expect(mockRes.status).toBeCalledWith(StatusCodes.NOT_FOUND)
expect(mockRes.json).toBeCalledWith(expectedResponse)
})

it('should return 410 when the form has been archived', async () => {
// Arrange
const ERROR_MESSAGE = 'all your base are belong to us'
MockAuthService.getFormAfterPermissionChecks.mockReturnValueOnce(
errAsync(new FormDeletedError(ERROR_MESSAGE)),
)
const mockRes = expressHandler.mockResponse()
const expectedResponse = { message: ERROR_MESSAGE }

// Act
await AdminFormController.handleGetFormCollaborators(
MOCK_REQ,
mockRes,
jest.fn(),
)

// Assert
expect(mockRes.status).toBeCalledWith(StatusCodes.GONE)
expect(mockRes.json).toBeCalledWith(expectedResponse)
})

it('should return 422 when the current user could not be retrieved from the database', async () => {
// Arrange
const ERROR_MESSAGE = 'all your base are belong to us'
MockUserService.getPopulatedUserById.mockReturnValueOnce(
errAsync(new MissingUserError(ERROR_MESSAGE)),
)
const expectedResponse = { message: ERROR_MESSAGE }
const mockRes = expressHandler.mockResponse()

// Act
await AdminFormController.handleGetFormCollaborators(
MOCK_REQ,
mockRes,
jest.fn(),
)

// Assert
expect(mockRes.status).toBeCalledWith(StatusCodes.UNPROCESSABLE_ENTITY)
expect(mockRes.json).toBeCalledWith(expectedResponse)
})

it('should return 500 when a database error occurs', async () => {
// Arrange
const ERROR_MESSAGE = 'all your base are belong to us'
MockUserService.getPopulatedUserById.mockReturnValueOnce(
errAsync(new DatabaseError(ERROR_MESSAGE)),
)
const expectedResponse = { message: ERROR_MESSAGE }
const mockRes = expressHandler.mockResponse()

// Act
await AdminFormController.handleGetFormCollaborators(
MOCK_REQ,
mockRes,
jest.fn(),
)

// Assert
expect(mockRes.status).toBeCalledWith(StatusCodes.INTERNAL_SERVER_ERROR)
expect(mockRes.json).toBeCalledWith(expectedResponse)
})
})
})
48 changes: 48 additions & 0 deletions src/app/modules/form/admin-form/admin-form.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,54 @@ export const handleGetAdminForm: RequestHandler<{ formId: string }> = (
)
}

/**
* Handler for GET /api/v3/admin/forms/:formId/collaborators
* @security session
*
* @returns 200 with collaborators
* @returns 403 when current user does not have read permissions for the form
* @returns 404 when form cannot be found
* @returns 410 when retrieving collaborators for an archived form
* @returns 422 when user in session cannot be retrieved from the database
* @returns 500 when database error occurs
*/
export const handleGetFormCollaborators: RequestHandler<
{ formId: string },
PermissionsUpdateDto | ErrorDto
> = (req, res) => {
const { formId } = req.params
const sessionUserId = (req.session as Express.AuthedSession).user._id

return (
// Step 1: Retrieve currently logged in user.
UserService.getPopulatedUserById(sessionUserId)
.andThen((user) =>
// Step 2: Check whether user has read permissions to form
AuthService.getFormAfterPermissionChecks({
user,
formId,
level: PermissionLevel.Read,
}),
)
.map(({ permissionList }) =>
res.status(StatusCodes.OK).send(permissionList),
seaerchin marked this conversation as resolved.
Show resolved Hide resolved
)
.mapErr((error) => {
logger.error({
message: 'Error retrieving form collaborators',
meta: {
action: 'handleGetFormCollaborators',
...createReqMeta(req),
},
error,
})

const { statusCode, errorMessage } = mapRouteError(error)
return res.status(statusCode).json({ message: errorMessage })
})
)
}

/**
* Handler for GET /:formId/adminform/preview.
* @security session
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { createAuthedSession } from 'tests/integration/helpers/express-auth'
import { setupApp } from 'tests/integration/helpers/express-setup'
import { buildCelebrateError } from 'tests/unit/backend/helpers/celebrate'
import dbHandler from 'tests/unit/backend/helpers/jest-db'
import { jsonParseStringify } from 'tests/unit/backend/helpers/serialize-data'

import { jsonParseStringify } from '../../../../../../../../tests/unit/backend/helpers/serialize-data'
import * as UserService from '../../../../../../modules/user/user.service'
Expand Down Expand Up @@ -396,4 +397,139 @@ describe('admin-form.settings.routes', () => {
expect(response.body).toEqual(expectedResponse)
})
})

describe('GET /admin/forms/:formId/collaborators', () => {
const MOCK_COLLABORATORS = [
{
email: `[email protected]`,
write: false,
},
]
it('should return the list of collaborators on a valid request', async () => {
// Arrange
const { form, user } = await dbHandler.insertEmailForm({
formOptions: {
permissionList: MOCK_COLLABORATORS,
},
})
const session = await createAuthedSession(user.email, request)

// Act
const response = await session.get(
`/admin/forms/${form._id}/collaborators`,
)

// Assert
expect(response.status).toEqual(200)
expect(response.body).toMatchObject(
jsonParseStringify(MOCK_COLLABORATORS),
)
})

it('should return 403 when the current user does not have read permissions for the specified form', async () => {
// Arrange
const { form } = await dbHandler.insertEmailForm({
formOptions: {
permissionList: MOCK_COLLABORATORS,
},
})
const fakeUser = await dbHandler.insertUser({
mailName: 'fakeUser',
agencyId: new ObjectId(),
})
const session = await createAuthedSession(fakeUser.email, request)
const expectedResponse = jsonParseStringify({
message: `User ${fakeUser.email} not authorized to perform read operation on Form ${form._id} with title: ${form.title}.`,
})

// Act
const response = await session.get(
`/admin/forms/${form._id}/collaborators`,
)

// Assert
expect(response.status).toEqual(403)
expect(response.body).toMatchObject(jsonParseStringify(expectedResponse))
})

it('should return 404 when the form could not be found', async () => {
// Arrange
const { user } = await dbHandler.insertEmailForm()
const session = await createAuthedSession(user.email, request)
const expectedResponse = jsonParseStringify({
message: 'Form not found',
})

// Act
const response = await session.get(
`/admin/forms/${new ObjectId().toHexString()}/collaborators`,
)

// Assert
expect(response.status).toEqual(404)
expect(response.body).toEqual(expectedResponse)
})

it('should return 410 when the form has been archived', async () => {
// Arrange
const { form, user } = await dbHandler.insertEmailForm({
formOptions: {
status: Status.Archived,
},
})
const session = await createAuthedSession(user.email, request)
const expectedResponse = jsonParseStringify({
message: 'Form has been archived',
})

// Act
const response = await session.get(
`/admin/forms/${form._id}/collaborators`,
)

// Assert
expect(response.status).toEqual(410)
expect(response.body).toEqual(expectedResponse)
})

it('should return 422 when the current session user cannot be retrieved', async () => {
// Arrange
const { form, user } = await dbHandler.insertEmailForm()
const session = await createAuthedSession(user.email, request)
const expectedResponse = jsonParseStringify({
message: 'User not found',
})
await dbHandler.clearCollection(UserModel.collection.name)

// Act
const response = await session.get(
`/admin/forms/${form._id}/collaborators`,
)

// Assert
expect(response.status).toEqual(422)
expect(response.body).toEqual(expectedResponse)
})

it('should return 500 when a database error occurs', async () => {
// Arrange
const { form, user } = await dbHandler.insertEmailForm()
const session = await createAuthedSession(user.email, request)
const expectedResponse = jsonParseStringify({
message: 'Something went wrong. Please try again.',
})
jest
.spyOn(UserService, 'getPopulatedUserById')
.mockReturnValueOnce(errAsync(new DatabaseError()))

// Act
const response = await session.get(
`/admin/forms/${form._id}/collaborators`,
)

// Assert
expect(response.status).toEqual(500)
expect(response.body).toEqual(expectedResponse)
})
})
})
Loading