Skip to content

Commit ad1bdb8

Browse files
jmgasperrakibansary
authored andcommitted
Allow for admin deletion of challenge tracks and types
#519
1 parent 4823b03 commit ad1bdb8

9 files changed

+243
-4
lines changed

app-constants.js

+4
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ const Topics = {
6464
ChallengeDeleted: 'challenge.notification.delete',
6565
ChallengeTypeCreated: 'test.new.bus.events', // 'challenge.action.type.created',
6666
ChallengeTypeUpdated: 'test.new.bus.events', // 'challenge.action.type.updated',
67+
ChallengeTypeDeleted: 'test.new.bus.events', // 'challenge.action.type.deleted',
68+
ChallengeTrackCreated: 'test.new.bus.events', // 'challenge.action.track.created',
69+
ChallengeTrackUpdated: 'test.new.bus.events', // 'challenge.action.track.updated',
70+
ChallengeTrackDeleted: 'test.new.bus.events', // 'challenge.action.track.deleted',
6771
ChallengePhaseCreated: 'test.new.bus.events', // 'challenge.action.phase.created',
6872
ChallengePhaseUpdated: 'test.new.bus.events', // 'challenge.action.phase.updated',
6973
ChallengePhaseDeleted: 'test.new.bus.events', // 'challenge.action.phase.deleted',

docs/swagger.yaml

+80
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,46 @@ paths:
908908
description: Internal Server error
909909
schema:
910910
$ref: "#/definitions/ErrorModel"
911+
delete:
912+
tags:
913+
- ChallengeTypes
914+
description: Delete the challenge type with specified id.
915+
security:
916+
- bearer: []
917+
produces:
918+
- application/json
919+
parameters:
920+
- name: challengeTypeId
921+
in: path
922+
required: true
923+
type: string
924+
format: UUID
925+
description: The id of challengeType to be deleted
926+
responses:
927+
"200":
928+
description: Deleted - The request was successful and the resource is returned.
929+
schema:
930+
$ref: "#/definitions/ChallengeType"
931+
"400":
932+
description: Bad request. Request parameters were invalid.
933+
schema:
934+
$ref: "#/definitions/ErrorModel"
935+
"401":
936+
description: Unauthorized. Fail to authenticate the requester.
937+
schema:
938+
$ref: "#/definitions/ErrorModel"
939+
"403":
940+
description: Forbidden. The requester does not have the correct permission to delete the challenge type.
941+
schema:
942+
$ref: "#/definitions/ErrorModel"
943+
"404":
944+
description: Not Found. Challenge type not found
945+
schema:
946+
$ref: "#/definitions/ErrorModel"
947+
"500":
948+
description: Internal Server Error
949+
schema:
950+
$ref: "#/definitions/ErrorModel"
911951
/challenge-tracks:
912952
get:
913953
tags:
@@ -1143,6 +1183,46 @@ paths:
11431183
description: Internal Server Error
11441184
schema:
11451185
$ref: "#/definitions/ErrorModel"
1186+
delete:
1187+
tags:
1188+
- ChallengeTracks
1189+
description: Delete the challenge track with specified id.
1190+
security:
1191+
- bearer: []
1192+
produces:
1193+
- application/json
1194+
parameters:
1195+
- name: challengeTrackId
1196+
in: path
1197+
required: true
1198+
type: string
1199+
format: UUID
1200+
description: The id of challengeTrack to be deleted.
1201+
responses:
1202+
"200":
1203+
description: Deleted - The request was successful and the resource is returned.
1204+
schema:
1205+
$ref: "#/definitions/ChallengeTrack"
1206+
"400":
1207+
description: Bad request. Request parameters were invalid.
1208+
schema:
1209+
$ref: "#/definitions/ErrorModel"
1210+
"401":
1211+
description: Unauthorized. Fail to authenticate the requester.
1212+
schema:
1213+
$ref: "#/definitions/ErrorModel"
1214+
"403":
1215+
description: Forbidden. The requester does not have the correct permission to delete the challenge track.
1216+
schema:
1217+
$ref: "#/definitions/ErrorModel"
1218+
"404":
1219+
description: Not Found. Challenge track not found
1220+
schema:
1221+
$ref: "#/definitions/ErrorModel"
1222+
"500":
1223+
description: Internal Server Error
1224+
schema:
1225+
$ref: "#/definitions/ErrorModel"
11461226
/challenge-phases:
11471227
get:
11481228
tags:

src/controllers/ChallengeTrackController.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,21 @@ async function partiallyUpdateChallengeTrack (req, res) {
5656
res.send(result)
5757
}
5858

59+
/**
60+
* Delete challenge track
61+
* @param {Object} req the request
62+
* @param {Object} res the response
63+
*/
64+
async function deleteChallengeTrack (req, res) {
65+
const result = await service.deleteChallengeTrack(req.params.challengeTrackId)
66+
res.send(result)
67+
}
68+
5969
module.exports = {
6070
searchChallengeTracks,
6171
createChallengeTrack,
6272
getChallengeTrack,
6373
fullyUpdateChallengeTrack,
64-
partiallyUpdateChallengeTrack
74+
partiallyUpdateChallengeTrack,
75+
deleteChallengeTrack
6576
}

src/controllers/ChallengeTypeController.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,21 @@ async function partiallyUpdateChallengeType (req, res) {
5656
res.send(result)
5757
}
5858

59+
/**
60+
* Delete challenge type
61+
* @param {Object} req the request
62+
* @param {Object} res the response
63+
*/
64+
async function deleteChallengeType (req, res) {
65+
const result = await service.deleteChallengeType(req.params.challengeTypeId)
66+
res.send(result)
67+
}
68+
5969
module.exports = {
6070
searchChallengeTypes,
6171
createChallengeType,
6272
getChallengeType,
6373
fullyUpdateChallengeType,
64-
partiallyUpdateChallengeType
74+
partiallyUpdateChallengeType,
75+
deleteChallengeType
6576
}

src/routes.js

+14
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ module.exports = {
113113
auth: 'jwt',
114114
access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager],
115115
scopes: [UPDATE, ALL]
116+
},
117+
delete: {
118+
controller: 'ChallengeTypeController',
119+
method: 'deleteChallengeType',
120+
auth: 'jwt',
121+
access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager],
122+
scopes: [DELETE, ALL]
116123
}
117124
},
118125
'/challenge-tracks': {
@@ -146,6 +153,13 @@ module.exports = {
146153
auth: 'jwt',
147154
access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager],
148155
scopes: [UPDATE, ALL]
156+
},
157+
delete: {
158+
controller: 'ChallengeTrackController',
159+
method: 'deleteChallengeTrack',
160+
auth: 'jwt',
161+
access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager],
162+
scopes: [DELETE, ALL]
149163
}
150164
},
151165
'/challenge-timelines': {

src/services/ChallengeTrackService.js

+21-1
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,32 @@ partiallyUpdateChallengeTrack.schema = {
172172
}).required()
173173
}
174174

175+
/**
176+
* Delete challenge track.
177+
* @param {String} id the challenge track id
178+
* @return {Object} the deleted challenge track
179+
*/
180+
async function deleteChallengeTrack (id) {
181+
const span = await logger.startSpan('ChallengeTrackService.deleteChallengeTrack')
182+
const record = await helper.getById('ChallengeTrack', id)
183+
await record.delete()
184+
// post bus event
185+
await helper.postBusEvent(constants.Topics.ChallengeTrackDeleted, record)
186+
await logger.endSpan(span)
187+
return record
188+
}
189+
190+
deleteChallengeTrack.schema = {
191+
id: Joi.id()
192+
}
193+
175194
module.exports = {
176195
searchChallengeTracks,
177196
createChallengeTrack,
178197
getChallengeTrack,
179198
fullyUpdateChallengeTrack,
180-
partiallyUpdateChallengeTrack
199+
partiallyUpdateChallengeTrack,
200+
deleteChallengeTrack
181201
}
182202

183203
// logger.buildService(module.exports)

src/services/ChallengeTypeService.js

+21-1
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,32 @@ partiallyUpdateChallengeType.schema = {
150150
}).required()
151151
}
152152

153+
/**
154+
* Delete challenge type.
155+
* @param {String} id the challenge type id
156+
* @returns {Object} the deleted challenge type
157+
*/
158+
async function deleteChallengeType (id) {
159+
const span = await logger.startSpan('ChallengeTypeService.deleteChallengeType')
160+
const ret = await helper.getById('ChallengeType', id)
161+
await ret.delete()
162+
// post bus event
163+
await helper.postBusEvent(constants.Topics.ChallengeTypeDeleted, ret)
164+
await logger.endSpan(span)
165+
return ret
166+
}
167+
168+
deleteChallengeType.schema = {
169+
id: Joi.id()
170+
}
171+
153172
module.exports = {
154173
searchChallengeTypes,
155174
createChallengeType,
156175
getChallengeType,
157176
fullyUpdateChallengeType,
158-
partiallyUpdateChallengeType
177+
partiallyUpdateChallengeType,
178+
deleteChallengeType
159179
}
160180

161181
// logger.buildService(module.exports)

test/e2e/challenge.type.api.test.js

+42
Original file line numberDiff line numberDiff line change
@@ -665,4 +665,46 @@ describe('challenge type API E2E tests', () => {
665665
should.equal(response.body.message, '"legacyId" must be a number')
666666
})
667667
})
668+
669+
describe('remove challenge type API tests', () => {
670+
it('remove challenge type - forbidden', async () => {
671+
const response = await chai.request(app)
672+
.delete(`${basePath}/${id}`)
673+
.set('Authorization', `Bearer ${config.USER_TOKEN}`)
674+
should.equal(response.status, 403)
675+
should.equal(response.body.message, 'You are not allowed to perform this action!')
676+
})
677+
678+
it('remove challenge type successfully', async () => {
679+
const response = await chai.request(app)
680+
.delete(`${basePath}/${id}`)
681+
.set('Authorization', `Bearer ${config.ADMIN_TOKEN}`)
682+
should.equal(response.status, 200)
683+
should.equal(response.body.id, id)
684+
})
685+
686+
it('remove challenge type - not found 1', async () => {
687+
const response = await chai.request(app)
688+
.delete(`${basePath}/${id}`)
689+
.set('Authorization', `Bearer ${config.ADMIN_TOKEN}`)
690+
should.equal(response.status, 404)
691+
should.equal(response.body.message, `ChallengeType with id: ${id} doesn't exist`)
692+
})
693+
694+
it('remove challenge type - not found 2', async () => {
695+
const response = await chai.request(app)
696+
.delete(`${basePath}/${notFoundId}`)
697+
.set('Authorization', `Bearer ${config.ADMIN_TOKEN}`)
698+
should.equal(response.status, 404)
699+
should.equal(response.body.message, `ChallengeType with id: ${notFoundId} doesn't exist`)
700+
})
701+
702+
it('remove challenge type - invalid id', async () => {
703+
const response = await chai.request(app)
704+
.delete(`${basePath}/invalid`)
705+
.set('Authorization', `Bearer ${config.ADMIN_TOKEN}`)
706+
should.equal(response.status, 400)
707+
should.equal(response.body.message, '"challengeTypeId" must be a valid GUID')
708+
})
709+
})
668710
})

test/unit/ChallengeTypeService.test.js

+37
Original file line numberDiff line numberDiff line change
@@ -630,4 +630,41 @@ describe('challenge type service unit tests', () => {
630630
throw new Error('should not reach here')
631631
})
632632
})
633+
634+
describe('remove challenge type tests', () => {
635+
it('remove challenge type successfully', async () => {
636+
const result = await service.deleteChallengeType(id2)
637+
should.equal(result.id, id2)
638+
})
639+
640+
it('remove challenge type - not found 1', async () => {
641+
try {
642+
await service.deleteChallengeType(notFoundId)
643+
} catch (e) {
644+
should.equal(e.message, `ChallengeType with id: ${notFoundId} doesn't exist`)
645+
return
646+
}
647+
throw new Error('should not reach here')
648+
})
649+
650+
it('remove challenge type - not found 2', async () => {
651+
try {
652+
await service.deleteChallengeType(id2)
653+
} catch (e) {
654+
should.equal(e.message, `ChallengeType with id: ${id2} doesn't exist`)
655+
return
656+
}
657+
throw new Error('should not reach here')
658+
})
659+
660+
it('remove challenge type - invalid id', async () => {
661+
try {
662+
await service.deleteChallengeType('invalid')
663+
} catch (e) {
664+
should.equal(e.message.indexOf('"challengeType" must be a valid GUID') >= 0, true)
665+
return
666+
}
667+
throw new Error('should not reach here')
668+
})
669+
})
633670
})

0 commit comments

Comments
 (0)