@@ -10,6 +10,7 @@ const constants = require("../../app-constants");
10
10
const axios = require ( "axios" ) ;
11
11
const { getM2MToken } = require ( "./m2m-helper" ) ;
12
12
const { hasAdminRole } = require ( "./role-helper" ) ;
13
+ const { ensureAcessibilityToModifiedGroups } = require ( "./group-helper" ) ;
13
14
14
15
class ChallengeHelper {
15
16
/**
@@ -45,7 +46,7 @@ class ChallengeHelper {
45
46
* @param {String } projectId the project id
46
47
* @param {String } currentUser the user
47
48
*/
48
- async ensureProjectExist ( projectId , currentUser ) {
49
+ static async ensureProjectExist ( projectId , currentUser ) {
49
50
let token = await getM2MToken ( ) ;
50
51
const url = `${ config . PROJECTS_API_URL } /${ projectId } ` ;
51
52
try {
@@ -98,6 +99,252 @@ class ChallengeHelper {
98
99
// check groups authorization
99
100
await helper . ensureAccessibleByGroupsAccess ( currentUser , challenge ) ;
100
101
}
102
+
103
+ async validateChallengeUpdateRequest ( currentUser , challenge , data ) {
104
+ if ( process . env . LOCAL != "true" ) {
105
+ await helper . ensureUserCanModifyChallenge ( currentUser , challenge ) ;
106
+ }
107
+
108
+ helper . ensureNoDuplicateOrNullElements ( data . tags , "tags" ) ;
109
+ helper . ensureNoDuplicateOrNullElements ( data . groups , "groups" ) ;
110
+
111
+ if ( data . projectId ) {
112
+ await ChallengeHelper . ensureProjectExist ( data . projectId , currentUser ) ;
113
+ }
114
+
115
+ // check groups access to be updated group values
116
+ if ( data . groups ) {
117
+ await ensureAcessibilityToModifiedGroups ( currentUser , data , challenge ) ;
118
+ }
119
+
120
+ // Ensure descriptionFormat is either 'markdown' or 'html'
121
+ if ( data . descriptionFormat && ! _ . includes ( [ "markdown" , "html" ] , data . descriptionFormat ) ) {
122
+ throw new errors . BadRequestError ( "The property 'descriptionFormat' must be either 'markdown' or 'html'" ) ;
123
+ }
124
+
125
+ // Ensure unchangeable fields are not changed
126
+ if (
127
+ _ . get ( challenge , "legacy.track" ) &&
128
+ _ . get ( data , "legacy.track" ) &&
129
+ _ . get ( challenge , "legacy.track" ) !== _ . get ( data , "legacy.track" )
130
+ ) {
131
+ throw new errors . ForbiddenError ( "Cannot change legacy.track" ) ;
132
+ }
133
+
134
+ if (
135
+ _ . get ( challenge , "trackId" ) &&
136
+ _ . get ( data , "trackId" ) &&
137
+ _ . get ( challenge , "trackId" ) !== _ . get ( data , "trackId" )
138
+ ) {
139
+ throw new errors . ForbiddenError ( "Cannot change trackId" ) ;
140
+ }
141
+
142
+ if (
143
+ _ . get ( challenge , "typeId" ) &&
144
+ _ . get ( data , "typeId" ) &&
145
+ _ . get ( challenge , "typeId" ) !== _ . get ( data , "typeId" )
146
+ ) {
147
+ throw new errors . ForbiddenError ( "Cannot change typeId" ) ;
148
+ }
149
+
150
+ if (
151
+ _ . get ( challenge , "legacy.pureV5Task" ) &&
152
+ _ . get ( data , "legacy.pureV5Task" ) &&
153
+ _ . get ( challenge , "legacy.pureV5Task" ) !== _ . get ( data , "legacy.pureV5Task" )
154
+ ) {
155
+ throw new errors . ForbiddenError ( "Cannot change legacy.pureV5Task" ) ;
156
+ }
157
+
158
+ if (
159
+ _ . get ( challenge , "legacy.pureV5" ) &&
160
+ _ . get ( data , "legacy.pureV5" ) &&
161
+ _ . get ( challenge , "legacy.pureV5" ) !== _ . get ( data , "legacy.pureV5" )
162
+ ) {
163
+ throw new errors . ForbiddenError ( "Cannot change legacy.pureV5" ) ;
164
+ }
165
+
166
+ if (
167
+ _ . get ( challenge , "legacy.selfService" ) &&
168
+ _ . get ( data , "legacy.selfService" ) &&
169
+ _ . get ( challenge , "legacy.selfService" ) !== _ . get ( data , "legacy.selfService" )
170
+ ) {
171
+ throw new errors . ForbiddenError ( "Cannot change legacy.selfService" ) ;
172
+ }
173
+
174
+ if (
175
+ ( challenge . status === constants . challengeStatuses . Completed ||
176
+ challenge . status === constants . challengeStatuses . Cancelled ) &&
177
+ data . status &&
178
+ data . status !== challenge . status &&
179
+ data . status !== constants . challengeStatuses . CancelledClientRequest
180
+ ) {
181
+ throw new errors . BadRequestError (
182
+ `Cannot change ${ challenge . status } challenge status to ${ data . status } status`
183
+ ) ;
184
+ }
185
+
186
+ if (
187
+ data . winners &&
188
+ data . winners . length > 0 &&
189
+ challenge . status !== constants . challengeStatuses . Completed &&
190
+ data . status !== constants . challengeStatuses . Completed
191
+ ) {
192
+ throw new errors . BadRequestError (
193
+ `Cannot set winners for challenge with non-completed ${ challenge . status } status`
194
+ ) ;
195
+ }
196
+ }
197
+
198
+ sanitizeRepeatedFieldsInUpdateRequest ( data ) {
199
+ if ( data . winners != null ) {
200
+ data . winnerUpdate = {
201
+ winners : data . winners ,
202
+ } ;
203
+ delete data . winners ;
204
+ }
205
+
206
+ if ( data . discussions != null ) {
207
+ data . discussionUpdate = {
208
+ discussions : data . discussions ,
209
+ } ;
210
+ delete data . discussions ;
211
+ }
212
+
213
+ if ( data . metadata != null ) {
214
+ data . metadataUpdate = {
215
+ metadata : data . metadata ,
216
+ } ;
217
+ delete data . metadata ;
218
+ }
219
+
220
+ if ( data . phases != null ) {
221
+ data . phaseUpdate = {
222
+ phases : data . phases ,
223
+ } ;
224
+ delete data . phases ;
225
+ }
226
+
227
+ if ( data . events != null ) {
228
+ data . eventUpdate = {
229
+ events : data . events ,
230
+ } ;
231
+ delete data . events ;
232
+ }
233
+
234
+ if ( data . terms != null ) {
235
+ data . termUpdate = {
236
+ terms : data . terms ,
237
+ } ;
238
+ delete data . terms ;
239
+ }
240
+
241
+ if ( data . prizeSets != null ) {
242
+ data . prizeSetUpdate = {
243
+ prizeSets : data . prizeSets ,
244
+ } ;
245
+ delete data . prizeSets ;
246
+ }
247
+
248
+ if ( data . tags != null ) {
249
+ data . tagUpdate = {
250
+ tags : data . tags ,
251
+ } ;
252
+ delete data . tags ;
253
+ }
254
+
255
+ if ( data . attachments != null ) {
256
+ data . attachmentUpdate = {
257
+ attachments : data . attachments ,
258
+ } ;
259
+ delete data . attachments ;
260
+ }
261
+
262
+ if ( data . groups != null ) {
263
+ data . groupUpdate = {
264
+ groups : data . groups ,
265
+ } ;
266
+ delete data . groups ;
267
+ }
268
+
269
+ return data ;
270
+ }
271
+
272
+ enrichChallengeForResponse ( challenge , track , type ) {
273
+ if ( challenge . phases && challenge . phases . length > 0 ) {
274
+ const registrationPhase = _ . find ( challenge . phases , ( p ) => p . name === "Registration" ) ;
275
+ const submissionPhase = _ . find ( challenge . phases , ( p ) => p . name === "Submission" ) ;
276
+
277
+ challenge . currentPhase = challenge . phases
278
+ . slice ( )
279
+ . reverse ( )
280
+ . find ( ( phase ) => phase . isOpen ) ;
281
+
282
+ challenge . currentPhaseNames = _ . map (
283
+ _ . filter ( challenge . phases , ( p ) => p . isOpen === true ) ,
284
+ "name"
285
+ ) ;
286
+
287
+ if ( registrationPhase ) {
288
+ challenge . registrationStartDate =
289
+ registrationPhase . actualStartDate || registrationPhase . scheduledStartDate ;
290
+ challenge . registrationEndDate =
291
+ registrationPhase . actualEndDate || registrationPhase . scheduledEndDate ;
292
+ }
293
+ if ( submissionPhase ) {
294
+ challenge . submissionStartDate =
295
+ submissionPhase . actualStartDate || submissionPhase . scheduledStartDate ;
296
+
297
+ challenge . submissionEndDate =
298
+ submissionPhase . actualEndDate || submissionPhase . scheduledEndDate ;
299
+ }
300
+ }
301
+
302
+ challenge . created = new Date ( challenge . created ) . toISOString ( ) ;
303
+ challenge . updated = new Date ( challenge . updated ) . toISOString ( ) ;
304
+ challenge . startDate = new Date ( challenge . startDate ) . toISOString ( ) ;
305
+ challenge . endDate = new Date ( challenge . endDate ) . toISOString ( ) ;
306
+
307
+ if ( track ) {
308
+ challenge . track = track . name ;
309
+ }
310
+
311
+ if ( type ) {
312
+ challenge . type = type . name ;
313
+ }
314
+
315
+ challenge . metadata = challenge . metadata . map ( ( m ) => {
316
+ try {
317
+ m . value = JSON . stringify ( JSON . parse ( m . value ) ) ; // when we update how we index data, make this a JSON field
318
+ } catch ( err ) {
319
+ // do nothing
320
+ }
321
+ return m ;
322
+ } ) ;
323
+ }
324
+
325
+ convertPrizeSetValuesToCents ( prizeSets ) {
326
+ prizeSets . forEach ( ( prizeSet ) => {
327
+ prizeSet . prizes . forEach ( ( prize ) => {
328
+ prize . amountInCents = prize . value * 100 ;
329
+ delete prize . value ;
330
+ } ) ;
331
+ } ) ;
332
+ }
333
+
334
+ convertPrizeSetValuesToDollars ( prizeSets , overview ) {
335
+ prizeSets . forEach ( ( prizeSet ) => {
336
+ prizeSet . prizes . forEach ( ( prize ) => {
337
+ if ( prize . amountInCents != null ) {
338
+ prize . value = prize . amountInCents / 100 ;
339
+ delete prize . amountInCents ;
340
+ }
341
+ } ) ;
342
+ } ) ;
343
+ if ( overview && overview . totalPrizesInCents ) {
344
+ overview . totalPrizes = overview . totalPrizesInCents / 100 ;
345
+ delete overview . totalPrizesInCents ;
346
+ }
347
+ }
101
348
}
102
349
103
350
module . exports = new ChallengeHelper ( ) ;
0 commit comments