@@ -6,6 +6,7 @@ const Factory = require('./modelFactory');
66const mongo = require ( '../mongo' ) ;
77const Event = require ( '../models/event' ) ;
88const { ObjectID } = require ( 'mongodb' ) ;
9+ const { composeEventPayloadWithRepetition } = require ( '../utils/merge' ) ;
910
1011/**
1112 * @typedef {Object } RecentEventSchema
@@ -287,6 +288,7 @@ class EventsFactory extends Factory {
287288 if ( result && result . events ) {
288289 result . events . forEach ( event => {
289290 event . projectId = this . projectId ;
291+ event . firstAppearanceTimestamp = event . timestamp ;
290292 } ) ;
291293 }
292294
@@ -391,23 +393,33 @@ class EventsFactory extends Factory {
391393 /**
392394 * Returns Event repetitions
393395 *
394- * @param {string|ObjectID } eventId - Event's id
396+ * @param {string|ObjectID } eventId - Event's id (may be repetition id)
395397 * @param {Number } limit - count limitations
396- * @param {Number } skip - selection offset
398+ * @param {Number } cursor - pointer to the next repetition
397399 *
398400 * @return {EventRepetitionSchema[] }
399401 *
400402 * @todo move to Repetitions(?) model
401403 */
402- async getEventRepetitions ( eventId , limit = 10 , skip = 0 ) {
404+ async getEventRepetitions ( eventId , limit = 10 , cursor = null ) {
403405 limit = this . validateLimit ( limit ) ;
404- skip = this . validateSkip ( skip ) ;
406+
407+ cursor = cursor ? new ObjectID ( cursor ) : null ;
408+
409+ const result = {
410+ repetitions : [ ] ,
411+ nextCursor : null ,
412+ } ;
405413
406414 /**
407415 * Get original event
408416 * @type {EventSchema }
409417 */
410- const eventOriginal = await this . findById ( eventId ) ;
418+ const eventOriginal = await this . _findOriginalEvent ( eventId ) ;
419+
420+ if ( ! eventOriginal ) {
421+ return result ;
422+ }
411423
412424 /**
413425 * Collect repetitions
@@ -416,13 +428,26 @@ class EventsFactory extends Factory {
416428 const repetitions = await this . getCollection ( this . TYPES . REPETITIONS )
417429 . find ( {
418430 groupHash : eventOriginal . groupHash ,
431+ _id : cursor ? { $lte : cursor } : { $exists : true } ,
419432 } )
420433 . sort ( { _id : - 1 } )
421- . limit ( limit )
422- . skip ( skip )
434+ . limit ( limit + 1 )
423435 . toArray ( ) ;
424436
425- const isLastPortion = repetitions . length < limit && skip === 0 ;
437+ if ( repetitions . length === limit + 1 ) {
438+ result . nextCursor = repetitions . pop ( ) . _id ;
439+ }
440+
441+ for ( const repetition of repetitions ) {
442+ const event = this . _composeEventWithRepetition ( eventOriginal , repetition ) ;
443+
444+ result . repetitions . push ( {
445+ ...event ,
446+ projectId : this . projectId ,
447+ } ) ;
448+ }
449+
450+ const isLastPortion = result . nextCursor === null ;
426451
427452 /**
428453 * For last portion:
@@ -434,16 +459,15 @@ class EventsFactory extends Factory {
434459 * @type {EventRepetitionSchema }
435460 */
436461 const firstRepetition = {
437- _id : eventOriginal . _id ,
438- payload : eventOriginal . payload ,
439- groupHash : eventOriginal . groupHash ,
440- timestamp : eventOriginal . timestamp ,
462+ ...eventOriginal ,
463+ firstAppearanceTimestamp : eventOriginal . timestamp ,
464+ projectId : this . projectId ,
441465 } ;
442466
443- repetitions . push ( firstRepetition ) ;
467+ result . repetitions . push ( firstRepetition ) ;
444468 }
445469
446- return repetitions ;
470+ return result ;
447471 }
448472
449473 /**
@@ -455,10 +479,33 @@ class EventsFactory extends Factory {
455479 * @todo move to Repetitions(?) model
456480 */
457481 async getEventRepetition ( repetitionId ) {
458- return this . getCollection ( this . TYPES . REPETITIONS )
482+ const repetition = await this . getCollection ( this . TYPES . REPETITIONS )
459483 . findOne ( {
460484 _id : ObjectID ( repetitionId ) ,
461485 } ) ;
486+
487+ if ( ! repetition ) {
488+ /**
489+ * If repetition is not found, it can mean that client is trying to get original event
490+ */
491+ const event = await this . findById ( repetitionId ) ;
492+
493+ return event ? {
494+ ...event ,
495+ firstAppearanceTimestamp : event . timestamp ,
496+ } : null ;
497+ }
498+
499+ const originalEvent = await this . getCollection ( this . TYPES . EVENTS )
500+ . findOne ( {
501+ groupHash : repetition . groupHash ,
502+ } ) ;
503+
504+ if ( ! originalEvent ) {
505+ return null ;
506+ }
507+
508+ return this . _composeEventWithRepetition ( originalEvent , repetition ) ;
462509 }
463510
464511 /**
@@ -483,7 +530,11 @@ class EventsFactory extends Factory {
483530 * @returns {Release|null }
484531 */
485532 async getEventRelease ( eventId ) {
486- const eventOriginal = await this . findById ( eventId ) ;
533+ const eventOriginal = await this . _findOriginalEvent ( eventId ) ;
534+
535+ if ( ! eventOriginal ) {
536+ return null ;
537+ }
487538
488539 const release = await mongo . databases . events . collection ( this . TYPES . RELEASES ) . findOne ( {
489540 release : eventOriginal . payload . release ,
@@ -502,9 +553,15 @@ class EventsFactory extends Factory {
502553 * @return {Promise<void> }
503554 */
504555 async visitEvent ( eventId , userId ) {
556+ const event = await this . _findOriginalEvent ( eventId ) ;
557+
558+ if ( ! event ) {
559+ return null ;
560+ }
561+
505562 return this . getCollection ( this . TYPES . EVENTS )
506563 . updateOne (
507- { _id : new ObjectID ( eventId ) } ,
564+ { _id : new ObjectID ( event . _id ) } ,
508565 { $addToSet : { visitedBy : new ObjectID ( userId ) } }
509566 ) ;
510567 }
@@ -519,9 +576,15 @@ class EventsFactory extends Factory {
519576 */
520577 async toggleEventMark ( eventId , mark ) {
521578 const collection = this . getCollection ( this . TYPES . EVENTS ) ;
522- const query = { _id : new ObjectID ( eventId ) } ;
523579
524- const event = await collection . findOne ( query ) ;
580+ const event = await this . _findOriginalEvent ( eventId ) ;
581+
582+ if ( ! event ) {
583+ return null ;
584+ }
585+
586+ const query = { _id : new ObjectID ( event . _id ) } ;
587+
525588 const markKey = `marks.${ mark } ` ;
526589
527590 let update ;
@@ -571,13 +634,74 @@ class EventsFactory extends Factory {
571634 */
572635 async updateAssignee ( eventId , assignee ) {
573636 const collection = this . getCollection ( this . TYPES . EVENTS ) ;
574- const query = { _id : new ObjectID ( eventId ) } ;
637+
638+ const event = await this . _findOriginalEvent ( eventId ) ;
639+
640+ if ( ! event ) {
641+ return null ;
642+ }
643+
644+ const query = { _id : new ObjectID ( event . _id ) } ;
645+
575646 const update = {
576647 $set : { assignee : assignee } ,
577648 } ;
578649
579650 return collection . updateOne ( query , update ) ;
580651 }
652+
653+ /**
654+ * Find original event by eventId. If event is not found directly,
655+ * try to find it as repetition and get original event by groupHash
656+ *
657+ * @param {string|ObjectID } eventId - event's id, may be repetition id
658+ * @returns {Promise<Event|null> } original event or null if not found
659+ */
660+ async _findOriginalEvent ( eventId ) {
661+ let originalEvent ;
662+
663+ /**
664+ * Try to find it by repetitionId
665+ */
666+ const repetition = await this . getCollection ( this . TYPES . REPETITIONS )
667+ . findOne ( {
668+ _id : new ObjectID ( eventId ) ,
669+ } ) ;
670+
671+ /**
672+ * If repetition is not found by eventId, try to find it by eventId
673+ */
674+ if ( ! repetition ) {
675+ originalEvent = await this . getCollection ( this . TYPES . EVENTS )
676+ . findOne ( {
677+ _id : new ObjectID ( eventId ) ,
678+ } ) ;
679+ } else {
680+ originalEvent = await this . getCollection ( this . TYPES . EVENTS )
681+ . findOne ( {
682+ groupHash : repetition . groupHash ,
683+ } ) ;
684+ }
685+
686+ return originalEvent ;
687+ }
688+
689+ /**
690+ * Compose event with repetition
691+ *
692+ * @param {Event } event - event
693+ * @param {Repetition } repetition - repetition
694+ * @returns {Event } event merged with repetition
695+ */
696+ _composeEventWithRepetition ( event , repetition ) {
697+ return {
698+ ...event ,
699+ _id : repetition . _id ,
700+ firstAppearanceTimestamp : event . timestamp ,
701+ timestamp : repetition . timestamp ,
702+ payload : composeEventPayloadWithRepetition ( event . payload , repetition ) ,
703+ } ;
704+ }
581705}
582706
583707module . exports = EventsFactory ;
0 commit comments