@@ -7,13 +7,48 @@ import config from 'config';
77import _ from 'lodash' ;
88import Promise from 'bluebird' ;
99import util from '../../util' ;
10+ import { TIMELINE_REFERENCES } from '../../constants' ;
11+
1012import messageService from '../../services/messageService' ;
1113
1214const ES_PROJECT_INDEX = config . get ( 'elasticsearchConfig.indexName' ) ;
1315const ES_PROJECT_TYPE = config . get ( 'elasticsearchConfig.docType' ) ;
1416
1517const eClient = util . getElasticSearchClient ( ) ;
1618
19+ /**
20+ * Build topics data based on route parameter.
21+ *
22+ * @param {Object } logger logger to log along with trace id
23+ * @param {Object } phase phase object
24+ * @param {String } route route value can be PHASE/WORK
25+ * @returns {undefined }
26+ */
27+ const buildTopicsData = ( logger , phase , route ) => {
28+ if ( route === TIMELINE_REFERENCES . WORK ) {
29+ return [ {
30+ tag : `work#${ phase . id } -details` ,
31+ title : `${ phase . name } - Details` ,
32+ reference : 'project' ,
33+ referenceId : `${ phase . projectId } ` ,
34+ body : 'This is the beginning of your phase discussion. During execution of this phase, all related communication will be conducted here - phase updates, questions and answers, suggestions, etc. If you haven\'t already, do please take a moment to review the form in the Specification tab above and fill in as much detail as possible. This will help get started faster. Thanks!' , // eslint-disable-line
35+ } , {
36+ tag : `work#${ phase . id } -requirements` ,
37+ title : `${ phase . name } - Requirements` ,
38+ reference : 'project' ,
39+ referenceId : `${ phase . projectId } ` ,
40+ body : 'This is the beginning of your phase discussion. During execution of this phase, all related communication will be conducted here - phase updates, questions and answers, suggestions, etc. If you haven\'t already, do please take a moment to review the form in the Specification tab above and fill in as much detail as possible. This will help get started faster. Thanks!' , // eslint-disable-line
41+ } ] ;
42+ }
43+ return [ {
44+ tag : `phase#${ phase . id } ` ,
45+ title : phase . name ,
46+ reference : 'project' ,
47+ referenceId : `${ phase . projectId } ` ,
48+ body : 'This is the beginning of your phase discussion. During execution of this phase, all related communication will be conducted here - phase updates, questions and answers, suggestions, etc. If you haven\'t already, do please take a moment to review the form in the Specification tab above and fill in as much detail as possible. This will help get started faster. Thanks!' , // eslint-disable-line
49+ } ] ;
50+ } ;
51+
1752/**
1853 * Indexes the project phase in the elastic search.
1954 *
@@ -59,26 +94,22 @@ const indexProjectPhase = Promise.coroutine(function* (logger, phase) { // eslin
5994} ) ;
6095
6196/**
62- * Creates a new phase topic in message api.
97+ * Creates topics in message api
6398 *
6499 * @param {Object } logger logger to log along with trace id
65- * @param {Object } msg event payload
100+ * @param {Object } phase phase object
101+ * @param {String } route route value can be `phase`/`work`
66102 * @returns {undefined }
67103 */
68- const createPhaseTopic = Promise . coroutine ( function * ( logger , phase ) { // eslint-disable-line func-names
104+ const createTopics = Promise . coroutine ( function * ( logger , phase , route ) { // eslint-disable-line func-names
69105 try {
70- logger . debug ( 'Creating topic for phase with phase' , phase ) ;
71- const topic = yield messageService . createTopic ( {
72- reference : 'project' ,
73- referenceId : `${ phase . projectId } ` ,
74- tag : `phase#${ phase . id } ` ,
75- title : phase . name ,
76- body : 'This is the beginning of your phase discussion. During execution of this phase, all related communication will be conducted here - phase updates, questions and answers, suggestions, etc. If you haven\'t already, do please take a moment to review the form in the Specification tab above and fill in as much detail as possible. This will help get started faster. Thanks!' , // eslint-disable-line
77- } , logger ) ;
78- logger . debug ( 'topic for the phase created successfully' ) ;
79- logger . debug ( 'created topic' , topic ) ;
106+ logger . debug ( `Creating topics for ${ route } with phase` , phase ) ;
107+ const topicsData = buildTopicsData ( logger , phase , route ) ;
108+ const topics = yield Promise . all ( _ . map ( topicsData , topicData => messageService . createTopic ( topicData , logger ) ) ) ;
109+ logger . debug ( `topics for the ${ route } created successfully` ) ;
110+ logger . debug ( 'created topics' , topics ) ;
80111 } catch ( error ) {
81- logger . error ( ' Error in creating topic for the project phase' , error ) ;
112+ logger . error ( ` Error in creating topic for ${ route } ` , error ) ;
82113 // don't throw the error back to nack the bus, because we don't want to get multiple topics per phase
83114 // we can create topic for a phase manually, if somehow it fails
84115 }
@@ -92,12 +123,14 @@ const createPhaseTopic = Promise.coroutine(function* (logger, phase) { // eslint
92123 * @returns {undefined }
93124 */
94125const projectPhaseAddedHandler = Promise . coroutine ( function * ( logger , msg , channel ) { // eslint-disable-line func-names
95- const phase = JSON . parse ( msg . content . toString ( ) ) ;
126+ const data = JSON . parse ( msg . content . toString ( ) ) ;
127+ const phase = _ . get ( data , 'added' , { } ) ;
128+ const route = _ . get ( data , 'route' , 'PHASE' ) ;
96129 try {
97130 logger . debug ( 'calling indexProjectPhase' , phase ) ;
98131 yield indexProjectPhase ( logger , phase , channel ) ;
99132 logger . debug ( 'calling createPhaseTopic' , phase ) ;
100- yield createPhaseTopic ( logger , phase ) ;
133+ yield createTopics ( logger , phase , route ) ;
101134 channel . ack ( msg ) ;
102135 } catch ( error ) {
103136 logger . error ( 'Error handling project.phase.added event' , error ) ;
@@ -135,31 +168,46 @@ const updateIndexProjectPhase = Promise.coroutine(function* (logger, data) { //
135168} ) ;
136169
137170/**
138- * Creates a new phase topic in message api.
171+ * Update one topic
172+ *
173+ * @param {Object } logger logger to log along with trace id
174+ * @param {Object } phase phase object
175+ * @param {Object } topicUpdate updated topic data
176+ * @returns {undefined }
177+ */
178+ const updateOneTopic = Promise . coroutine ( function * ( logger , phase , topicUpdate ) { // eslint-disable-line func-names
179+ const topic = yield messageService . getTopicByTag ( phase . projectId , topicUpdate . tag , logger ) ;
180+ logger . trace ( 'Topic' , topic ) ;
181+ const title = topicUpdate . title ;
182+ const titleChanged = topic && topic . title !== title ;
183+ logger . trace ( 'titleChanged' , titleChanged ) ;
184+ const contentPost = topic && topic . posts && topic . posts . length > 0 ? topic . posts [ 0 ] : null ;
185+ logger . trace ( 'contentPost' , contentPost ) ;
186+ const postId = _ . get ( contentPost , 'id' ) ;
187+ const content = _ . get ( contentPost , 'body' ) ;
188+ if ( postId && content && titleChanged ) {
189+ const updatedTopic = yield messageService . updateTopic ( topic . id , { title, postId, content } , logger ) ;
190+ logger . debug ( 'topic updated successfully' ) ;
191+ logger . trace ( 'updated topic' , updatedTopic ) ;
192+ }
193+ } ) ;
194+
195+ /**
196+ * Update topics in message api.
139197 *
140198 * @param {Object } logger logger to log along with trace id
141- * @param {Object } msg event payload
199+ * @param {Object } phase phase object
200+ * @param {String } route route value can be `phase`/`work`
142201 * @returns {undefined }
143202 */
144- const updatePhaseTopic = Promise . coroutine ( function * ( logger , phase ) { // eslint-disable-line func-names
203+ const updateTopics = Promise . coroutine ( function * ( logger , phase , route ) { // eslint-disable-line func-names
145204 try {
146- logger . debug ( 'Updating topic for phase with phase' , phase ) ;
147- const topic = yield messageService . getPhaseTopic ( phase . projectId , phase . id , logger ) ;
148- logger . trace ( 'Topic' , topic ) ;
149- const title = phase . name ;
150- const titleChanged = topic && topic . title !== title ;
151- logger . trace ( 'titleChanged' , titleChanged ) ;
152- const contentPost = topic && topic . posts && topic . posts . length > 0 ? topic . posts [ 0 ] : null ;
153- logger . trace ( 'contentPost' , contentPost ) ;
154- const postId = _ . get ( contentPost , 'id' ) ;
155- const content = _ . get ( contentPost , 'body' ) ;
156- if ( postId && content && titleChanged ) {
157- const updatedTopic = yield messageService . updateTopic ( topic . id , { title, postId, content } , logger ) ;
158- logger . debug ( 'topic for the phase updated successfully' ) ;
159- logger . trace ( 'updated topic' , updatedTopic ) ;
160- }
205+ logger . debug ( `Updating topic for ${ route } with phase` , phase ) ;
206+ const topicsData = buildTopicsData ( logger , phase , route ) ;
207+ yield Promise . all ( _ . map ( topicsData , topicData => updateOneTopic ( logger , phase , topicData ) ) ) ;
208+ logger . debug ( `topics for the ${ route } updated successfully` ) ;
161209 } catch ( error ) {
162- logger . error ( ' Error in updating topic for the project phase' , error ) ;
210+ logger . error ( ` Error in updating topic for ${ route } ` , error ) ;
163211 // don't throw the error back to nack the bus, because we don't want to get multiple topics per phase
164212 // we can create topic for a phase manually, if somehow it fails
165213 }
@@ -175,10 +223,11 @@ const updatePhaseTopic = Promise.coroutine(function* (logger, phase) { // eslint
175223const projectPhaseUpdatedHandler = Promise . coroutine ( function * ( logger , msg , channel ) { // eslint-disable-line func-names
176224 try {
177225 const data = JSON . parse ( msg . content . toString ( ) ) ;
226+ const route = _ . get ( data , 'route' , 'PHASE' ) ;
178227 logger . debug ( 'calling updateIndexProjectPhase' , data ) ;
179228 yield updateIndexProjectPhase ( logger , data , channel ) ;
180- logger . debug ( 'calling updatePhaseTopic ' , data . updated ) ;
181- yield updatePhaseTopic ( logger , data . updated ) ;
229+ logger . debug ( 'calling updateTopics ' , data . updated ) ;
230+ yield updateTopics ( logger , data . updated , route ) ;
182231 channel . ack ( msg ) ;
183232 } catch ( error ) {
184233 logger . error ( 'Error handling project.phase.updated event' , error ) ;
@@ -197,13 +246,14 @@ const projectPhaseUpdatedHandler = Promise.coroutine(function* (logger, msg, cha
197246const removePhaseFromIndex = Promise . coroutine ( function * ( logger , msg ) { // eslint-disable-line func-names
198247 try {
199248 const data = JSON . parse ( msg . content . toString ( ) ) ;
200- const doc = yield eClient . get ( { index : ES_PROJECT_INDEX , type : ES_PROJECT_TYPE , id : data . projectId } ) ;
201- const phases = _ . filter ( doc . _source . phases , single => single . id !== data . id ) ; // eslint-disable-line no-underscore-dangle
249+ const phase = _ . get ( data , 'deleted' , { } ) ;
250+ const doc = yield eClient . get ( { index : ES_PROJECT_INDEX , type : ES_PROJECT_TYPE , id : phase . projectId } ) ;
251+ const phases = _ . filter ( doc . _source . phases , single => single . id !== phase . id ) ; // eslint-disable-line no-underscore-dangle
202252 const merged = _ . assign ( doc . _source , { phases } ) ; // eslint-disable-line no-underscore-dangle
203253 yield eClient . update ( {
204254 index : ES_PROJECT_INDEX ,
205255 type : ES_PROJECT_TYPE ,
206- id : data . projectId ,
256+ id : phase . projectId ,
207257 body : {
208258 doc : merged ,
209259 } ,
@@ -217,26 +267,46 @@ const removePhaseFromIndex = Promise.coroutine(function* (logger, msg) { // esli
217267} ) ;
218268
219269/**
220- * Removes the phase topic from the message api.
270+ * Removes one topic from the message api.
221271 *
222- * @param {Object } logger logger to log along with trace id
223- * @param {Object } msg event payload
272+ * @param {Object } logger logger to log along with trace id
273+ * @param {Object } phase phase object
274+ * @param {Object } tag topic tag
224275 * @returns {undefined }
225276 */
226- const removePhaseTopic = Promise . coroutine ( function * ( logger , msg ) { // eslint-disable-line func-names
277+ const removeOneTopic = Promise . coroutine ( function * ( logger , phase , tag ) { // eslint-disable-line func-names
227278 try {
228- const phase = JSON . parse ( msg . content . toString ( ) ) ;
229- const phaseTopic = yield messageService . getPhaseTopic ( phase . projectId , phase . id , logger ) ;
279+ const phaseTopic = yield messageService . getTopicByTag ( phase . projectId , tag , logger ) ;
230280 yield messageService . deletePosts ( phaseTopic . id , phaseTopic . postIds , logger ) ;
231281 yield messageService . deleteTopic ( phaseTopic . id , logger ) ;
232- logger . debug ( 'topic for the phase removed successfully' ) ;
233282 } catch ( error ) {
234- logger . error ( ' Error in removing topic for the project phase' , error ) ;
283+ logger . error ( ` Error removing topic by tab ${ tag } ` , error ) ;
235284 // don't throw the error back to nack the bus
236285 // we can delete topic for a phase manually, if somehow it fails
237286 }
238287} ) ;
239288
289+ /**
290+ * Remove topics in message api.
291+ *
292+ * @param {Object } logger logger to log along with trace id
293+ * @param {Object } phase phase object
294+ * @param {String } route route value can be `phase`/`work`
295+ * @returns {undefined }
296+ */
297+ const removeTopics = Promise . coroutine ( function * ( logger , phase , route ) { // eslint-disable-line func-names
298+ try {
299+ logger . debug ( `Removing topic for ${ route } with phase` , phase ) ;
300+ const topicsData = buildTopicsData ( logger , phase , route ) ;
301+ yield Promise . all ( _ . map ( topicsData , topicData => removeOneTopic ( logger , phase , topicData . tag ) ) ) ;
302+ logger . debug ( `topics for the ${ route } removed successfully` ) ;
303+ } catch ( error ) {
304+ logger . error ( `Error in removing topic for ${ route } ` , error ) ;
305+ // don't throw the error back to nack the bus, because we don't want to get multiple topics per phase
306+ // we can create topic for a phase manually, if somehow it fails
307+ }
308+ } ) ;
309+
240310/**
241311 * Handler for project phase deleted event
242312 * @param {Object } logger logger to log along with trace id
@@ -247,7 +317,11 @@ const removePhaseTopic = Promise.coroutine(function* (logger, msg) { // eslint-d
247317const projectPhaseRemovedHandler = Promise . coroutine ( function * ( logger , msg , channel ) { // eslint-disable-line func-names
248318 try {
249319 yield removePhaseFromIndex ( logger , msg , channel ) ;
250- yield removePhaseTopic ( logger , msg ) ;
320+ const data = JSON . parse ( msg . content . toString ( ) ) ;
321+ const phase = _ . get ( data , 'deleted' , { } ) ;
322+ const route = _ . get ( data , 'route' ) ;
323+ logger . debug ( 'calling removeTopics' ) ;
324+ yield removeTopics ( logger , phase , route ) ;
251325 channel . ack ( msg ) ;
252326 } catch ( error ) {
253327 logger . error ( 'Error fetching project document from elasticsearch' , error ) ;
@@ -261,5 +335,5 @@ module.exports = {
261335 projectPhaseAddedHandler,
262336 projectPhaseRemovedHandler,
263337 projectPhaseUpdatedHandler,
264- createPhaseTopic,
338+ createPhaseTopic : createTopics ,
265339} ;
0 commit comments