From f941ea6db392ce97451a0be84f076807724ee0e2 Mon Sep 17 00:00:00 2001 From: Wayne Ngo Date: Fri, 2 Jan 2026 21:23:00 -0800 Subject: [PATCH 1/2] ui page for admin or officers --- .../models/PermissionRequest.js | 6 +- .../routes/PermissionRequest.js | 35 ++++- src/APIFunctions/PermissionRequest.js | 97 ++++++++++++- src/Pages/LedSign/LedSign.js | 135 +++++++++++++++++- 4 files changed, 261 insertions(+), 12 deletions(-) diff --git a/api/main_endpoints/models/PermissionRequest.js b/api/main_endpoints/models/PermissionRequest.js index 5d42f4362..b88e1f067 100644 --- a/api/main_endpoints/models/PermissionRequest.js +++ b/api/main_endpoints/models/PermissionRequest.js @@ -14,6 +14,10 @@ const PermissionRequestSchema = new Schema( enum: Object.values(PermissionRequestTypes), required: true, }, + approved: { + type: Boolean, + default: false, + }, deletedAt: { type: Date, default: null, @@ -23,7 +27,7 @@ const PermissionRequestSchema = new Schema( ); // Compound unique index prevents duplicate active requests per user+type -PermissionRequestSchema.index({ userId: 1, type: 1 }, { unique: true, partialFilterExpression: { deletedAt: null }}); +PermissionRequestSchema.index({ userId: 1, type: 1 }, { unique: true, partialFilterExpression: { deletedAt: null, approved: false }}); module.exports = mongoose.model('PermissionRequest', PermissionRequestSchema); diff --git a/api/main_endpoints/routes/PermissionRequest.js b/api/main_endpoints/routes/PermissionRequest.js index b2ad88eb9..e3a634df1 100644 --- a/api/main_endpoints/routes/PermissionRequest.js +++ b/api/main_endpoints/routes/PermissionRequest.js @@ -39,17 +39,20 @@ router.get('/get', async (req, res) => { try { const query = { deletedAt: null }; - // If theres no userId, return all for officers and admins + // If theres no userId, return all for officers and admins (only pending requests) if (!queryUserId) { if (!isOfficer) { return res.sendStatus(UNAUTHORIZED); } + // For admin view, only show pending (non-approved) requests + query.approved = false; } else { // If there is a userId, check their perms if (!isOfficer && queryUserId !== decoded.token._id.toString()) { return res.sendStatus(FORBIDDEN); } query.userId = queryUserId; + // For member's own request, return it regardless of approval status } // If there is a type, filter by it @@ -68,6 +71,36 @@ router.get('/get', async (req, res) => { } }); +router.post('/approve', async (req, res) => { + const decoded = await decodeToken(req, membershipState.OFFICER); + if (decoded.status !== OK) return res.sendStatus(decoded.status); + + const { type, _id } = req.body; + if (!type || !Object.keys(PermissionRequestTypes).includes(type)) { + return res.status(BAD_REQUEST).send({ error: 'Invalid type' }); + } + + if (!_id) { + return res.status(BAD_REQUEST).send({ error: '_id is required' }); + } + + try { + const request = await PermissionRequest.findOne({ + _id, + type, + deletedAt: null, + }); + + if (!request) return res.sendStatus(NOT_FOUND); + request.approved = true; + await request.save(); + res.sendStatus(OK); + } catch (error) { + logger.error('Failed to approve permission request:', error); + res.sendStatus(SERVER_ERROR); + } +}); + router.post('/delete', async (req, res) => { const decoded = await decodeToken(req, membershipState.MEMBER); if (decoded.status !== OK) return res.sendStatus(decoded.status); diff --git a/src/APIFunctions/PermissionRequest.js b/src/APIFunctions/PermissionRequest.js index 85adcc35a..9d37682e2 100644 --- a/src/APIFunctions/PermissionRequest.js +++ b/src/APIFunctions/PermissionRequest.js @@ -1,10 +1,13 @@ import { ApiResponse } from './ApiResponses'; import { BASE_API_URL } from '../Enums'; -export async function getPermissionRequest(type, token) { +export async function getPermissionRequest(type, userId, token) { const status = new ApiResponse(); const url = new URL('/api/PermissionRequest/get', BASE_API_URL); url.searchParams.append('type', type); + if (userId) { + url.searchParams.append('userId', userId); + } try { const res = await fetch(url.toString(), { @@ -15,11 +18,11 @@ export async function getPermissionRequest(type, token) { if (res.ok) { const data = await res.json(); - status.responseData = data; - } else if (res.status === 404) { - status.responseData = null; + // API returns an array, return first item or null + status.responseData = Array.isArray(data) && data.length > 0 ? data[0] : null; } else { status.error = true; + status.responseData = null; } } catch (err) { status.responseData = err; @@ -43,6 +46,38 @@ export async function createPermissionRequest(type, token) { body: JSON.stringify({ type }), }); + if (res.ok) { + // API returns 200 with no body, so we just mark success + status.responseData = true; + } else if (res.status === 409) { + // CONFLICT - duplicate request + status.error = true; + status.responseData = 'Request already exists'; + } else { + status.error = true; + } + } catch (err) { + status.responseData = err; + status.error = true; + } + + return status; +} + +export async function getAllPermissionRequests(type, token) { + const status = new ApiResponse(); + const url = new URL('/api/PermissionRequest/get', BASE_API_URL); + if (type) { + url.searchParams.append('type', type); + } + + try { + const res = await fetch(url.toString(), { + headers: { + Authorization: `Bearer ${token}`, + }, + }); + if (res.ok) { const data = await res.json(); status.responseData = data; @@ -57,3 +92,57 @@ export async function createPermissionRequest(type, token) { return status; } +export async function approvePermissionRequest(type, id, token) { + const status = new ApiResponse(); + const url = new URL('/api/PermissionRequest/approve', BASE_API_URL); + + try { + const res = await fetch(url.toString(), { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ type, _id: id }), + }); + + if (res.ok) { + status.responseData = true; + } else { + status.error = true; + } + } catch (err) { + status.responseData = err; + status.error = true; + } + + return status; +} + +export async function deletePermissionRequest(type, id, token) { + const status = new ApiResponse(); + const url = new URL('/api/PermissionRequest/delete', BASE_API_URL); + + try { + const res = await fetch(url.toString(), { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ type, _id: id }), + }); + + if (res.ok) { + status.responseData = true; + } else { + status.error = true; + } + } catch (err) { + status.responseData = err; + status.error = true; + } + + return status; +} + diff --git a/src/Pages/LedSign/LedSign.js b/src/Pages/LedSign/LedSign.js index 1b9b1baed..176aa7fa3 100644 --- a/src/Pages/LedSign/LedSign.js +++ b/src/Pages/LedSign/LedSign.js @@ -1,6 +1,6 @@ import React, { useState, useEffect } from 'react'; import { healthCheck, updateSignText } from '../../APIFunctions/LedSign'; -import { getPermissionRequest, createPermissionRequest } from '../../APIFunctions/PermissionRequest'; +import { getPermissionRequest, createPermissionRequest, getAllPermissionRequests, approvePermissionRequest, deletePermissionRequest } from '../../APIFunctions/PermissionRequest'; import { useSCE } from '../../Components/context/SceContext'; import { membershipState } from '../../Enums'; @@ -25,6 +25,10 @@ function LedSign() { const [permissionRequest, setPermissionRequest] = useState(null); const [checkingPermission, setCheckingPermission] = useState(false); const [requestingPermission, setRequestingPermission] = useState(false); + const isOfficer = user.accessLevel >= membershipState.OFFICER; + const [tab, setTab] = useState('sign'); + const [allPermissionRequests, setAllPermissionRequests] = useState([]); + const [loadingRequests, setLoadingRequests] = useState(false); const inputArray = [ { title: 'Sign Text:', @@ -220,7 +224,7 @@ function LedSign() { async function checkPermission() { if (user.accessLevel < membershipState.OFFICER) { setCheckingPermission(true); - const result = await getPermissionRequest('LED_SIGN', user.token); + const result = await getPermissionRequest('LED_SIGN', user._id, user.token); if (!result.error && result.responseData) { setPermissionRequest(result.responseData); } @@ -231,7 +235,14 @@ function LedSign() { checkSignHealth(); checkPermission(); // eslint-disable-next-line - }, []) + }, []); + + useEffect(() => { + if (isOfficer && tab === 'requests') { + fetchAllPermissionRequests(); + } + // eslint-disable-next-line + }, [tab, isOfficer]); if (loading || checkingPermission) { return ( @@ -253,7 +264,10 @@ function LedSign() { setRequestingPermission(true); const result = await createPermissionRequest('LED_SIGN', user.token); if (!result.error) { - setPermissionRequest(result.responseData); + const fetchResult = await getPermissionRequest('LED_SIGN', user._id, user.token); + if (!fetchResult.error && fetchResult.responseData) { + setPermissionRequest(fetchResult.responseData); + } } setRequestingPermission(false); } @@ -271,7 +285,7 @@ function LedSign() { ); } - if (permissionRequest) { + if (permissionRequest && !permissionRequest.approved) { return (

@@ -311,6 +325,95 @@ function LedSign() { return (11 - scrollSpeed); } + function getSelectedClassName(currTab) { + return currTab === tab + ? 'p-2 bg-gray-100 dark:bg-gray-700 rounded-md dark:text-white text-gray-700' + : 'p-2 hover:bg-gray-400 rounded-md dark:text-white text-gray-700'; + } + + async function fetchAllPermissionRequests() { + if (!isOfficer) return; + setLoadingRequests(true); + const result = await getAllPermissionRequests('LED_SIGN', user.token); + if (!result.error && result.responseData) { + setAllPermissionRequests(result.responseData); + } + setLoadingRequests(false); + } + + async function handleApprove(requestId) { + const result = await approvePermissionRequest('LED_SIGN', requestId, user.token); + if (!result.error) await fetchAllPermissionRequests(); + } + + async function handleDeny(requestId) { + const result = await deletePermissionRequest('LED_SIGN', requestId, user.token); + if (!result.error) await fetchAllPermissionRequests(); + } + + function formatUserName(userData) { + if (!userData) return 'Unknown User'; + const name = `${userData.firstName || ''} ${userData.lastName || ''}`.trim(); + return name || 'Unknown User'; + } + + function MaybeRenderListOfSignRequests() { + if (!isOfficer) return null; + if (loadingRequests) { + return ( +

+

Loading requests...

+
+ ); + } + + return ( +
+
+ + + + + + + + + + + {allPermissionRequests.length === 0 ? ( + + + + ) : ( + allPermissionRequests.map((request) => ( + + + + + + + )) + )} + +
User NameEmailRequest DateActions
+ No pending requests +
+ {formatUserName(request.userId)} + {request.userId?.email || 'N/A'}{getFormattedTime(request.createdAt)} +
+ + +
+
+
+
+ ); + } + const hasAccess = user.accessLevel >= membershipState.OFFICER; return ( @@ -321,7 +424,24 @@ function LedSign() {
)} {hasAccess && ( -
+ <> +
+ +
 | 
+ +
+ {tab === 'sign' && ( +
@@ -391,6 +511,9 @@ function LedSign() {
+ )} + {tab === 'requests' && } + )}
); From 0f1be4d3d70fde52f4543e52873977342195eea2 Mon Sep 17 00:00:00 2001 From: Wayne Ngo Date: Tue, 27 Jan 2026 16:38:39 -0800 Subject: [PATCH 2/2] enum changes --- .../models/PermissionRequest.js | 17 ++++----- .../routes/PermissionRequest.js | 34 +++++++++++++----- api/util/constants.js | 7 ++++ src/APIFunctions/PermissionRequest.js | 6 ++-- src/Pages/LedSign/LedSign.js | 9 +++-- test/api/PermissionRequest.js | 36 +++++++++++++------ 6 files changed, 75 insertions(+), 34 deletions(-) diff --git a/api/main_endpoints/models/PermissionRequest.js b/api/main_endpoints/models/PermissionRequest.js index b88e1f067..956bbe36c 100644 --- a/api/main_endpoints/models/PermissionRequest.js +++ b/api/main_endpoints/models/PermissionRequest.js @@ -1,6 +1,7 @@ const mongoose = require('mongoose'); const Schema = mongoose.Schema; const PermissionRequestTypes = require('../util/permissionRequestTypes'); +const PermissionRequestStatus = require('../../util/constants').PERMISSION_REQUEST_STATUS; const PermissionRequestSchema = new Schema( { @@ -14,20 +15,20 @@ const PermissionRequestSchema = new Schema( enum: Object.values(PermissionRequestTypes), required: true, }, - approved: { - type: Boolean, - default: false, - }, - deletedAt: { - type: Date, - default: null, + status: { + type: String, + enum: Object.values(PermissionRequestStatus), + default: PermissionRequestStatus.PENDING, }, }, { timestamps: { createdAt: true, updatedAt: false } } ); // Compound unique index prevents duplicate active requests per user+type -PermissionRequestSchema.index({ userId: 1, type: 1 }, { unique: true, partialFilterExpression: { deletedAt: null, approved: false }}); +PermissionRequestSchema.index( + { userId: 1, type: 1 }, + { unique: true, partialFilterExpression: { status: PermissionRequestStatus.PENDING } } +); module.exports = mongoose.model('PermissionRequest', PermissionRequestSchema); diff --git a/api/main_endpoints/routes/PermissionRequest.js b/api/main_endpoints/routes/PermissionRequest.js index 8ccb4cffd..d4c7ae9b9 100644 --- a/api/main_endpoints/routes/PermissionRequest.js +++ b/api/main_endpoints/routes/PermissionRequest.js @@ -1,7 +1,10 @@ const express = require('express'); const router = express.Router(); const PermissionRequest = require('../models/PermissionRequest'); -const { OK, UNAUTHORIZED, SERVER_ERROR, NOT_FOUND, BAD_REQUEST, CONFLICT } = require('../../util/constants').STATUS_CODES; +const { + STATUS_CODES: { OK, UNAUTHORIZED, SERVER_ERROR, NOT_FOUND, BAD_REQUEST, CONFLICT }, + PERMISSION_REQUEST_STATUS: PermissionRequestStatus, +} = require('../../util/constants'); const membershipState = require('../../util/constants.js').MEMBERSHIP_STATE; const { decodeToken } = require('../util/token-functions.js'); const logger = require('../../util/logger'); @@ -17,11 +20,23 @@ router.post('/create', async (req, res) => { } try { - await PermissionRequest.create({ + const existingRequest = await PermissionRequest.findOne({ userId: decoded.token._id, type, }); - res.sendStatus(OK); + + if (existingRequest) { + if (existingRequest.status === PermissionRequestStatus.PENDING) { + return res.sendStatus(CONFLICT); + } + existingRequest.status = PermissionRequestStatus.PENDING; + existingRequest.createdAt = new Date(); + await existingRequest.save(); + return res.sendStatus(OK); + } + + await PermissionRequest.create({ userId: decoded.token._id, type }); + return res.sendStatus(OK); } catch (error) { if (error.code === 11000) return res.sendStatus(CONFLICT); logger.error('Failed to create permission request:', error); @@ -37,7 +52,7 @@ router.get('/', async (req, res) => { const isOfficer = decoded.token.accessLevel >= membershipState.OFFICER; try { - const query = { deletedAt: null }; + const query = { status: { $ne: PermissionRequestStatus.DENIED } }; if (queryUserId) { query.userId = queryUserId; @@ -45,6 +60,9 @@ router.get('/', async (req, res) => { } if (!isOfficer) { query.userId = decoded.token._id.toString(); + } else if (!queryUserId) { + // Officers viewing the list should only see pending requests + query.status = PermissionRequestStatus.PENDING; } // If there is a type, filter by it @@ -80,11 +98,11 @@ router.post('/approve', async (req, res) => { const request = await PermissionRequest.findOne({ _id, type, - deletedAt: null, + status: PermissionRequestStatus.PENDING, }); if (!request) return res.sendStatus(NOT_FOUND); - request.approved = true; + request.status = PermissionRequestStatus.APPROVED; await request.save(); res.sendStatus(OK); } catch (error) { @@ -117,13 +135,13 @@ router.post('/delete', async (req, res) => { const query = { _id: idToUse, type, - deletedAt: null, + status: { $ne: PermissionRequestStatus.DENIED }, }; const request = await PermissionRequest.findOne(query); if (!request) return res.sendStatus(NOT_FOUND); - request.deletedAt = new Date(); + request.status = PermissionRequestStatus.DENIED; await request.save(); res.sendStatus(OK); } catch (error) { diff --git a/api/util/constants.js b/api/util/constants.js index 7b7e6b68a..99844ed6d 100644 --- a/api/util/constants.js +++ b/api/util/constants.js @@ -33,10 +33,17 @@ const consoleColors = { // 60 seconds per minute * 60 minutes per hour * 12 hours const PASSWORD_RESET_EXPIRATION = 60 * 60 * 12; +const PERMISSION_REQUEST_STATUS = { + PENDING: 'PENDING', + APPROVED: 'APPROVED', + DENIED: 'DENIED', +}; + module.exports = { STATUS_CODES, MEMBERSHIP_STATE, MESSAGES_API, consoleColors, PASSWORD_RESET_EXPIRATION, + PERMISSION_REQUEST_STATUS, }; diff --git a/src/APIFunctions/PermissionRequest.js b/src/APIFunctions/PermissionRequest.js index 34098c998..dc7ccee3a 100644 --- a/src/APIFunctions/PermissionRequest.js +++ b/src/APIFunctions/PermissionRequest.js @@ -16,10 +16,12 @@ export async function getPermissionRequest(type, userId, token) { }, }); - status.error = !!res.ok; + status.error = !res.ok; if (res.ok) { const data = await res.json(); status.responseData = Array.isArray(data) && data.length > 0 ? data[0] : null; + } else { + status.responseData = null; } } catch (err) { status.responseData = err; @@ -63,7 +65,7 @@ export async function createPermissionRequest(type, token) { export async function getAllPermissionRequests(type, token) { const status = new ApiResponse(); - const url = new URL('/api/PermissionRequest/get', BASE_API_URL); + const url = new URL('/api/PermissionRequest/', BASE_API_URL); if (type) { url.searchParams.append('type', type); } diff --git a/src/Pages/LedSign/LedSign.js b/src/Pages/LedSign/LedSign.js index b7fc8d461..fc92fe805 100644 --- a/src/Pages/LedSign/LedSign.js +++ b/src/Pages/LedSign/LedSign.js @@ -202,9 +202,9 @@ function LedSign() { useEffect(() => { async function checkSignHealth() { setLoading(true); + setSignHealthy(true); const status = await healthCheck(user.firstName); if (status.responseData && !status.error) { - setSignHealthy(true); const { responseData } = status; if (Object.keys(responseData).length > 0) { setText(responseData.text); @@ -215,8 +215,7 @@ function LedSign() { setBorderColor(responseData.borderColor); setExistingExpirationFromSign(responseData.expiration); } - } else { - setSignHealthy(false); + } setLoading(false); } @@ -263,7 +262,7 @@ function LedSign() { async function handleRequestAccess() { setRequestingPermission(true); const result = await createPermissionRequest('LED_SIGN', user.token); - if (!result.error) { + if (!result.error || result.responseData === 'Request already exists') { const fetchResult = await getPermissionRequest('LED_SIGN', user._id, user.token); if (!fetchResult.error && fetchResult.responseData) { setPermissionRequest(fetchResult.responseData); @@ -285,7 +284,7 @@ function LedSign() { ); } - if (permissionRequest && !permissionRequest.approved) { + if (permissionRequest && permissionRequest.status === 'PENDING') { return (

diff --git a/test/api/PermissionRequest.js b/test/api/PermissionRequest.js index 8f539114e..ca91a87b4 100644 --- a/test/api/PermissionRequest.js +++ b/test/api/PermissionRequest.js @@ -15,6 +15,7 @@ const { } = require('../util/mocks/TokenValidFunctions'); const mongoose = require('mongoose'); const PermissionRequestTypes = require('../../api/main_endpoints/util/permissionRequestTypes'); +const PermissionRequestStatus = constants.PERMISSION_REQUEST_STATUS; let app = null; let test = null; @@ -96,6 +97,17 @@ describe('PermissionRequest', () => { expect(res).to.have.status(CONFLICT); }); + it('Should allow new request after denial', async () => { + const userId = createUserToken(); + const request = await createRequest(userId); + request.status = PermissionRequestStatus.DENIED; + await request.save(); + const res = await test.sendPostRequestWithToken(token, '/api/PermissionRequest/create', { type: PermissionRequestTypes.LED_SIGN }); + expect(res).to.have.status(OK); + const updated = await PermissionRequest.findById(request._id); + expect(updated.status).to.equal(PermissionRequestStatus.PENDING); + }); + it('Should create permission request successfully', async () => { const userId = createUserToken(); const res = await test.sendPostRequestWithToken(token, '/api/PermissionRequest/create', { type: PermissionRequestTypes.LED_SIGN }); @@ -174,11 +186,11 @@ describe('PermissionRequest', () => { expect(typeRes.body.every(r => r.type === PermissionRequestTypes.LED_SIGN)).to.be.true; }); - it('Should exclude deleted requests and sort by createdAt descending', async () => { + it('Should exclude denied requests and sort by createdAt descending', async () => { const userId = createUserToken(); await PermissionRequest.deleteMany({ userId }); const active = await createRequest(userId); - active.deletedAt = new Date(); + active.status = PermissionRequestStatus.DENIED; await active.save(); const res = await test.sendGetRequest(GET_ROUTE); expect(res.body.map(r => r._id.toString())).to.not.include(active._id.toString()); @@ -224,11 +236,10 @@ describe('PermissionRequest', () => { expect(missingRes).to.have.status(BAD_REQUEST); }); - it('Should delete permission request successfully and set deletedAt', async () => { + it('Should delete permission request successfully and set status', async () => { const userId = createUserToken(); await PermissionRequest.deleteMany({ userId, type: PermissionRequestTypes.LED_SIGN }); const request = await new PermissionRequest({ userId, type: PermissionRequestTypes.LED_SIGN }).save(); - const beforeDelete = new Date(); // For non-officers, the API uses userId as _id in query, which won't match request._id // So we need to test with an officer who can provide the actual _id createUserToken(constants.MEMBERSHIP_STATE.OFFICER); @@ -237,18 +248,21 @@ describe('PermissionRequest', () => { }); expect(res).to.have.status(OK); const deleted = await PermissionRequest.findById(request._id); - expect(deleted.deletedAt).to.not.be.null; - expect(new Date(deleted.deletedAt).getTime()).to.be.at.least(beforeDelete.getTime()); + expect(deleted.status).to.equal(PermissionRequestStatus.DENIED); }); - it('Should return 404 when _id does not exist or request already deleted', async () => { + it('Should return 404 when _id does not exist or request already denied', async () => { const userId = createUserToken(constants.MEMBERSHIP_STATE.OFFICER); const nonExistentId = new mongoose.Types.ObjectId(); const res1 = await test.sendPostRequestWithToken(token, '/api/PermissionRequest/delete', { type: PermissionRequestTypes.LED_SIGN, _id: nonExistentId }); expect(res1).to.have.status(NOT_FOUND); - const deletedRequest = await new PermissionRequest({ userId, type: PermissionRequestTypes.LED_SIGN, deletedAt: new Date() }).save(); + const deletedRequest = await new PermissionRequest({ + userId, + type: PermissionRequestTypes.LED_SIGN, + status: PermissionRequestStatus.DENIED, + }).save(); const res2 = await test.sendPostRequestWithToken(token, '/api/PermissionRequest/delete', { type: PermissionRequestTypes.LED_SIGN, _id: deletedRequest._id }); @@ -264,14 +278,14 @@ describe('PermissionRequest', () => { type: PermissionRequestTypes.LED_SIGN, _id: request2._id }); expect(memberRes).to.have.status(NOT_FOUND); - expect((await PermissionRequest.findById(request2._id)).deletedAt).to.be.null; + expect((await PermissionRequest.findById(request2._id)).status).to.equal(PermissionRequestStatus.PENDING); // Officer can delete any request createUserToken(constants.MEMBERSHIP_STATE.OFFICER); const officerRes = await test.sendPostRequestWithToken(token, '/api/PermissionRequest/delete', { type: PermissionRequestTypes.LED_SIGN, _id: request2._id }); expect(officerRes).to.have.status(OK); - expect((await PermissionRequest.findById(request2._id)).deletedAt).to.not.be.null; + expect((await PermissionRequest.findById(request2._id)).status).to.equal(PermissionRequestStatus.DENIED); }); it('Should require _id parameter even for officers', async () => { @@ -281,7 +295,7 @@ describe('PermissionRequest', () => { type: PermissionRequestTypes.LED_SIGN }); expect(res).to.have.status(NOT_FOUND); - expect((await PermissionRequest.findById(request._id)).deletedAt).to.be.null; + expect((await PermissionRequest.findById(request._id)).status).to.equal(PermissionRequestStatus.PENDING); }); }); });