Newer
Older
import { Client } from 'cozy-client'

Hugo SUBTIL
committed
import challengeEntityData from 'db/challengeEntity.json'
import duelEntityData from 'db/duelEntity.json'
import ecogestureData from 'db/ecogestureData.json'
import explorationEntityData from 'db/explorationEntity.json'
import profileData from 'db/profileData.json'
import quizEntityData from 'db/quizEntity.json'

Hugo SUBTIL
committed
CHALLENGE_DOCTYPE,
DUEL_DOCTYPE,

Hugo SUBTIL
committed
EXPLORATION_DOCTYPE,
PROFILE_DOCTYPE,
QUIZ_DOCTYPE,
} from 'doctypes'
import { FluidType } from 'enum/fluid.enum'

Hugo SUBTIL
committed
import { DateTime } from 'luxon'

Hugo SUBTIL
committed
import { InitSteps, InitStepsErrors } from 'models/initialisationSteps.model'
import { ProfileEcogesture } from 'models/profileEcogesture.model'
import React from 'react'
import ChallengeService from 'services/challenge.service'
import DuelService from 'services/duel.service'

Hugo SUBTIL
committed
import EcogestureService from 'services/ecogesture.service'
import ExplorationService from 'services/exploration.service'

Hugo SUBTIL
committed
import FluidService from 'services/fluid.service'
import KonnectorStatusService from 'services/konnectorStatus.service'
import ProfileService from 'services/profile.service'
import QuizService from 'services/quiz.service'
import { getActualAnalysisDate } from 'utils/date'

Hugo SUBTIL
committed
import { hashFile } from 'utils/hash'
import EnvironmentService from './environment.service'

Hugo SUBTIL
committed
import FluidPricesService from './fluidsPrices.service'
import ProfileEcogestureService from './profileEcogesture.service'
import ProfileTypeEntityService from './profileTypeEntity.service'
import TermsService from './terms.service'
import logger from 'cozy-logger'
import {
REMOTE_ORG_ECOLYO_AGENT_PRICES,
REMOTE_ORG_ECOLYO_AGENT_PRICES_REC,
} from 'doctypes/remote/org.ecolyo.agent.prices'
const cozyLog = logger.namespace('initializationService')
export default class InitializationService {
private readonly _client: Client
private readonly _setinitStep: React.Dispatch<React.SetStateAction<InitSteps>>
private readonly _setinitStepError: React.Dispatch<
React.SetStateAction<InitStepsErrors | null>
>
constructor(
_client: Client,
_setinitStep: React.Dispatch<React.SetStateAction<InitSteps>>,
_setinitStepError: React.Dispatch<
React.SetStateAction<InitStepsErrors | null>
>
) {
this._setinitStep = _setinitStep
this._setinitStepError = _setinitStepError
}
/*
* Check if profil exist
* If not, the profil is created
* sucess return: profil
* failure return: null
*/
public async initProfile(): Promise<Profile | null> {
const profileService = new ProfileService(this._client)
try {
this._setinitStep(InitSteps.PROFILE)
const loadedProfile = await profileService.getProfile()
if (!loadedProfile) {
// Population with the data
const { data: newProfile } = await this._client.create(
PROFILE_DOCTYPE,
profileData[0]
)
if (newProfile) {
log.info('[Initialization] Profile created')
} else {
this._setinitStepError(InitStepsErrors.PROFILE_ERROR)
throw new Error('initProfile: Profile not created')
}
} else {
log.info('[Initialization] Profile loaded')
}
const updatedProfile = await profileService.updateProfile({
lastConnectionDate: DateTime.local().setZone('utc', {
keepLocalTime: true,
}),
})
return updatedProfile
} catch (error) {
this._setinitStepError(InitStepsErrors.PROFILE_ERROR)
log.error('Initialization error - initProfile: ', error)
throw error
}
}
/*
* Check if profileType exist
* If not, the profileType is created
* sucess return: profileType
* failure return: null
*/
public async initProfileType(): Promise<ProfileType | null> {
const profileTypeEntityService = new ProfileTypeEntityService(this._client)
try {
const loadedProfileType = await profileTypeEntityService.getProfileType()
log.info('[Initialization] ProfileType loaded')
return loadedProfileType
} catch (error) {
this._setinitStepError(InitStepsErrors.PROFILETYPE_ERROR)
log.error('Initialization error - initProfileType: ', error)
throw error
}
}
public async initProfileEcogesture(): Promise<ProfileEcogesture | null> {
const profileEcogestureService = new ProfileEcogestureService(this._client)
try {
const loadedProfileEcogesture =
await profileEcogestureService.getProfileEcogesture()
log.info('[Initialization] ProfileEcogesture loaded')
return loadedProfileEcogesture
} catch (error) {
this._setinitStepError(InitStepsErrors.PROFILETYPE_ERROR)
log.error('Initialization error - initProfileEcogesture: ', error)
throw error
}
}
public async initEcogesture(hash: string): Promise<string> {
this._setinitStep(InitSteps.ECOGESTURE)
const hashEcogestureType = hashFile(ecogestureData)
const ecogestureService = new EcogestureService(this._client)
// Populate data if none ecogesture exists
const loadedEcogestures = await ecogestureService.getAllEcogestures(
undefined,
true
)
if (!loadedEcogestures || loadedEcogestures?.length === 0) {
// Populate the doctype with data
try {
for (const ecogesture of ecogestureData) {
await this._client.create(ECOGESTURE_DOCTYPE, ecogesture)
}
// Check of created document based on count
const checkCount = await ecogestureService.getAllEcogestures()
if (!checkCount || checkCount?.length !== ecogestureData.length) {
this._setinitStepError(InitStepsErrors.ECOGESTURE_ERROR)
throw new Error(
'initEcogesture: Created ecogesture type entities does not match'
)
}
log.info('[Initialization] Ecogesture list created')
return hashEcogestureType
} catch (error) {
this._setinitStepError(InitStepsErrors.ECOGESTURE_ERROR)
log.error('Initialization error - initEcogesture: ', error)
throw error
}
}
// Update if the hash is not the same as the one from profile
if (hash !== hashEcogestureType) {
// Update the doctype
try {
// Deletion of all documents
await ecogestureService.deleteAllEcogestures()
// Population with the data
for (const [index, ecogesture] of ecogestureData.entries()) {
const updateEcogesture = loadedEcogestures[index]
? {
...ecogesture,
objective: loadedEcogestures[index].objective ? true : false,
doing: loadedEcogestures[index].doing ? true : false,
viewedInSelection: loadedEcogestures[index].viewedInSelection
? true
: false,
}
: ecogesture
await this._client.create(ECOGESTURE_DOCTYPE, updateEcogesture)
}
// Check of created document based on count
const checkCount = await ecogestureService.getAllEcogestures()
if (!checkCount || checkCount?.length !== ecogestureData.length) {
this._setinitStepError(InitStepsErrors.ECOGESTURE_ERROR)
throw new Error(
'initEcogesture: Created ecogesture type entities does not match'
)
}
log.info('[Initialization] Ecogesture updated')
return hashEcogestureType
} catch (error) {
this._setinitStepError(InitStepsErrors.ECOGESTURE_ERROR)
log.error('Initialization error - initEcogesture: ', error)
throw error
}
} else {
// Doctype already up to date
log.info('[Initialization] Ecogesture already up-to-date')
public async initFluidPrices(): Promise<boolean> {
const fpService = new FluidPricesService(this._client)
// Populate data if none ecogesture exists
const loadedPrices = await fpService.getAllPrices()
if (loadedPrices?.length) {
log.info('[Initialization] FluidPrices db already created')
return true
} else {
const fluidTypes: FluidType[] = [
FluidType.ELECTRICITY,
FluidType.WATER,
FluidType.GAS,
]
const allPrices: FluidPrice[] = []
const env = new EnvironmentService()
const remoteUrl = env.isProduction()
? REMOTE_ORG_ECOLYO_AGENT_PRICES
: REMOTE_ORG_ECOLYO_AGENT_PRICES_REC
for (const fluid of fluidTypes) {
const prices = await this._client
.getStackClient()
.fetchJSON('GET', `${remoteUrl}?fluidtype=${fluid}`)
allPrices.push(...prices)
for (const price of allPrices) {
await fpService.createPrice(price)
log.info('[Initialization] FluidPrices db created successfully')
return true
} catch (err) {
log.error('Initialization error - initFluidPrices: ', err)
cozyLog('error', `Initialization error - initFluidPrices: ${err}`)
}
}
}
public async initChallengeEntity(hash: string): Promise<string> {
this._setinitStep(InitSteps.CHALLENGES)
const challengeHash = hashFile(challengeEntityData)
const challengeService = new ChallengeService(this._client)
// Populate data if none challengeEntity exists
const loadedChallengeEntity =
await challengeService.getAllChallengeEntities()
if (!loadedChallengeEntity || loadedChallengeEntity?.length === 0) {
// Populate the doctype with data
try {
for (const challengeEntity of challengeEntityData) {
await this._client.create(CHALLENGE_DOCTYPE, challengeEntity)
}
// Check of created document
const checkCount = await challengeService.getAllChallengeEntities()
if (!checkCount || checkCount?.length !== challengeEntityData.length) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
throw new Error(
'initChallengeEntity: Created challenge entities does not match'
)
}
log.info('[Initialization] Challenge entities created')
return challengeHash
} catch (error) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
log.error('Initialization error - initChallengeEntity: ', error)
throw error
}
}
// Update if the hash is not the same as the one from profile
if (hash !== challengeHash) {
// Update the doctype
try {
// Deletion of all documents
await challengeService.deleteAllChallengeEntities()
// Population with the data
for (const challengeEntity of challengeEntityData) {
await this._client.create(CHALLENGE_DOCTYPE, challengeEntity)
}
// Check of created document
const checkCount = await challengeService.getAllChallengeEntities()
if (!checkCount || checkCount?.length !== challengeEntityData.length) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
throw new Error(
'initChallengeEntity: Created challenge entities does not match'
)
}
log.info('[Initialization] Challenge entities updated')
return challengeHash
} catch (error) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
log.error('Initialization error - initChallengeEntity: ', error)
throw error
}
} else {
// Doctype already up to date
log.info('[Initialization] Challenge Entity loaded')
return challengeHash
}
}
public async initDuelEntity(hash: string): Promise<string> {
const hashDuelEntity = hashFile(duelEntityData)
const duelService = new DuelService(this._client)
// Populate data if none DuelEntity exists
const loadedDuelTypes = await duelService.getAllDuelEntities()
if (!loadedDuelTypes || loadedDuelTypes?.length === 0) {
// Populate the doctype with data
try {
for (const duelEntity of duelEntityData) {
await this._client.create(DUEL_DOCTYPE, duelEntity)
}
// Check of created document
const checkCount = await duelService.getAllDuelEntities()
if (!checkCount || checkCount?.length !== duelEntityData.length) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
throw new Error(
'initDuelEntity: Created duel entities does not match'
)
}
log.info('[Initialization] UserDuel entities created')
return hashDuelEntity
} catch (error) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
log.error('Initialization error - initDuelEntity: ', error)
throw error
}
}
// Update if the hash is not the same as the one from profile
if (hash !== hashDuelEntity) {
// Update the doctype
try {
// Deletion of all documents
await duelService.deleteAllDuelEntities()
// Population with the data
for (const duelEntity of duelEntityData) {
await this._client.create(DUEL_DOCTYPE, duelEntity)
}
// Check of created document
const checkCount = await duelService.getAllDuelEntities()
if (!checkCount || checkCount?.length !== duelEntityData.length) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
throw new Error(
'initDuelEntity: Created duel entities does not match'
)
}
log.info('[Initialization] UserDuel entities updated')
return hashDuelEntity
} catch (error) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
log.error('Initialization error - initDuelEntity: ', error)
throw error
}
} else {
// Doctype already up to date
return hashDuelEntity
}
}
public async initQuizEntity(hash: string): Promise<string> {
const quizHash = hashFile(quizEntityData)
const quizService = new QuizService(this._client)
// Populate data if none quizEntity exists
const loadedQuizEntity = await quizService.getAllQuizEntities()
if (!loadedQuizEntity || loadedQuizEntity?.length === 0) {
// Populate the doctype with data
try {
for (const quizEntity of quizEntityData) {
await this._client.create(QUIZ_DOCTYPE, quizEntity)
}
// Check of created document
const checkCount = await quizService.getAllQuizEntities()
if (!checkCount || checkCount?.length !== quizEntityData.length) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
throw new Error(
'initQuizEntity: Created quiz entities does not match'
)
}
log.info('[Initialization] Quiz entities created')
return quizHash
} catch (error) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
log.error('Initialization error - initQuizEntity: ', error)
throw error
}
}
// Update if the hash is not the same as the one from profile
if (hash !== quizHash) {
// Update the doctype
try {
// Deletion of all documents
await quizService.deleteAllQuizEntities()
// Population with the data
for (const quizEntity of quizEntityData) {
await this._client.create(QUIZ_DOCTYPE, quizEntity)
}
// Check of created document
const checkCount = await quizService.getAllQuizEntities()
if (!checkCount || checkCount?.length !== quizEntityData.length) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
throw new Error(
'initQuizEntity: Created quiz entities does not match'
)
}
log.info('[Initialization] Quiz entities updated')
return quizHash
} catch (error) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
log.error('Initialization error - initQuizEntity: ', error)
throw error
}
} else {
// Doctype already up to date
log.info('[Initialization] Quiz Entity loaded')
return quizHash
}
}
public async initExplorationEntity(hash: string): Promise<string> {
const explorationHash = hashFile(explorationEntityData)
const explorationService = new ExplorationService(this._client)
// Populate data if none explorationEntity exists
const loadedExplorationEntity =
await explorationService.getAllExplorationEntities()
if (!loadedExplorationEntity || loadedExplorationEntity?.length === 0) {
// Populate the doctype with data
try {
for (const explorationEntity of explorationEntityData) {
await this._client.create(EXPLORATION_DOCTYPE, explorationEntity)
}
// Check of created document
const checkCount = await explorationService.getAllExplorationEntities()
if (
!checkCount ||
checkCount?.length !== explorationEntityData.length
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
throw new Error(
'initExplorationEntity: Created exploration entities does not match'
)
}
log.info('[Initialization] Exploration entities created')
return explorationHash
} catch (error) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
log.error('Initialization error - initExplorationEntity: ', error)
throw error
}
}
// Update if the hash is not the same as the one from profile
if (hash !== explorationHash) {
// Update the doctype
try {
// Deletion of all documents
await explorationService.deleteAllExplorationEntities()
// Population with the data
for (const explorationEntity of explorationEntityData) {
await this._client.create(EXPLORATION_DOCTYPE, explorationEntity)
}
// Check of created document
const checkCount = await explorationService.getAllExplorationEntities()
if (
!checkCount ||
checkCount?.length !== explorationEntityData.length
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
throw new Error(
'initExplorationEntity: Created exploration entities does not match'
)
}
log.info('[Initialization] Exploration entities updated')
return explorationHash
} catch (error) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
log.error('Initialization error - initExplorationEntity: ', error)
throw error
}
} else {
// Doctype already up to date
log.info('[Initialization] Exploration Entity loaded')
return explorationHash
}
}
public async initAnalysis(profile: Profile): Promise<{
monthlyAnalysisDate: DateTime
haveSeenLastAnalysis: boolean
}> {
try {
const actualAnalysisDate = getActualAnalysisDate()
if (
profile.monthlyAnalysisDate &&
actualAnalysisDate <= profile.monthlyAnalysisDate
) {
return {
monthlyAnalysisDate: profile.monthlyAnalysisDate,
haveSeenLastAnalysis: profile.haveSeenLastAnalysis,
}
} else {
log.info('[Initialization] Analysis information from profile updated')
return {
monthlyAnalysisDate: actualAnalysisDate,
haveSeenLastAnalysis: profile.isFirstConnection ? true : false,
}
}
} catch (error) {
this._setinitStepError(InitStepsErrors.ANALYSIS_ERROR)
log.error('Initialization error - initAnalysis: ', error)
throw error
}
}
/*
* Check if FluidTypes exist
* sucess return: FluidType[]
* failure throw error
*/
public async initFluidTypes(): Promise<FluidType[]> {
const kss = new KonnectorStatusService(this._client)
try {
const fluidtypes = await kss.getKonnectorAccountStatus()
if (fluidtypes) {
log.info('[Initialization] Fluid Types loaded')
return fluidtypes
} else {
this._setinitStepError(InitStepsErrors.CONSOS_ERROR)
throw new Error('initFluidTypes: FluidTypes not found')
}
} catch (error) {
this._setinitStepError(InitStepsErrors.CONSOS_ERROR)
log.error('Initialization error - initFluidTypes: ', error)
throw error
}
}
/*
* For each fluid get the trigger status and the last data date
* sucess return: FluidStatus[]
* failure throw error
*/
public async initFluidStatus(): Promise<FluidStatus[]> {
const fs = new FluidService(this._client)
try {
this._setinitStep(InitSteps.CONSOS)
const fluidStatus = await fs.getFluidStatus()
if (fluidStatus) {
log.info('[Initialization] Fluid Status loaded')
return fluidStatus
} else {
this._setinitStepError(InitStepsErrors.CONSOS_ERROR)
throw new Error('initFluidStatus: fluidStatus not found')
}
} catch (error) {
this._setinitStepError(InitStepsErrors.CONSOS_ERROR)
log.error('Initialization error - initFluidStatus: ', error)
throw error
}
}
/*
* Build the userChallengeList
* sucess return: UserChallenge[]
* failure throw error
*/
public async initUserChallenges(
fluidStatus: FluidStatus[]
): Promise<UserChallenge[]> {
const challengeService = new ChallengeService(this._client)
try {
const userChallengeList = await challengeService.buildUserChallengeList(
fluidStatus
)
if (userChallengeList) {
log.info('[Initialization] Challenges loaded')
return userChallengeList
} else {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
throw new Error('initUserChallenges: userChallengeList not found')
}
} catch (error) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
log.error('Initialization error - initUserChallenges: ', error)
throw error
}
}
/*
* Retrieve dataloads for ongoing duel
* sucess return: UserChallenge, Dataload[]
* failure throw error
*/
public async initDuelProgress(userChallenge: UserChallenge): Promise<{
updatedUserChallenge: UserChallenge
dataloads: Dataload[]
}> {
const challengeService = new ChallengeService(this._client)
try {
const { updatedUserChallenge, dataloads } =
await challengeService.initChallengeDuelProgress(userChallenge)
return { updatedUserChallenge, dataloads }
} catch (error) {
this._setinitStepError(InitStepsErrors.CHALLENGES_ERROR)
log.error('Initialization error: ', error)
throw error
}
}
Yoan VALLET
committed
public async initConsent(): Promise<TermsStatus> {
const termsStatus: TermsStatus = {
accepted: false,
versionType: 'init',
}
this._setinitStep(InitSteps.CONSENT)
const termService = new TermsService(this._client)
const isUpToDate = await termService.isConsentVersionUpToDate()
const lastTerm = await termService.getLastTerm()
if (lastTerm) {
if (isUpToDate) {
const isLastConsentValidated = await termService.isLastTermValidated()
if (isLastConsentValidated) {
termsStatus.accepted = true
termsStatus.versionType = 'init'
log.info(
'[Initialization] Last Consent successfully loaded and valid'
)
} else {
termsStatus.versionType = 'init'
termsStatus.accepted = false
log.info('[Initialization] Consent not up-to-date')
}
const versionType = await termService.getTermsVersionType()
if (versionType === 'minor') {
termsStatus.accepted = false
termsStatus.versionType = 'minor'
log.info('[Initialization] Minor Terms update detected')
} else {
termsStatus.accepted = false
termsStatus.versionType = 'major'
log.info('[Initialization] Major Terms update detected')
}
termsStatus.accepted = false
termsStatus.versionType = 'init'
log.info('[Initialization] Init first terms')
this._setinitStepError(InitStepsErrors.CONSENT_ERROR)
log.error('Initialization error - initConsent: ', error)
throw error
}
}
}