Skip to content

Commit cac71dd

Browse files
authored
Merge pull request #559 from topcoder-platform/dev
feat: filter, sort type, challenge-track and challenge-type delete api
2 parents 4823b03 + d6ff83c commit cac71dd

12 files changed

+267
-8
lines changed

.circleci/config.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,7 @@ workflows:
7171
filters:
7272
branches:
7373
only:
74-
- develop
75-
- feature/PLAT-2032
74+
- dev
7675

7776
# Production builds are exectuted only on tagged commits to the
7877
# master branch.

app-constants.js

+8
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ const validChallengeParams = {
4545
StartDate: 'startDate',
4646
ProjectId: 'projectId',
4747
Name: 'name',
48+
Type: 'type',
49+
NumOfSubmissions: 'numOfSubmissions',
50+
NumOfRegistrants: 'numOfRegistrants',
51+
Status: 'status',
4852
TypeId: 'typeId',
4953
Prizes: 'overview.totalPrizes'
5054
}
@@ -64,6 +68,10 @@ const Topics = {
6468
ChallengeDeleted: 'challenge.notification.delete',
6569
ChallengeTypeCreated: 'test.new.bus.events', // 'challenge.action.type.created',
6670
ChallengeTypeUpdated: 'test.new.bus.events', // 'challenge.action.type.updated',
71+
ChallengeTypeDeleted: 'test.new.bus.events', // 'challenge.action.type.deleted',
72+
ChallengeTrackCreated: 'test.new.bus.events', // 'challenge.action.track.created',
73+
ChallengeTrackUpdated: 'test.new.bus.events', // 'challenge.action.track.updated',
74+
ChallengeTrackDeleted: 'test.new.bus.events', // 'challenge.action.track.deleted',
6775
ChallengePhaseCreated: 'test.new.bus.events', // 'challenge.action.phase.created',
6876
ChallengePhaseUpdated: 'test.new.bus.events', // 'challenge.action.phase.updated',
6977
ChallengePhaseDeleted: 'test.new.bus.events', // 'challenge.action.phase.deleted',

docs/swagger.yaml

+84-1
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,9 @@ paths:
360360
projectId,
361361
name,
362362
typeId,
363+
numOfRegistrants,
364+
numOfSubmissions,
365+
status,
363366
overview.totalPrizes,
364367
]
365368
- name: sortOrder
@@ -908,6 +911,46 @@ paths:
908911
description: Internal Server error
909912
schema:
910913
$ref: "#/definitions/ErrorModel"
914+
delete:
915+
tags:
916+
- ChallengeTypes
917+
description: Delete the challenge type with specified id.
918+
security:
919+
- bearer: []
920+
produces:
921+
- application/json
922+
parameters:
923+
- name: challengeTypeId
924+
in: path
925+
required: true
926+
type: string
927+
format: UUID
928+
description: The id of challengeType to be deleted
929+
responses:
930+
"200":
931+
description: Deleted - The request was successful and the resource is returned.
932+
schema:
933+
$ref: "#/definitions/ChallengeType"
934+
"400":
935+
description: Bad request. Request parameters were invalid.
936+
schema:
937+
$ref: "#/definitions/ErrorModel"
938+
"401":
939+
description: Unauthorized. Fail to authenticate the requester.
940+
schema:
941+
$ref: "#/definitions/ErrorModel"
942+
"403":
943+
description: Forbidden. The requester does not have the correct permission to delete the challenge type.
944+
schema:
945+
$ref: "#/definitions/ErrorModel"
946+
"404":
947+
description: Not Found. Challenge type not found
948+
schema:
949+
$ref: "#/definitions/ErrorModel"
950+
"500":
951+
description: Internal Server Error
952+
schema:
953+
$ref: "#/definitions/ErrorModel"
911954
/challenge-tracks:
912955
get:
913956
tags:
@@ -1143,6 +1186,46 @@ paths:
11431186
description: Internal Server Error
11441187
schema:
11451188
$ref: "#/definitions/ErrorModel"
1189+
delete:
1190+
tags:
1191+
- ChallengeTracks
1192+
description: Delete the challenge track with specified id.
1193+
security:
1194+
- bearer: []
1195+
produces:
1196+
- application/json
1197+
parameters:
1198+
- name: challengeTrackId
1199+
in: path
1200+
required: true
1201+
type: string
1202+
format: UUID
1203+
description: The id of challengeTrack to be deleted.
1204+
responses:
1205+
"200":
1206+
description: Deleted - The request was successful and the resource is returned.
1207+
schema:
1208+
$ref: "#/definitions/ChallengeTrack"
1209+
"400":
1210+
description: Bad request. Request parameters were invalid.
1211+
schema:
1212+
$ref: "#/definitions/ErrorModel"
1213+
"401":
1214+
description: Unauthorized. Fail to authenticate the requester.
1215+
schema:
1216+
$ref: "#/definitions/ErrorModel"
1217+
"403":
1218+
description: Forbidden. The requester does not have the correct permission to delete the challenge track.
1219+
schema:
1220+
$ref: "#/definitions/ErrorModel"
1221+
"404":
1222+
description: Not Found. Challenge track not found
1223+
schema:
1224+
$ref: "#/definitions/ErrorModel"
1225+
"500":
1226+
description: Internal Server Error
1227+
schema:
1228+
$ref: "#/definitions/ErrorModel"
11461229
/challenge-phases:
11471230
get:
11481231
tags:
@@ -2927,7 +3010,7 @@ definitions:
29273010
type: boolean
29283011
selfServiceCopilot:
29293012
type: string
2930-
cancelReason:
3013+
cancelReason:
29313014
type: string
29323015
billing:
29333016
type: object

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/init-es.js

+18
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,24 @@ const initES = async () => {
4141
},
4242
normalizer: 'custom_sort_normalizer'
4343
},
44+
status: {
45+
type: 'keyword',
46+
fields: {
47+
text: {
48+
type: 'text'
49+
}
50+
},
51+
normalizer: 'custom_sort_normalizer'
52+
},
53+
type: {
54+
type: 'keyword',
55+
fields: {
56+
text: {
57+
type: 'text'
58+
}
59+
},
60+
normalizer: 'custom_sort_normalizer'
61+
},
4462
prizeSets: {
4563
properties: {
4664
type: { type: 'text' },

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/ChallengeService.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ async function searchChallenges (currentUser, criteria) {
165165
if (criteria.types) {
166166
for (const t of criteria.types) {
167167
const typeSearchRes = await ChallengeTypeService.searchChallengeTypes({ abbreviation: t })
168-
if (typeSearchRes.total > 0) {
168+
if (typeSearchRes.total > 0 || criteria.types.length === 1) {
169169
includedTypeIds.push(_.get(typeSearchRes, 'result[0].id'))
170170
}
171171
}

src/services/ChallengeTrackService.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,30 @@ 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 record = await helper.getById('ChallengeTrack', id)
182+
await record.delete()
183+
// post bus event
184+
await helper.postBusEvent(constants.Topics.ChallengeTrackDeleted, record)
185+
return record
186+
}
187+
188+
deleteChallengeTrack.schema = {
189+
id: Joi.id()
190+
}
191+
175192
module.exports = {
176193
searchChallengeTracks,
177194
createChallengeTrack,
178195
getChallengeTrack,
179196
fullyUpdateChallengeTrack,
180-
partiallyUpdateChallengeTrack
197+
partiallyUpdateChallengeTrack,
198+
deleteChallengeTrack
181199
}
182200

183201
// logger.buildService(module.exports)

src/services/ChallengeTypeService.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,30 @@ 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 ret = await helper.getById('ChallengeType', id)
160+
await ret.delete()
161+
// post bus event
162+
await helper.postBusEvent(constants.Topics.ChallengeTypeDeleted, ret)
163+
return ret
164+
}
165+
166+
deleteChallengeType.schema = {
167+
id: Joi.id()
168+
}
169+
153170
module.exports = {
154171
searchChallengeTypes,
155172
createChallengeType,
156173
getChallengeType,
157174
fullyUpdateChallengeType,
158-
partiallyUpdateChallengeType
175+
partiallyUpdateChallengeType,
176+
deleteChallengeType
159177
}
160178

161179
// 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
})

0 commit comments

Comments
 (0)