diff --git a/src/db/challengeEntity.json b/src/db/challengeEntity.json index 05f66909fec15eef19d6881a257ec5991041bd14..9fb11a5aa71733ea89bd7113d615b74603e3f2ef 100644 --- a/src/db/challengeEntity.json +++ b/src/db/challengeEntity.json @@ -12,10 +12,12 @@ "data": { "_id": "DUEL001", "_type": "com.grandlyon.ecolyo.duel" } }, "exploration": { - "data": { - "_id": "EXPLORATION001", - "_type": "com.grandlyon.ecolyo.exploration" - } + "data": [ + { + "_id": "EXPLORATION001", + "_type": "com.grandlyon.ecolyo.exploration" + } + ] } } }, @@ -32,10 +34,16 @@ "data": { "_id": "DUEL002", "_type": "com.grandlyon.ecolyo.duel" } }, "exploration": { - "data": { - "_id": "EXPLORATION006", - "_type": "com.grandlyon.ecolyo.exploration" - } + "data": [ + { + "_id": "EXPLORATION006", + "_type": "com.grandlyon.ecolyo.exploration" + }, + { + "_id": "EXPLORATION006_0", + "_type": "com.grandlyon.ecolyo.exploration" + } + ] } } }, @@ -52,10 +60,12 @@ "data": { "_id": "DUEL003", "_type": "com.grandlyon.ecolyo.duel" } }, "exploration": { - "data": { - "_id": "EXPLORATION003", - "_type": "com.grandlyon.ecolyo.exploration" - } + "data": [ + { + "_id": "EXPLORATION003", + "_type": "com.grandlyon.ecolyo.exploration" + } + ] } } } diff --git a/src/db/explorationEntity.json b/src/db/explorationEntity.json index f6274cab0367ac3b21b8cd59540ec174a3316052..dc025250588dbf7f9ad9d9bb9f5dab09f9cf188e 100644 --- a/src/db/explorationEntity.json +++ b/src/db/explorationEntity.json @@ -83,7 +83,7 @@ "date": null, "ecogesture_id": "0099", "fluid_condition": [], - "isConditional": true, + "isConditional": false, "message_success": "Vous avez consulté l'écogeste \"Lord Kelvin\"" }, { diff --git a/src/doctypes/index.ts b/src/doctypes/index.ts index 5c1f91d059ae95cdf2f2096a41e7601fba43331f..cb2adf861f88dd9fbf42631ced6a80f7286a30a5 100644 --- a/src/doctypes/index.ts +++ b/src/doctypes/index.ts @@ -71,7 +71,7 @@ const doctypes = { }, exploration: { doctype: EXPLORATION_DOCTYPE, - type: 'has-one', + type: 'has-many', }, }, }, diff --git a/src/models/challenge.model.ts b/src/models/challenge.model.ts index dcc2c95ea33a6e8d7632e830ba178b5fb32ec571..4910b8246a90e1f7d80e5a377bffd79a17d32797 100644 --- a/src/models/challenge.model.ts +++ b/src/models/challenge.model.ts @@ -12,6 +12,7 @@ import { UserQuiz, ExplorationEntity, UserExploration, + Relation, } from 'models' export interface ChallengeState { @@ -24,6 +25,16 @@ export interface ChallengeEntity { title: string description: string target: number + relationships: { + quiz: { + data: Relation + } + duel: { + data: Relation + } + exploration: { data: Relation[] } + } + duel: DuelEntity | null quiz: QuizEntity | null exploration: ExplorationEntity | null diff --git a/src/models/relation.model.ts b/src/models/relation.model.ts index 6045092d586ffd72e17e36df1d87a1630547a254..8cb5ea239e444cae73f19cc36c3e00fdab5f00ed 100644 --- a/src/models/relation.model.ts +++ b/src/models/relation.model.ts @@ -1,4 +1,15 @@ export interface Relation { _id: string _type: string + data?: Relation +} + +export interface RelationEntitiesObject { + duelEntityRelation: Relation + quizEntityRelation: Relation + explorationEntityRelation: Relation[] +} + +export interface GetRelationshipsReturn { + [relName: string]: Array<Relation> } diff --git a/src/services/challenge.service.ts b/src/services/challenge.service.ts index 00d94cd15482dd8b24b6820d235f3b15f80a12c5..e39dec03770e41e4cbc9afb687623b51056aa40f 100644 --- a/src/services/challenge.service.ts +++ b/src/services/challenge.service.ts @@ -15,6 +15,7 @@ import { UserQuiz, UserExploration, ExplorationEntity, + RelationEntitiesObject, } from 'models' import { UserChallengeState, @@ -27,7 +28,7 @@ import { UserDuelState } from 'enum/userDuel.enum' import DuelService from 'services/duel.service' import QuizService from 'services/quiz.service' import ConsumptionDataManager from 'services/consumption.service' -import { getRelationship } from 'utils/utils' +import { getRelationship, getRelationshipHasMany } from 'utils/utils' import { getLagDays } from 'utils/date' import ExplorationService from './exploration.service' import { FluidState, FluidType } from 'enum/fluid.enum' @@ -126,6 +127,144 @@ export default class ChallengeService { return userChallenge } + public async isExplorationConditionVerified( + exploration: UserExploration | ExplorationEntity + ): Promise<boolean> { + const fluidService = new FluidService(this._client) + let isValid = false + const fluidStatus = await fluidService.getFluidStatus() + const fluidCondition: FluidType[] = exploration.fluid_condition + //check if the fluid is connected + if ( + fluidStatus[fluidCondition[0]].status !== + FluidState.KONNECTOR_NOT_FOUND && + fluidStatus[fluidCondition[0]].status !== FluidState.NOT_CONNECTED + ) { + isValid = true + } else { + isValid = false + } + return isValid + } + + public async getRelationEntities( + challenge: ChallengeEntity + ): Promise<RelationEntitiesObject> { + const duelEntityRelation: Relation = getRelationship(challenge, 'duel') + const quizEntityRelation: Relation = getRelationship(challenge, 'quiz') + const explorationEntityRelation: Relation[] = getRelationshipHasMany( + challenge, + 'exploration' + ) + const result = { + duelEntityRelation: duelEntityRelation, + quizEntityRelation: quizEntityRelation, + explorationEntityRelation: explorationEntityRelation, + } + return result + } + + public async getUpdatedUserChallengeIfExplorationConditionIsValid( + exploration: UserExploration, + challenge: ChallengeEntity, + duel: UserDuel, + quiz: UserQuiz + ): Promise<UserChallenge | undefined> { + let userChallenge: UserChallenge | null = null + //Check if it's a conditionnal exploration + if (exploration.isConditional) { + const isConditionVerified = await this.isExplorationConditionVerified( + exploration + ) + // if condition is verified, add exploration to UserChallenge and return it + if (isConditionVerified) { + userChallenge = this.parseChallengeEntityToUserChallenge( + challenge, + duel, + quiz, + exploration + ) + return userChallenge + } + } //if there is no condition, add the exploration + else { + userChallenge = this.parseChallengeEntityToUserChallenge( + challenge, + duel, + quiz, + exploration + ) + return userChallenge + } + } + + public async processExploration( + explorationEntities: ExplorationEntity[] | undefined, + explorationEntityRelation: Relation[], + challenge: ChallengeEntity, + duel: UserDuel, + quiz: UserQuiz, + buildList: UserChallenge[] + ): Promise<UserChallenge[]> { + const explorationService = new ExplorationService(this._client) + for (const explorationRelation of explorationEntityRelation) { + const exploration: UserExploration = explorationService.getUserExplorationfromExplorationEntities( + explorationEntities || [], + explorationRelation._id + ) + const userChallenge = await this.getUpdatedUserChallengeIfExplorationConditionIsValid( + exploration, + challenge, + duel, + quiz + ) + if (userChallenge) { + buildList.push(userChallenge) + break + } + } + return buildList + } + + public async loopVerificationExplorationCondition( + userChallenge: UserChallenge, + challengeEntityList: ChallengeEntity[] + ): Promise<UserChallenge> { + const currentEntity = challengeEntityList.filter( + challenge => challenge.id === userChallenge.id + ) + const relationsArray = currentEntity[0].relationships.exploration + const explorationService = new ExplorationService(this._client) + let updatedUserChallenge: UserChallenge = userChallenge + for (const relation of relationsArray.data) { + const newExploEntity = await explorationService.getExplorationEntityById( + relation._id + ) + const newUserExplo: UserExploration = explorationService.parseExplorationEntityToUserExploration( + newExploEntity + ) + if (newExploEntity.isConditional) { + const isConditionValid = await this.isExplorationConditionVerified( + newExploEntity + ) + if (isConditionValid) { + updatedUserChallenge = { + ...updatedUserChallenge, + exploration: newUserExplo, + } + break + } + } else { + updatedUserChallenge = { + ...updatedUserChallenge, + exploration: newUserExplo, + } + break + } + } + return updatedUserChallenge + } + /** * Retrieve UserChallenge list with all challenges * @returns {UserChallenge[]} @@ -162,111 +301,80 @@ export default class ChallengeService { const quizService = new QuizService(this._client) const explorationService = new ExplorationService(this._client) let buildList: UserChallenge[] = [] + // Case UserChallengList is empty if (challengeEntityList.length > 0 && userChallengeList.length === 0) { - challengeEntityList.forEach(async challenge => { - const duelEntityRelation: Relation = getRelationship(challenge, 'duel') - const quizEntityRelation: Relation = getRelationship(challenge, 'quiz') - const explorationEntityRelation: Relation = getRelationship( - challenge, - 'exploration' - ) + for (const challenge of challengeEntityList) { + const relationEntities = await this.getRelationEntities(challenge) const duel: UserDuel = duelService.getDuelfromDuelEntities( duelEntities || [], - duelEntityRelation._id + relationEntities.duelEntityRelation._id ) const quiz: UserQuiz = quizService.getUserQuizfromQuizEntities( quizEntities || [], - quizEntityRelation._id - ) - const exploration: UserExploration = explorationService.getUserExplorationfromExplorationEntities( - explorationEntities || [], - explorationEntityRelation._id - ) - const userChallenge = this.parseChallengeEntityToUserChallenge( - challenge, - duel, - quiz, - exploration + relationEntities.quizEntityRelation._id ) - - buildList.push(userChallenge) - }) + //Only one exploration relation + if (relationEntities.explorationEntityRelation.length === 1) { + const exploration: UserExploration = explorationService.getUserExplorationfromExplorationEntities( + explorationEntities || [], + relationEntities.explorationEntityRelation[0]._id + ) + const userChallenge = this.parseChallengeEntityToUserChallenge( + challenge, + duel, + quiz, + exploration + ) + buildList.push(userChallenge) + } + //Several explorations with fluid condition + else { + await this.processExploration( + explorationEntities, + relationEntities.explorationEntityRelation, + challenge, + duel, + quiz, + buildList + ) + } + } buildList = this.unLockCurrentUserChallenge(buildList) - } else if (challengeEntityList.length > 0 && userChallengeList.length > 0) { - challengeEntityList.forEach(async challenge => { + } + // Case UserChallengeList is existing + else if (challengeEntityList.length > 0 && userChallengeList.length > 0) { + for (const challenge of challengeEntityList) { const userChallengeIndex = userChallengeList.findIndex( entity => entity.id === challenge.id ) if (userChallengeIndex >= 0) { let userChallenge: UserChallenge = userChallengeList[userChallengeIndex] - console.log('index', userChallenge) - if (userChallenge.exploration.isConditional) { - const fluidService = new FluidService(this._client) - const fluidStatus = await fluidService.getFluidStatus() - console.log('status', status) - const fluidCondition: FluidType[] = - userChallenge.exploration.fluid_condition - //check if the fluid is connected - let isConditionValid = false - if ( - fluidStatus[fluidCondition[0]].status !== - FluidState.KONNECTOR_NOT_FOUND && - fluidStatus[fluidCondition[0]].status !== FluidState.NOT_CONNECTED - ) - isConditionValid = true - if (isConditionValid === false) { - const newExploId = `${userChallenge.exploration.id}_0` - const newExploEntity = await explorationService.getExplorationEntityById( - newExploId - ) - const newUserExplo: UserExploration = explorationService.parseExplorationEntityToUserExploration( - newExploEntity - ) - userChallenge = { - ...userChallenge, - exploration: newUserExplo, - } - } - } + userChallenge = await this.loopVerificationExplorationCondition( + userChallenge, + challengeEntityList + ) buildList.push(userChallenge) - console.log('buildList', buildList) } else { - const duelEntityRelation: Relation = getRelationship( - challenge, - 'duel' - ) - const quizEntityRelation: Relation = getRelationship( - challenge, - 'quiz' - ) - const explorationEntityRelation: Relation = getRelationship( - challenge, - 'exploration' - ) + const relationEntities = await this.getRelationEntities(challenge) const duel: UserDuel = duelService.getDuelfromDuelEntities( duelEntities || [], - duelEntityRelation._id + relationEntities.duelEntityRelation._id ) const quiz: UserQuiz = quizService.getUserQuizfromQuizEntities( quizEntities || [], - quizEntityRelation._id + relationEntities.quizEntityRelation._id ) - const exploration: UserExploration = explorationService.getUserExplorationfromExplorationEntities( - explorationEntities || [], - explorationEntityRelation._id - ) - - buildList.push( - this.parseChallengeEntityToUserChallenge( - challenge, - duel, - quiz, - exploration - ) + await this.processExploration( + explorationEntities, + relationEntities.explorationEntityRelation, + challenge, + duel, + quiz, + buildList ) } - }) + } buildList = this.unLockCurrentUserChallenge(buildList) } return buildList @@ -551,7 +659,11 @@ export default class ChallengeService { public async isChallengeDone( userChallenge: UserChallenge, dataloads: Dataload[] - ): Promise<{ isDone: boolean; isWin: boolean; isEmpty: boolean }> { + ): Promise<{ + isDone: boolean + isWin: boolean + isEmpty: boolean + }> { //TODO incorect value value when missing data let isDone = false let isWin = false diff --git a/src/services/exploration.service.ts b/src/services/exploration.service.ts index 3818fecc11fd27a6857bcfbfec0ef08c3b905f10..d2fcfc03f2c8310cd973dfb5fc311f14aef05572 100644 --- a/src/services/exploration.service.ts +++ b/src/services/exploration.service.ts @@ -8,7 +8,6 @@ import { } from 'enum/userExploration.enum' import { DateTime } from 'luxon' import { ExplorationEntity, UserChallenge, UserExploration } from 'models' -import { explorationEntity } from '../../test/__mocks__/explorationData.mock' import ChallengeService from './challenge.service' export default class ExplorationService { @@ -93,17 +92,14 @@ export default class ExplorationService { const explorationEntityIndex = explorationEntityList.findIndex( entity => entity.id === searchId ) - console.log('eeeee', explorationEntityIndex) if (explorationEntityIndex >= 0) { const explorationEntity: ExplorationEntity = explorationEntityList[explorationEntityIndex] - console.log('exploEntity', explorationEntity) exploration = this.parseExplorationEntityToUserExploration( explorationEntity ) } } - console.log('exploration', exploration) return exploration } @@ -122,7 +118,6 @@ export default class ExplorationService { keepLocalTime: true, }), } - console.log('parse', userExploration) return userExploration } diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 49052fd065fc335fffadf2cadb562794477b1b6c..52aef321e8b7f7b0edf527c5f7051de193e9a67d 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,5 +1,5 @@ import get from 'lodash/get' -import { Relation } from 'models' +import { GetRelationshipsReturn, Relation } from 'models' import { FluidType } from '../enum/fluid.enum' import { KonnectorUpdate } from '../enum/konnectorUpdate.enum' @@ -53,6 +53,32 @@ export function formatNumberValues( export function getRelationship<D>(doc: D, relName: string): Relation { return get(doc, `relationships.${relName}.data`, []) } + +/** + * Get array of items in one relation in doc + * + * @param {object} doc - DocumentEntity + * @param {string} relName - Name of the relation + */ +export function getRelationshipHasMany<D>(doc: D, relName: string): Relation[] { + return get(doc, `relationships.${relName}.data`, []) +} + +/** + * Get many relations in doc + * + * @param {object} doc - DocumentEntity + * @param {Array<[relName: string]: Array<Relation>>} relNameList - Array of name of the relations + */ +export function getRelationships<D>( + doc: D, + relNameList: Array<string> +): GetRelationshipsReturn { + return relNameList.map(relName => ({ + [relName]: get(doc, `relationships.${relName}.data`, []), + }))[0] +} + /** * * @param id