1
+ < << << << HEAD
1
2
const { GRPC_CHALLENGE_SERVER_HOST , GRPC_CHALLENGE_SERVER_PORT } = process . env ;
2
3
3
4
const {
@@ -22,6 +23,14 @@ const timelineTemplateService = require("../services/TimelineTemplateService");
22
23
// );
23
24
24
25
const phaseDomain = new PhaseDomain ( GRPC_CHALLENGE_SERVER_HOST , GRPC_CHALLENGE_SERVER_PORT ) ;
26
+ = === ===
27
+ const _ = require ( 'lodash' )
28
+ const uuid = require ( 'uuid/v4' )
29
+ const moment = require ( 'moment' )
30
+
31
+ const errors = require ( './errors' )
32
+ const helper = require ( './helper' )
33
+ >>> > >>> 21 bc5fc ( feat : challenge phase extension )
25
34
26
35
class ChallengePhaseHelper {
27
36
/**
@@ -30,6 +39,7 @@ class ChallengePhaseHelper {
30
39
* @param {Date } startDate the challenge start date
31
40
* @param {String } timelineTemplateId the timeline template id
32
41
*/
42
+ < << << << HEAD
33
43
async populatePhases ( phases , startDate , timelineTemplateId ) {
34
44
if ( _ . isUndefined ( timelineTemplateId ) ) {
35
45
throw new errors . BadRequestError ( `Invalid timeline template ID: ${ timelineTemplateId } ` ) ;
@@ -44,10 +54,26 @@ class ChallengePhaseHelper {
44
54
// auto populate phases
45
55
for ( const p of timelineTempate ) {
46
56
phases . push ( { ...p } ) ;
57
+ = === ===
58
+ async populatePhases ( phases , startDate , timelineTemplateId ) {
59
+ console . log ( 'populatePhases' , phases , startDate , timelineTemplateId )
60
+ if ( _ . isUndefined ( timelineTemplateId ) ) {
61
+ throw new errors . BadRequestError ( `Invalid timeline template ID: ${ timelineTemplateId } ` )
62
+ }
63
+
64
+ const { timelineTempate, timelineTemplateMap } = await this . getTemplateAndTemplateMap ( timelineTemplateId )
65
+ const { phaseDefinitionMap } = await this . getPhaseDefinitionsAndMap ( )
66
+
67
+ if ( ! phases || phases . length === 0 ) {
68
+ // auto populate phases
69
+ for ( const p of timelineTempate . phases ) {
70
+ phases . push ( { ...p } )
71
+ >>> > >>> 21 bc5fc ( feat : challenge phase extension )
47
72
}
48
73
}
49
74
50
75
for ( const p of phases ) {
76
+ < << << << HEAD
51
77
const phaseDefinition = phaseDefinitionMap . get ( p . phaseId ) ;
52
78
53
79
// TODO: move to domain-challenge
@@ -73,18 +99,45 @@ class ChallengePhaseHelper {
73
99
}
74
100
p . predecessor = phaseTemplate . predecessor ;
75
101
console . log ( "Setting predecessor" , p . predecessor , "for phase" , p . phaseId ) ;
102
+ = === ===
103
+ const phaseDefinition = phaseDefinitionMap . get ( p . phaseId )
104
+
105
+ p . id = uuid ( )
106
+ p . name = phaseDefinition . name
107
+ p . description = phaseDefinition . description
108
+
109
+ // set p.open based on current phase
110
+ const phaseTemplate = timelineTemplateMap . get ( p . phaseId )
111
+ if ( phaseTemplate ) {
112
+ if ( ! p . duration ) {
113
+ p . duration = phaseTemplate . defaultDuration
114
+ }
115
+
116
+ if ( phaseTemplate . predecessor ) {
117
+ const predecessor = _ . find ( phases , { phaseId : phaseTemplate . predecessor } )
118
+ if ( ! predecessor ) {
119
+ throw new errors . BadRequestError ( `Predecessor ${ phaseTemplate . predecessor } not found in given phases.` )
120
+ }
121
+ p . predecessor = phaseTemplate . predecessor
122
+ console . log ( 'Setting predecessor' , p . predecessor , 'for phase' , p . phaseId )
123
+ >>> > >>> 21 bc5fc ( feat : challenge phase extension )
76
124
}
77
125
}
78
126
}
79
127
80
128
// calculate dates
81
129
if ( ! startDate ) {
130
+ < << << << HEAD
82
131
return ;
132
+ === === =
133
+ return
134
+ >>> >>> > 21bc5fc (feat: challenge phase extension)
83
135
}
84
136
85
137
// sort phases by predecessor
86
138
phases . sort ( ( a , b ) => {
87
139
if ( a . predecessor === b . phaseId ) {
140
+ < << << << HEAD
88
141
return 1 ;
89
142
}
90
143
if ( b . predecessor === a . phaseId ) {
@@ -206,3 +259,97 @@ class ChallengePhaseHelper {
206
259
}
207
260
208
261
module . exports = new ChallengePhaseHelper ( ) ;
262
+ = === ===
263
+ return 1
264
+ }
265
+ if ( b . predecessor === a . phaseId ) {
266
+ return - 1
267
+ }
268
+ return 0
269
+ } )
270
+
271
+ let isSubmissionPhaseOpen = false
272
+ let postMortemPhaseIndex = - 1
273
+
274
+ for ( let p of phases ) {
275
+ const predecessor = timelineTemplateMap . get ( p . predecessor )
276
+
277
+ if ( predecessor == null ) {
278
+ p . scheduledStartDate = startDate
279
+ // p.actualStartDate = startDate
280
+
281
+ p . scheduledEndDate = moment ( p . actualStartDate != null ? p . actaulStartDate : startDate ) . add ( p . duration , 'seconds' ) . toDate ( )
282
+ } else {
283
+ const precedecessorPhase = _ . find ( phases , { phaseId : predecessor . phaseId } )
284
+ if ( precedecessorPhase == null ) {
285
+ throw new errors . BadRequestError ( `Predecessor ${ predecessor . phaseId } not found in given phases.` )
286
+ }
287
+ let phaseEndDate = moment ( precedecessorPhase . scheduledEndDate )
288
+ if ( precedecessorPhase . actualEndDate != null && moment ( precedecessorPhase . actualEndDate ) . isAfter ( phaseEndDate ) ) {
289
+ phaseEndDate = moment ( precedecessorPhase . actualEndDate )
290
+ } else {
291
+ phaseEndDate = moment ( precedecessorPhase . scheduledEndDate )
292
+ }
293
+
294
+ p . scheduledStartDate = phaseEndDate . toDate ( )
295
+ p . scheduledEndDate = moment ( p . scheduledStartDate ) . add ( p . duration , 'seconds' ) . toDate ( )
296
+ }
297
+ p . isOpen = moment ( ) . isBetween ( p . scheduledStartDate , p . scheduledEndDate )
298
+ if ( p . name === 'Submission' ) {
299
+ isSubmissionPhaseOpen = p . isOpen
300
+ }
301
+ if ( p . name === 'Post-Mortem' ) {
302
+ postMortemPhaseIndex = _ . findIndex ( phases , { phaseId : p . phaseId } )
303
+ }
304
+ }
305
+
306
+ // if submission phase is open, remove post-mortem phase
307
+ if ( isSubmissionPhaseOpen && postMortemPhaseIndex > - 1 ) {
308
+ phases . splice ( postMortemPhaseIndex , 1 )
309
+ }
310
+
311
+ // phases.sort((a, b) => moment(a.scheduledStartDate).isAfter(b.scheduledStartDate))
312
+ }
313
+
314
+ async validatePhases ( phases ) {
315
+ if ( ! phases || phases . length === 0 ) {
316
+ return
317
+ }
318
+ const records = await helper . scan ( 'Phase' )
319
+ const map = new Map ( )
320
+ _ . each ( records , ( r ) => {
321
+ map . set ( r . id , r )
322
+ } )
323
+ const invalidPhases = _ . filter ( phases , ( p ) => ! map . has ( p . phaseId ) )
324
+ if ( invalidPhases . length > 0 ) {
325
+ throw new errors . BadRequestError (
326
+ `The following phases are invalid: ${ toString ( invalidPhases ) } `
327
+ )
328
+ }
329
+ }
330
+
331
+ async getPhaseDefinitionsAndMap ( ) {
332
+ const records = await helper . scan ( 'Phase' )
333
+ const map = new Map ( )
334
+ _ . each ( records , ( r ) => {
335
+ map . set ( r . id , r )
336
+ } )
337
+ return { phaseDefinitions : records , phaseDefinitionMap : map }
338
+ }
339
+
340
+ async getTemplateAndTemplateMap ( timelineTemplateId ) {
341
+ const records = await helper . getById ( 'TimelineTemplate' , timelineTemplateId )
342
+ const map = new Map ( )
343
+ _ . each ( records . phases , ( r ) => {
344
+ map . set ( r . phaseId , r )
345
+ } )
346
+
347
+ return {
348
+ timelineTempate : records . phases ,
349
+ timelineTemplateMap : map
350
+ }
351
+ }
352
+ }
353
+
354
+ module . exports = new ChallengePhaseHelper ( )
355
+ >>> > >>> 21 bc5fc ( feat : challenge phase extension )
0 commit comments