1
1
const { GRPC_CHALLENGE_SERVER_HOST , GRPC_CHALLENGE_SERVER_PORT } = process . env ;
2
2
3
3
const {
4
- DomainHelper : { getLookupCriteria , getScanCriteria } ,
4
+ DomainHelper : { getScanCriteria } ,
5
5
} = require ( "@topcoder-framework/lib-common" ) ;
6
6
7
- const { PhaseDomain, TimelineTemplateDomain } = require ( "@topcoder-framework/domain-challenge" ) ;
7
+ const { PhaseDomain } = require ( "@topcoder-framework/domain-challenge" ) ;
8
8
9
9
const _ = require ( "lodash" ) ;
10
10
@@ -13,153 +13,13 @@ const moment = require("moment");
13
13
14
14
const errors = require ( "./errors" ) ;
15
15
16
- const phaseService = require ( "../services/PhaseService" ) ;
17
16
const timelineTemplateService = require ( "../services/TimelineTemplateService" ) ;
18
17
19
18
const phaseDomain = new PhaseDomain ( GRPC_CHALLENGE_SERVER_HOST , GRPC_CHALLENGE_SERVER_PORT ) ;
20
19
21
20
class ChallengePhaseHelper {
22
- /**
23
- * Populate challenge phases.
24
- * @param {Array } phases the phases to populate
25
- * @param {Date } startDate the challenge start date
26
- * @param {String } timelineTemplateId the timeline template id
27
- */
28
- async populatePhases ( phases , startDate , timelineTemplateId ) {
29
- if ( _ . isUndefined ( timelineTemplateId ) ) {
30
- throw new errors . BadRequestError ( `Invalid timeline template ID: ${ timelineTemplateId } ` ) ;
31
- }
32
-
33
- const { timelineTempate, timelineTemplateMap } = await this . getTemplateAndTemplateMap (
34
- timelineTemplateId
35
- ) ;
36
- const { phaseDefinitionMap } = await this . getPhaseDefinitionsAndMap ( ) ;
37
-
38
- if ( ! phases || phases . length === 0 ) {
39
- // auto populate phases
40
- for ( const p of timelineTempate ) {
41
- phases . push ( { ...p } ) ;
42
- }
43
- }
44
-
45
- for ( const p of phases ) {
46
- const phaseDefinition = phaseDefinitionMap . get ( p . phaseId ) ;
47
-
48
- // TODO: move to domain-challenge
49
- p . id = uuid ( ) ;
50
- p . name = phaseDefinition . name ;
51
- p . description = phaseDefinition . description ;
52
-
53
- // set p.open based on current phase
54
- const phaseTemplate = timelineTemplateMap . get ( p . phaseId ) ;
55
- if ( phaseTemplate ) {
56
- if ( ! p . duration ) {
57
- p . duration = phaseTemplate . defaultDuration ;
58
- }
59
-
60
- if ( phaseTemplate . predecessor ) {
61
- const predecessor = _ . find ( phases , {
62
- phaseId : phaseTemplate . predecessor ,
63
- } ) ;
64
- if ( ! predecessor ) {
65
- throw new errors . BadRequestError (
66
- `Predecessor ${ phaseTemplate . predecessor } not found in given phases.`
67
- ) ;
68
- }
69
- p . predecessor = phaseTemplate . predecessor ;
70
- console . log ( "Setting predecessor" , p . predecessor , "for phase" , p . phaseId ) ;
71
- }
72
- }
73
- }
74
-
75
- // calculate dates
76
- if ( ! startDate ) {
77
- return ;
78
- }
79
-
80
- // sort phases by predecessor
81
- phases . sort ( ( a , b ) => {
82
- if ( a . predecessor === b . phaseId ) {
83
- return 1 ;
84
- }
85
- if ( b . predecessor === a . phaseId ) {
86
- return - 1 ;
87
- }
88
- return 0 ;
89
- } ) ;
90
-
91
- let isSubmissionPhaseOpen = false ;
92
-
93
- for ( let p of phases ) {
94
- const predecessor = timelineTemplateMap . get ( p . predecessor ) ;
95
-
96
- if ( predecessor == null ) {
97
- if ( p . name === "Registration" ) {
98
- p . scheduledStartDate = moment ( startDate ) . toDate ( ) ;
99
- }
100
- if ( p . name === "Submission" ) {
101
- p . scheduledStartDate = moment ( startDate ) . add ( 5 , "minutes" ) . toDate ( ) ;
102
- }
103
-
104
- if ( moment ( p . scheduledStartDate ) . isSameOrBefore ( moment ( ) ) ) {
105
- p . actualStartDate = p . scheduledStartDate ;
106
- } else {
107
- delete p . actualStartDate ;
108
- }
109
-
110
- p . scheduledEndDate = moment ( p . scheduledStartDate ) . add ( p . duration , "seconds" ) . toDate ( ) ;
111
- if ( moment ( p . scheduledEndDate ) . isBefore ( moment ( ) ) ) {
112
- delete p . actualEndDate ;
113
- } else {
114
- p . actualEndDate = p . scheduledEndDate ;
115
- }
116
- } else {
117
- const precedecessorPhase = _ . find ( phases , {
118
- phaseId : predecessor . phaseId ,
119
- } ) ;
120
- if ( precedecessorPhase == null ) {
121
- throw new errors . BadRequestError (
122
- `Predecessor ${ predecessor . phaseId } not found in given phases.`
123
- ) ;
124
- }
125
- let phaseEndDate = moment ( precedecessorPhase . scheduledEndDate ) ;
126
- if (
127
- precedecessorPhase . actualEndDate != null &&
128
- moment ( precedecessorPhase . actualEndDate ) . isAfter ( phaseEndDate )
129
- ) {
130
- phaseEndDate = moment ( precedecessorPhase . actualEndDate ) ;
131
- } else {
132
- phaseEndDate = moment ( precedecessorPhase . scheduledEndDate ) ;
133
- }
134
-
135
- p . scheduledStartDate = phaseEndDate . toDate ( ) ;
136
- p . scheduledEndDate = moment ( p . scheduledStartDate ) . add ( p . duration , "seconds" ) . toDate ( ) ;
137
- }
138
- p . isOpen = moment ( ) . isBetween ( p . scheduledStartDate , p . scheduledEndDate ) ;
139
- if ( p . isOpen ) {
140
- if ( p . name === "Submission" ) {
141
- isSubmissionPhaseOpen = true ;
142
- }
143
- delete p . actualEndDate ;
144
- }
145
-
146
- if ( moment ( p . scheduledStartDate ) . isAfter ( moment ( ) ) ) {
147
- delete p . actualStartDate ;
148
- delete p . actualEndDate ;
149
- }
150
-
151
- if ( p . name === "Post-Mortem" && isSubmissionPhaseOpen ) {
152
- delete p . actualStartDate ;
153
- delete p . actualEndDate ;
154
- p . isOpen = false ;
155
- }
156
-
157
- if ( p . constraints == null ) {
158
- p . constraints = [ ] ;
159
- }
160
- }
161
- }
162
-
21
+ phaseDefinitionMap = { } ;
22
+ timelineTemplateMap = { } ;
163
23
async populatePhasesForChallengeCreation ( phases , startDate , timelineTemplateId ) {
164
24
if ( _ . isUndefined ( timelineTemplateId ) ) {
165
25
throw new errors . BadRequestError ( `Invalid timeline template ID: ${ timelineTemplateId } ` ) ;
@@ -232,9 +92,7 @@ class ChallengePhaseHelper {
232
92
timelineTemplateId ,
233
93
isBeingActivated
234
94
) {
235
- const { timelineTempate, timelineTemplateMap } = await this . getTemplateAndTemplateMap (
236
- timelineTemplateId
237
- ) ;
95
+ const { timelineTemplateMap } = await this . getTemplateAndTemplateMap ( timelineTemplateId ) ;
238
96
const { phaseDefinitionMap } = await this . getPhaseDefinitionsAndMap ( ) ;
239
97
let fixedStartDate = undefined ;
240
98
const updatedPhases = _ . map ( challengePhases , ( phase ) => {
@@ -303,9 +161,9 @@ class ChallengePhaseHelper {
303
161
}
304
162
if ( _ . isUndefined ( phase . actualEndDate ) ) {
305
163
phase . scheduledEndDate = moment ( phase . scheduledStartDate )
306
- . add ( phase . duration , "seconds" )
307
- . toDate ( )
308
- . toISOString ( ) ;
164
+ . add ( phase . duration , "seconds" )
165
+ . toDate ( )
166
+ . toISOString ( ) ;
309
167
}
310
168
}
311
169
return updatedPhases ;
@@ -315,41 +173,46 @@ class ChallengePhaseHelper {
315
173
if ( ! phases || phases . length === 0 ) {
316
174
return ;
317
175
}
318
- const { items : records } = await phaseDomain . scan ( { criteria : getScanCriteria ( { } ) } ) ;
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 ) ) ;
176
+ const { phaseDefinitionMap } = await this . getPhaseDefinitionsAndMap ( ) ;
177
+ const invalidPhases = _ . filter ( phases , ( p ) => ! phaseDefinitionMap . has ( p . phaseId ) ) ;
324
178
if ( invalidPhases . length > 0 ) {
325
179
throw new errors . BadRequestError (
326
180
`The following phases are invalid: ${ toString ( invalidPhases ) } `
327
181
) ;
328
182
}
329
183
}
330
184
185
+ async getPhase ( phaseId ) {
186
+ const { phaseDefinitionMap } = await this . getPhaseDefinitionsAndMap ( ) ;
187
+ return phaseDefinitionMap . get ( phaseId ) ;
188
+ }
189
+
331
190
async getPhaseDefinitionsAndMap ( ) {
332
- const { result : records } = await phaseService . searchPhases ( ) ;
191
+ if ( _ . isEmpty ( this . phaseDefinitionMap ) ) {
192
+ const { items : records } = await phaseDomain . scan ( { criteria : getScanCriteria ( { } ) } ) ;
333
193
334
- const map = new Map ( ) ;
335
- _ . each ( records , ( r ) => {
336
- map . set ( r . id , r ) ;
337
- } ) ;
338
- return { phaseDefinitions : records , phaseDefinitionMap : map } ;
194
+ const map = new Map ( ) ;
195
+ _ . each ( records , ( r ) => {
196
+ map . set ( r . id , r ) ;
197
+ } ) ;
198
+
199
+ this . phaseDefinitionMap = { phaseDefinitions : records , phaseDefinitionMap : map } ;
200
+ }
201
+ return this . phaseDefinitionMap ;
339
202
}
340
203
341
204
async getTemplateAndTemplateMap ( timelineTemplateId ) {
342
- const records = await timelineTemplateService . getTimelineTemplate ( timelineTemplateId ) ;
205
+ if ( _ . isEmpty ( this . timelineTemplateMap ) ) {
206
+ const records = await timelineTemplateService . getTimelineTemplate ( timelineTemplateId ) ;
343
207
344
- const map = new Map ( ) ;
345
- _ . each ( records . phases , ( r ) => {
346
- map . set ( r . phaseId , r ) ;
347
- } ) ;
208
+ const map = new Map ( ) ;
209
+ _ . each ( records . phases , ( r ) => {
210
+ map . set ( r . phaseId , r ) ;
211
+ } ) ;
348
212
349
- return {
350
- timelineTempate : records . phases ,
351
- timelineTemplateMap : map ,
352
- } ;
213
+ this . timelineTemplateMap = { timelineTempate : records . phases , timelineTemplateMap : map } ;
214
+ }
215
+ return this . timelineTemplateMap ;
353
216
}
354
217
}
355
218
0 commit comments