@@ -21,6 +21,8 @@ const sinon = require('sinon');
2121const SceApiTester = require ( '../util/tools/SceApiTester' ) ;
2222const { mockDayMonthAndYear, revertClock} = require ( '../util/mocks/Date.js' ) ;
2323
24+ const AuditLog = require ( '../../api/main_endpoints/models/AuditLog.js' ) ;
25+ const AuditLogActions = require ( '../../api/main_endpoints/util/auditLogActions.js' ) ;
2426
2527let app = null ;
2628let test = null ;
@@ -44,9 +46,6 @@ const {
4446const { MEMBERSHIP_STATE } = require ( '../../api/util/constants' ) ;
4547const { getMemberExpirationDate } = require ( '../../api/main_endpoints/util/userHelpers.js' ) ;
4648
47- const AuditLogActions = require ( '../../api/main_endpoints/util/auditLogActions.js' ) ;
48- const AuditLog = require ( '../../api/main_endpoints/models/AuditLog.js' ) ;
49-
5049chai . should ( ) ;
5150chai . use ( chaiHttp ) ;
5251
@@ -212,51 +211,158 @@ describe('User', () => {
212211 expect ( result ) . to . have . status ( NOT_FOUND ) ;
213212 } ) ;
214213
215- it ( 'Should return statusCode 200 and a message ' +
216- 'if a user was edited' , async ( ) => {
217- const user = {
218- _id : id ,
219- 220- token : token ,
221- firstName : 'pinkUnicorn' ,
222- discordID : '0987654321' ,
223- numberOfSemestersToSignUpFor : undefined
224- } ;
225- setTokenStatus ( true ) ;
226- const result = await test . sendPostRequestWithToken (
227- token , '/api/User/edit' , user ) ;
228- expect ( result ) . to . have . status ( OK ) ;
229- result . body . should . be . a ( 'object' ) ;
230- result . body . should . have . property ( 'message' ) ;
231- } ) ;
214+ describe ( 'create audit log on user change' , async ( ) => {
232215
233- it ( 'Should create an audit log when a user is updated' , async ( ) => {
234- // ensure Audit log DB starts fresh before this test
235- await AuditLog . deleteMany ( { } ) ;
236- // update email, firstname, password, and discordID
237- const user = {
238- _id : id ,
239- 240- password : 'newPassword' ,
241- token : token ,
242- firstName : 'Newname' ,
243- discordID : '421482148' ,
244- numberOfSemestersToSignUpFor : undefined
245- } ;
246- setTokenStatus ( true , user ) ;
216+ // create clean testUser before each test
217+ let testUser ;
247218
248- const result = await test . sendPostRequestWithToken (
249- token , '/api/User/edit' , user
250- ) ;
251- expect ( result ) . to . have . status ( OK ) ;
219+ beforeEach ( async ( ) => {
220+ await User . deleteMany ( { } ) ;
221+ testUser = await new User ( {
222+ 223+ password : 'Passw0rd' ,
224+ firstName : 'first-name' ,
225+ lastName : 'last-name' ,
226+ major : 'Computer Science'
227+ } ) . save ( ) ;
228+
229+ setTokenStatus ( true , testUser ) ;
230+ } ) ;
231+
232+ afterEach ( async ( ) => {
233+ await AuditLog . deleteMany ( { } ) ;
234+ } ) ;
235+
236+ it ( 'Should create an audit log when a user is updated (no password change)' + 'not create an audit log for password change' , async ( ) => {
237+ const res = await test . sendPostRequestWithToken ( token , '/api/User/edit' , {
238+ _id : testUser . _id . toString ( ) ,
239+ firstName : 'Newname' ,
240+ 241+ token
242+ } ) ;
243+
244+ expect ( res ) . to . have . status ( OK ) ;
245+ res . body . should . be . a ( 'object' ) ;
246+ res . body . should . have . property ( 'message' ) ;
247+
248+ const auditEntry = await AuditLog . findOne ( { userId : testUser . _id } ) . lean ( ) ;
249+ expect ( auditEntry ) . to . exist ;
250+ expect ( auditEntry . details . fieldChanges . firstName ) . to . have . deep . equal ( {
251+ from : 'first-name' ,
252+ to : 'Newname'
253+ } ) ;
254+
255+ // make sure pw change log doesn't exist
256+ const changePWlog = await AuditLog . findOne ( {
257+ userId : id ,
258+ action : AuditLogActions . CHANGE_PW
259+ } ) . lean ( ) ;
260+ expect ( changePWlog ) . to . not . exist ;
261+ } ) ;
252262
253- const auditEntry = await AuditLog . findOne ( ) . lean ( ) ;
263+ it ( 'Should create an audit log when a user changes their password (no profile update)' , async ( ) => {
264+ const res = await test . sendPostRequestWithToken ( token , '/api/User/edit' , {
265+ _id : testUser . _id . toString ( ) ,
266+ firstName : 'first-name' ,
267+ 268+ password : 'Newpassw0rd' ,
269+ token
270+ } ) ;
271+
272+ expect ( res ) . to . have . status ( OK ) ;
273+
274+ const auditEntry = await AuditLog . findOne ( { userId : testUser . _id } ) . lean ( ) ;
275+ expect ( auditEntry ) . to . exist ;
276+ expect ( auditEntry . action ) . to . equal ( AuditLogActions . CHANGE_PW ) ;
277+ expect ( auditEntry ) . to . not . have . property ( 'password' ) ;
278+ } ) ;
279+
280+ it ( 'Should create both audit logs when password and profile info are updated' , async ( ) => {
281+ const res = await test . sendPostRequestWithToken ( token , '/api/User/edit' , {
282+ _id : testUser . _id . toString ( ) ,
283+ firstName : 'Newname' ,
284+ 285+ password : 'Newpassword1' ,
286+ discordID : 'anotherID' ,
287+ token
288+ } ) ;
289+
290+ expect ( res ) . to . have . status ( OK ) ;
291+
292+ const changePwLog = await AuditLog . findOne ( { action : AuditLogActions . CHANGE_PW } ) . lean ( ) ;
293+ const updateUserLog = await AuditLog . findOne ( { action : AuditLogActions . UPDATE_USER } ) . lean ( ) ;
294+
295+ expect ( changePwLog ) . to . exist ;
296+ expect ( updateUserLog ) . to . exist ;
297+ } ) ;
298+
299+ it ( 'Should track profile changes in audit log with correct from/to values' , async ( ) => {
300+ const res = await test . sendPostRequestWithToken ( token , '/api/User/edit' , {
301+ _id : testUser . _id . toString ( ) ,
302+ firstName : 'Newname' ,
303+ lastName : 'Newlastname' ,
304+ 305+ password : 'Newpassword1' ,
306+ discordID : 'anotherID' ,
307+ major : 'Software Engineering' ,
308+ token
309+ } ) ;
310+
311+ expect ( res ) . to . have . status ( OK ) ;
312+
313+ const auditEntry = await AuditLog . findOne ( {
314+ action : AuditLogActions . UPDATE_USER ,
315+ documentId : testUser . _id
316+ } ) . lean ( ) ;
317+
318+ expect ( auditEntry ) . to . exist ;
319+ expect ( auditEntry . details ) . to . have . property ( 'fieldChanges' ) ;
320+
321+ // track firstName change
322+ expect ( auditEntry . details . fieldChanges ) . to . have . property ( 'firstName' ) ;
323+ expect ( auditEntry . details . fieldChanges . firstName ) . to . have . deep . equal ( {
324+ from : 'first-name' ,
325+ to : 'Newname'
326+ } ) ;
327+
328+ // track lastName change
329+ expect ( auditEntry . details . fieldChanges ) . to . have . property ( 'lastName' ) ;
330+ expect ( auditEntry . details . fieldChanges . lastName ) . to . have . deep . equal ( {
331+ from : 'last-name' ,
332+ to : 'Newlastname'
333+ } ) ;
334+
335+ // track major change
336+ expect ( auditEntry . details . fieldChanges ) . to . have . property ( 'major' ) ;
337+ expect ( auditEntry . details . fieldChanges . major ) . to . have . deep . equal ( {
338+ from : 'Computer Science' ,
339+ to : 'Software Engineering'
340+ } ) ;
341+
342+ // Should NOT track unchanged fields + password field
343+ expect ( auditEntry . details . fieldChanges ) . to . not . have . property ( 'password' ) ;
344+ expect ( auditEntry . details . fieldChanges ) . to . not . have . property ( 'email' ) ;
345+ } ) ;
254346
255- expect ( auditEntry ) . to . exist ;
256- expect ( auditEntry ) . to . have . property ( 'userId' ) ;
257- expect ( auditEntry ) . to . have . property ( 'action' , AuditLogActions . UPDATE_USER ) ;
258- expect ( auditEntry . details . updatedInfo ) . to . have . property ( 'password' , true ) ;
259- await AuditLog . deleteMany ( { } ) ;
347+ it ( 'Should not create audit log when no fields actually change' , async ( ) => {
348+ const res = await test . sendPostRequestWithToken ( token , '/api/User/edit' , {
349+ _id : testUser . _id . toString ( ) ,
350+ 351+ password : 'Passw0rd' ,
352+ firstName : 'first-name' ,
353+ lastName : 'last-name' ,
354+ major : 'Computer Science'
355+ } ) ;
356+
357+ expect ( res ) . to . have . status ( OK ) ;
358+
359+ const auditEntry = await AuditLog . findOne ( {
360+ action : AuditLogActions . UPDATE_USER || AuditLogActions . CHANGE_PW ,
361+ documentId : testUser . _id
362+ } ) . lean ( ) ;
363+
364+ expect ( auditEntry ) . to . not . exist ;
365+ } ) ;
260366 } ) ;
261367 } ) ;
262368
@@ -288,14 +394,27 @@ describe('User', () => {
288394 expect ( result ) . to . have . status ( NOT_FOUND ) ;
289395 } ) ;
290396 it ( 'Should return status code 200 if user is found' , async ( ) => {
291- const user = {
292- userID : id ,
293- token : token
294- } ;
295- setTokenStatus ( true ) ;
296- const result = await test . sendPostRequestWithToken ( token , '/api/User/getUserById' , user ) ;
297- expect ( result ) . to . have . status ( OK ) ;
298- result . body . should . not . have . property ( 'password' ) ;
397+
398+ const testUser = await new User ( {
399+ 400+ password : 'Passw0rd' ,
401+ firstName : 'Get' ,
402+ lastName : 'User' ,
403+ accessLevel : MEMBERSHIP_STATE . ADMIN ,
404+ emailVerified : true
405+ } ) . save ( ) ;
406+
407+ // Set token mock for this user
408+ setTokenStatus ( true , { _id : testUser . _id , accessLevel : MEMBERSHIP_STATE . ADMIN } ) ;
409+
410+ const res = await test . sendPostRequestWithToken ( '' , '/api/User/getUserById' , {
411+ userID : testUser . _id ,
412+ token : ''
413+ } ) ;
414+
415+ expect ( res ) . to . have . status ( OK ) ;
416+ res . body . should . have . property ( 'email' ) . eql ( '[email protected] ' ) ; 417+ res . body . should . not . have . property ( 'password' ) ;
299418 } ) ;
300419 } ) ;
301420
@@ -351,13 +470,17 @@ describe('User', () => {
351470
352471 it ( 'Should return statusCode 200 and a message ' +
353472 'if a user was deleted' , async ( ) => {
354- const user = {
473+ const user = await new User ( {
355474 _id : id ,
475+ 476+ password : 'Passw0rd' ,
477+ firstName : 'Delete' ,
478+ lastName : 'Me' ,
356479 token : token
357- } ;
358- setTokenStatus ( true ) ;
480+ } ) . save ( ) ;
481+ setTokenStatus ( true , { _id : user . _id , accesslevel : MEMBERSHIP_STATE . ADMIN } ) ;
359482 const result = await test . sendPostRequestWithToken (
360- token , '/api/User/delete' , user ) ;
483+ token , '/api/User/delete' , { _id : user . _id , token : token } ) ;
361484 expect ( result ) . to . have . status ( OK ) ;
362485 } ) ;
363486
0 commit comments