Commit bd62c3c4 authored by Rémi PAILHAREY's avatar Rémi PAILHAREY Committed by Guilhem CARRON
Browse files

feat(dacc): Add new indicator "uninitialized-konnector-attempts-monthly"

parent a573bd2e
@echo off
echo This script to export data from a cozy doctype
echo Please provide cozysessid (can be found after connection in browser dev tool)
set /p token="CozySessid ? : "
echo Please select your cozy instance name : 'https://mon.instance.cozygrandlyon.cloud/'
set /p instance="Instance ? : "
echo Please select the doctype name you wish to export (ex : com.grandlyon.egl.day)
set /p name="Choice ? : "
echo Please select the file name for exported data
set /p filename="Filename ? : "
echo Execute ACH -t %token% -u %instance% export %name% %filename%
echo Do not forget to delete tour token (AAAAA....etc.json) before executing another ACH command !
ACH -t %token% -u %instance% export %name% %filename%
@echo off
echo This script allows you to edit data in cozy alpha
echo Please provide cozysessid (can be found after connection in browser dev tool)
set /p token="CozySessid ? : "
echo Please select an action between drop and import
set /p action="Action ? : "
echo Please select your cozy instance name : 'https://mon.instance.cozygrandlyon.cloud/'
set /p instance="Instance ? : "
echo Please select the doctype name you wish to drop (ex : com.grandlyon.egl.day) or the pathh to the data file you wish to import
set /p name="Choice ? : "
echo Execute ACH -t %token% -u %instance% %action% %name%
echo Do not forget to delete tour token (AAAAA....etc.json) before executing another ACH command !
ACH -t %token% -u %instance% %action% %name%
......@@ -101,6 +101,7 @@ const ConnectionOAuth: React.FC<ConnectionOAuthProps> = ({
<ConnectionOAuthWithPartnerAccount
konnectorSlug={konnectorSlug}
konnector={konnector}
fluidStatus={fluidStatus}
handleSuccess={handleSuccess}
togglePartnerConnectionModal={togglePartnerConnectionModal}
/>
......@@ -108,6 +109,7 @@ const ConnectionOAuth: React.FC<ConnectionOAuthProps> = ({
<ConnectionOAuthNoPartnerAccount
konnectorSlug={konnectorSlug}
konnector={konnector}
fluidStatus={fluidStatus}
handleSuccess={handleSuccess}
togglePartnerConnectionModal={togglePartnerConnectionModal}
/>
......
import React from 'react'
import { useI18n } from 'cozy-ui/transpiled/react/I18n'
import './connectionOAuth.scss'
import { Konnector } from 'models'
import { FluidStatus, Konnector } from 'models'
import FormOAuth from 'components/Connection/FormOAuth'
import Button from '@material-ui/core/Button'
......@@ -10,6 +10,7 @@ interface ConnectionOAuthNoPartnerAccountProps {
konnector: Konnector | null
handleSuccess: (accountId: string) => Promise<void>
togglePartnerConnectionModal: () => void
fluidStatus: FluidStatus
}
const ConnectionOAuthNoPartnerAccount = ({
......@@ -17,6 +18,7 @@ const ConnectionOAuthNoPartnerAccount = ({
konnector,
handleSuccess,
togglePartnerConnectionModal,
fluidStatus,
}: ConnectionOAuthNoPartnerAccountProps) => {
const { t } = useI18n()
......@@ -53,9 +55,9 @@ const ConnectionOAuthNoPartnerAccount = ({
konnector={konnector}
onSuccess={handleSuccess}
highlightedStyle={false}
fluidStatus={fluidStatus}
/>
</div>
<div className="koauthform-infotext text-16-italic">
{t('auth.' + `${konnectorSlug}` + '.no_account.info')}
</div>
......
import React, { useCallback } from 'react'
import { useI18n } from 'cozy-ui/transpiled/react/I18n'
import './connectionOAuth.scss'
import { Konnector } from 'models'
import { FluidStatus, Konnector } from 'models'
import FormOAuth from 'components/Connection/FormOAuth'
import Button from '@material-ui/core/Button'
......@@ -10,6 +10,7 @@ interface ConnectionOAuthWithPartnerAccountProps {
konnector: Konnector | null
handleSuccess: (accountId: string) => Promise<void>
togglePartnerConnectionModal: () => void
fluidStatus: FluidStatus
}
const ConnectionOAuthWithPartnerAccount = ({
......@@ -17,6 +18,7 @@ const ConnectionOAuthWithPartnerAccount = ({
konnector,
handleSuccess,
togglePartnerConnectionModal,
fluidStatus,
}: ConnectionOAuthWithPartnerAccountProps) => {
const { t } = useI18n()
......@@ -41,6 +43,7 @@ const ConnectionOAuthWithPartnerAccount = ({
konnector={konnector}
onSuccess={handleSuccess}
highlightedStyle={true}
fluidStatus={fluidStatus}
/>
</div>
{konnectorSlug === 'grdfgrandlyon' && (
......
......@@ -82,6 +82,12 @@ const FormLogin: React.FC<FormLoginProps> = ({
const connect = async () => {
const connectionService = new ConnectionService(client)
try {
// If first connexion, send the usage event
await UsageEventService.addEvent(client, {
type: UsageEventType.KONNECTOR_ATTEMPT_EVENT,
target: konnectorSlug,
result: 'error',
})
const {
account: _account,
trigger: _trigger,
......@@ -97,7 +103,6 @@ const FormLogin: React.FC<FormLoginProps> = ({
trigger: _trigger,
}
setLoading(false)
// await sendUsageEventSuccess(konnectorSlug)
dispatch(updatedFluidConnection(fluidStatus.fluidType, updatedConnection))
handleSuccess()
} catch (err) {
......
......@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useState } from 'react'
import { useI18n } from 'cozy-ui/transpiled/react/I18n'
import { useClient } from 'cozy-client'
import './auth.scss'
import { Konnector } from 'models'
import { FluidStatus, Konnector } from 'models'
import { OAuthWindow } from 'cozy-harvest-lib/dist/components/OAuthWindow'
import Button from '@material-ui/core/Button'
import StyledIcon from 'components/CommonKit/Icon/StyledIcon'
......@@ -11,17 +11,21 @@ import { getPartnerPicto } from 'utils/picto'
import { useDispatch, useSelector } from 'react-redux'
import { AppStore } from 'store'
import { setShouldRefreshConsent } from 'store/global/global.actions'
import { UsageEventType } from 'enum/usageEvent.enum'
import UsageEventService from 'services/usageEvent.service'
interface FormOAuthProps {
konnector: Konnector | null
onSuccess: Function
highlightedStyle?: boolean
fluidStatus: FluidStatus
}
const FormOAuth: React.FC<FormOAuthProps> = ({
konnector,
onSuccess,
highlightedStyle = true,
fluidStatus,
}: FormOAuthProps) => {
const IDLE = 'idle'
const WAITING = 'waiting'
......@@ -39,9 +43,17 @@ const FormOAuth: React.FC<FormOAuthProps> = ({
dispatch(setShouldRefreshConsent(false))
}, [dispatch])
const startOAuth = useCallback(() => {
const startOAuth = useCallback(async () => {
// If first connexion, send the usage event
if (konnector && konnector.slug && fluidStatus.lastDataDate === null) {
await UsageEventService.addEvent(client, {
type: UsageEventType.KONNECTOR_ATTEMPT_EVENT,
target: konnector.slug,
result: 'error',
})
}
setStatus(WAITING)
}, [])
}, [client, fluidStatus.lastDataDate, konnector])
const handleAccountId = useCallback(
(accountId: string) => {
......
......@@ -36,7 +36,7 @@ interface KonnectorModalProps {
state: string | null
error: string | null
fluidType: FluidType
handleCloseClick: () => void
handleCloseClick: (isSuccess?: boolean) => void
}
const KonnectorModal: React.FC<KonnectorModalProps> = ({
......@@ -77,7 +77,7 @@ const KonnectorModal: React.FC<KonnectorModalProps> = ({
open={open}
disableBackdropClick
disableEscapeKeyDown
onClose={handleCloseClick}
onClose={() => handleCloseClick(state === SUCCESS_EVENT)}
aria-labelledby={'accessibility-title'}
classes={{
root: 'modal-root',
......@@ -184,7 +184,7 @@ const KonnectorModal: React.FC<KonnectorModalProps> = ({
{state !== LOGIN_SUCCESS_EVENT && (
<Button
aria-label={t('konnector_modal.accessibility.button_close')}
onClick={() => handleCloseClick()}
onClick={() => handleCloseClick(state === SUCCESS_EVENT)}
classes={{
root: 'btn-highlight',
label: 'text-16-bold',
......
......@@ -179,46 +179,57 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({
dispatch,
])
const handleConnectionEnd = useCallback(async () => {
if (
account &&
konnectorErrorDescription === 'LOGIN_FAILED' &&
fluidStatus !== null &&
fluidStatus.connection.account !== null &&
fluidStatus.connection.account.auth !== undefined &&
fluidStatus.connection.account.auth.login
) {
fluidStatus.connection.konnectorConfig.lastKnownCredentials =
const handleConnectionEnd = useCallback(
async (isSuccess?: boolean) => {
if (
account &&
konnectorErrorDescription === 'LOGIN_FAILED' &&
fluidStatus !== null &&
fluidStatus.connection.account !== null &&
fluidStatus.connection.account.auth !== undefined &&
fluidStatus.connection.account.auth.login
const accountService = new AccountService(client)
await accountService.deleteAccount(account)
await handleAccountDeletion()
} else {
if (updatedFluidStatus.length > 0) {
const partnersInfo: PartnersInfo = await partnersInfoService.getPartnersInfo()
const _updatedFluidStatus: FluidStatus[] = await fluidService.getFluidStatus(
partnersInfo
)
dispatch(setFluidStatus(_updatedFluidStatus))
) {
fluidStatus.connection.konnectorConfig.lastKnownCredentials =
fluidStatus.connection.account.auth.login
const accountService = new AccountService(client)
await accountService.deleteAccount(account)
await handleAccountDeletion()
} else {
if (isSuccess && fluidStatus.lastDataDate === null) {
await UsageEventService.udpateConnectionAttemptEvent(
client,
fluidSlug
)
}
if (updatedFluidStatus.length > 0) {
const partnersInfo: PartnersInfo = await partnersInfoService.getPartnersInfo()
const _updatedFluidStatus: FluidStatus[] = await fluidService.getFluidStatus(
partnersInfo
)
dispatch(setFluidStatus(_updatedFluidStatus))
}
}
}
setActive(false)
setOpenModal(false)
// TODO null state seems to be read before modal closing and display a success icon in modal
setKonnectorState(null)
setKonnectorErrorDescription(null)
}, [
account,
client,
dispatch,
fluidService,
fluidStatus,
handleAccountDeletion,
konnectorErrorDescription,
partnersInfoService,
setActive,
updatedFluidStatus.length,
])
setActive(false)
setOpenModal(false)
// TODO null state seems to be read before modal closing and display a success icon in modal
setKonnectorState(null)
setKonnectorErrorDescription(null)
},
[
account,
client,
dispatch,
fluidService,
fluidStatus,
handleAccountDeletion,
konnectorErrorDescription,
partnersInfoService,
setActive,
updatedFluidStatus.length,
fluidSlug,
]
)
const sendUsageEventSuccess = useCallback(
async (
......@@ -294,8 +305,10 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({
dispatch(
updatedFluidConnection(fluidStatus.fluidType, updatedConnection)
)
await refreshChallengeState()
await updateGlobalFluidStatus()
Promise.all([
await refreshChallengeState(),
await updateGlobalFluidStatus(),
])
setKonnectorState(_state)
}
},
......@@ -391,16 +404,12 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({
const connectionFlow = new ConnectionFlow(client, trigger, konnector)
await connectionFlow.launch()
connectionFlow.jobWatcher.on(ERROR_EVENT, () => {
if (subscribed) {
sendUsageEventError(fluidSlug, fluidStatus.lastDataDate === null)
}
sendUsageEventError(fluidSlug, fluidStatus.lastDataDate === null)
setKonnectorErrorDescription(connectionFlow.jobWatcher.on()._error)
callbackResponse(ERROR_EVENT)
})
connectionFlow.jobWatcher.on(LOGIN_SUCCESS_EVENT, () => {
if (subscribed) {
sendUsageEventSuccess(fluidSlug, fluidStatus.lastDataDate === null)
}
sendUsageEventSuccess(fluidSlug, fluidStatus.lastDataDate === null)
callbackResponse(LOGIN_SUCCESS_EVENT)
})
connectionFlow.jobWatcher.on(SUCCESS_EVENT, () => {
......
......@@ -1638,7 +1638,7 @@
"fluidTypes": [0, 2],
"shortName": "Tuyaux bien au chaud",
"longName": "J'isole les tuyaux de mon circuit de chauffage hydraulique.",
"longDescription": "Isolez les circuits de distribution deau de chauffage et deau chaude sanitaire dans les locaux non chauffés ou les faux-plafonds. Vous limiterez ainsi les déperditions de chaleur et améliorerez la protection du circuit contre le gel. Cela peut réduire de 10 % la consommation. Le plus simple est d’utiliser des manchons souples en mousse ou en fibres minérales. On peut aussi utiliser des isolants à base de laine ou de chanvre",
"longDescription": "Isolez les circuits de distribution d'eau de chauffage et d'eau chaude sanitaire dans les locaux non chauffés ou les faux-plafonds. Vous limiterez ainsi les déperditions de chaleur et améliorerez la protection du circuit contre le gel. Cela peut réduire de 10 % la consommation. Le plus simple est d’utiliser des manchons souples en mousse ou en fibres minérales. On peut aussi utiliser des isolants à base de laine ou de chanvre",
"impactLevel": 6,
"efficiency": 3,
"difficulty": 3,
......@@ -1684,7 +1684,7 @@
"fluidTypes": [1],
"shortName": "Nitro cuvette",
"longName": "J'installe une chasse d'eau à double vitesse.",
"longDescription": "L'installation d'une chasse d'eau double est à la portée de tous. Si les mécanismes sont généralement standard, veillez malgré tout à vérifier avant de l'acheter les dimensions du trou du couvercle dans lequel viendra se positionner le double bouton poussoir, ainsi que la hauteur du réservoir. Reste à suivre le pas à pas suivant : Commencez par couper l'arrivée d'eau et tirez la chasse pour vider le réservoir. Dévissez le bouton de tirage existant et ôtez le couvercle du réservoir. Dévissez l'arrivée d'eau, retirez le robinet flotteur et le mécanisme de la chasse. Dévissez les vis de fixation du réservoir et retirez-le. Changez le joint entre le réservoir et la cuvette, puis revissez le réservoir. Installez le nouveau mécanisme de chasse (à partir de 20€ dans les enseignes de bricolage). Clipsez le flotteur de réglage de la petite chasse, puis le mécanisme au complet. Revissez l'arrivée d'eau. Refermez le couvercle et installez le double bouton poussoir.À défaut, il est possible de réduire le volume de la chasse d’eau grâce à une éco-plaquette ou à une bouteille d’eau pleine placée dans le réservoir. Pour garantir son bon fonctionnement, nettoyez régulièrement le mécanisme de chasse d'eau double, particulièrement si votre eau est très calcaire.",
"longDescription": "L'installation d'une chasse d'eau double est à la portée de tous. Si les mécanismes sont généralement standard, veillez malgré tout à vérifier avant de l'acheter les dimensions du trou du couvercle dans lequel viendra se positionner le double bouton poussoir, ainsi que la hauteur du réservoir. Reste à suivre le pas à pas suivant : Commencez par couper l'arrivée d'eau et tirez la chasse pour vider le réservoir. Dévissez le bouton de tirage existant et ôtez le couvercle du réservoir. Dévissez l'arrivée d'eau, retirez le robinet flotteur et le mécanisme de la chasse. Dévissez les vis de fixation du réservoir et retirez-le. Changez le joint entre le réservoir et la cuvette, puis revissez le réservoir. Installez le nouveau mécanisme de chasse (à partir de 20€ dans les enseignes de bricolage). Clipsez le flotteur de réglage de la petite chasse, puis le mécanisme au complet. Revissez l'arrivée d'eau. Refermez le couvercle et installez le double bouton poussoir. À défaut, il est possible de réduire le volume de la chasse d’eau grâce à une éco-plaquette ou à une bouteille d’eau pleine placée dans le réservoir. Pour garantir son bon fonctionnement, nettoyez régulièrement le mécanisme de chasse d'eau double, particulièrement si votre eau est très calcaire.",
"impactLevel": 5,
"efficiency": 2.5,
"difficulty": 3,
......@@ -1753,7 +1753,7 @@
"fluidTypes": [0],
"shortName": "Blanc Resplendissant",
"longName": "Je peins mes murs avec des couleurs claires et j'installe des luminaires blancs.",
"longDescription": "Cela permet à la lumière naturelle de se répartir plus uniformément dans l’espace et de pénétrer plus profondément dans la pièce grâce aux jeux de réflexions. Cet effet des couleurs se remarque également sur la lumière artificielle : un intérieur foncé amène à doubler voire tripler l’intensité de l’éclairag",
"longDescription": "Cela permet à la lumière naturelle de se répartir plus uniformément dans l’espace et de pénétrer plus profondément dans la pièce grâce aux jeux de réflexions. Cet effet des couleurs se remarque également sur la lumière artificielle : un intérieur foncé amène à doubler voire tripler l’intensité de l’éclairage.",
"impactLevel": 2,
"efficiency": 1,
"difficulty": 3,
......
......@@ -12,6 +12,7 @@ export enum DaccEvent {
SUMMARY_SUBSCRIPTION_MONTHLY = 'summary-subscription-monthly',
FLUID_DATA_GRANULARITY = 'fluid-data-granularity-monthly',
PARTNER_SUCESS_MONTHLY = 'konnector-attempts-before-success',
UNINITIALIZED_KONNECTOR_ATTEMPTS_MONTHLY = 'uninitialized-konnector-attempts-monthly',
CONNECTION_COUNT_MONTHLY = 'connection-count-monthly',
PROFILE_COUNT_MONTHLY = 'profile-count',
}
export enum UsageEventType {
CONNECTION_EVENT = 'ConnectionEvent',
KONNECTOR_CONNECT_EVENT = 'KonnectorConnectEvent',
KONNECTOR_ATTEMPT_EVENT = 'KonnectorAttemptEvent',
KONNECTOR_REFRESH_EVENT = 'KonnectorRefreshEvent',
NAVIGATION_EVENT = 'NavigationEvent',
CONSUMPTION_COMPARE_EVENT = 'ConsumptionCompareEvent',
......
......@@ -56,6 +56,7 @@ export default class AccountService {
const query: QueryDefinition = Q(ACCOUNTS_DOCTYPE)
// eslint-disable-next-line @typescript-eslint/camelcase
.where({ account_type: type })
.indexFields(['account_type'])
const { data: accounts }: QueryResult<Account[]> = await this._client.query(
query
)
......@@ -99,6 +100,7 @@ export default class AccountService {
const query: QueryDefinition = Q(ACCOUNTS_DOCTYPE)
// eslint-disable-next-line @typescript-eslint/camelcase
.where({ account_type: type })
.indexFields(['account_type'])
const { data: accounts }: QueryResult<Account[]> = await this._client.query(
query
)
......@@ -129,6 +131,7 @@ export default class AccountService {
const query: QueryDefinition = Q(ACCOUNTS_DOCTYPE)
// eslint-disable-next-line @typescript-eslint/camelcase
.where({ account_type: 'index' })
.indexFields(['account_type'])
.limitBy(1)
const { data: result }: QueryResult<[]> = await this._client.query(query)
return result
......
......@@ -5,13 +5,13 @@ import EnvironmentService from './environment.service'
export default class PartnersInfoService {
private readonly _client: Client
private readonly _setinitStepError: React.Dispatch<
private readonly _setinitStepError?: React.Dispatch<
React.SetStateAction<InitStepsErrors | null>
>
constructor(
_client: Client,
_setinitStepError: React.Dispatch<
_setinitStepError?: React.Dispatch<
React.SetStateAction<InitStepsErrors | null>
>
) {
......@@ -35,7 +35,8 @@ export default class PartnersInfoService {
.fetchJSON('GET', remoteUrl)
return result as PartnersInfo
} catch (error) {
this._setinitStepError(InitStepsErrors.PARTNERS_ERROR)
this._setinitStepError &&
this._setinitStepError(InitStepsErrors.PARTNERS_ERROR)
console.error(error)
throw new Error("Failed to get partners' info")
}
......
......@@ -5,6 +5,8 @@ import { AddEventParams, UsageEventEntity } from 'models'
import { QueryResult } from 'cozy-client'
import {
allUsageEventsData,
connectionAttemptEGLError,
connectionAttemptEGLSuccess,
connectionEventEntitiesData,
connectionUsageEventsData,
usageEventData,
......@@ -59,6 +61,17 @@ describe('UsageEvent service', () => {
)
expect(result).toEqual(true)
})
it('should throw an error', async () => {
mockClient.save.mockRejectedValue(new Error())
try {
await UsageEventService.updateUsageEventsAggregated(
mockClient,
allUsageEventsData
)
} catch (error) {
expect(error).toEqual(new Error())
}
})
})
describe('getEvents method', () => {
it('should return all Connection events', async () => {
......@@ -75,4 +88,94 @@ describe('UsageEvent service', () => {
expect(result).toEqual(connectionUsageEventsData)
})
})
describe('addEventIfDoesntExist method', () => {
it('should not add event', async () => {
const mockQueryResult: QueryResult<UsageEventEntity[]> = {
data: connectionEventEntitiesData,
bookmark: '',
next: false,
skip: 0,
}
mockClient.query.mockResolvedValueOnce(mockQueryResult)
const result = await UsageEventService.addEventIfDoesntExist(
mockClient,
{ type: UsageEventType.CONNECTION_EVENT },
{ id: { $gt: 0 } }
)
expect(result).toEqual(null)
})
it('should add event', async () => {
const mockQueryResult: QueryResult<UsageEventEntity[]> = {
data: [],
bookmark: '',
next: false,
skip: 0,
}
mockClient.query.mockResolvedValueOnce(mockQueryResult)
const mockQueryResult2: QueryResult<UsageEventEntity> = {
data: usageEventEntityData,
bookmark: '',
next: false,
skip: 0,
}
mockClient.create.mockResolvedValueOnce(mockQueryResult2)
const result = await UsageEventService.addEventIfDoesntExist(
mockClient,
{ type: UsageEventType.CONNECTION_EVENT },
{ id: { $gt: 0 } }
)
expect(result).toEqual(usageEventData)
})
})
describe('udpateConnectionAttemptEvent method', () => {
it('should update the last attempt to true', async () => {
const mockQueryResult: QueryResult<UsageEventEntity[]> = {
data: [connectionAttemptEGLError],
bookmark: '',
next: false,
skip: 0,
}
const mockQueryResult2: QueryResult<UsageEventEntity> = {
data: connectionAttemptEGLSuccess,
bookmark: '',
next: false,
skip: 0,
}
mockClient.query.mockResolvedValueOnce(mockQueryResult)
mockClient.save.mockResolvedValueOnce(mockQueryResult2)
const result = await UsageEventService.udpateConnectionAttemptEvent(
mockClient,
'eglgrandlyon'
)
expect(result).toEqual(connectionAttemptEGLSuccess)
})
it('should fail to update the attempts', async () => {
const mockQueryResult: QueryResult<UsageEventEntity[] | undefined> = {
data: undefined,
bookmark: '',
next: false,
skip: 0,
}
mockClient.query.mockResolvedValueOnce(mockQueryResult)
const result = await UsageEventService.udpateConnectionAttemptEvent(
mockClient,
'eglgrandlyon'
)
expect(result).toEqual(undefined)
})
it('should find no attempt', async () => {
const mockQueryResult: QueryResult<UsageEventEntity[] | undefined> = {
data: [],
bookmark: '',
next: false,
skip: 0,
}
mockClient.query.mockResolvedValueOnce(mockQueryResult)
const result = await UsageEventService.udpateConnectionAttemptEvent(
mockClient,
'eglgrandlyon'
)
expect(result).toEqual(undefined)
})
})
})
......@@ -6,6 +6,7 @@ import {
MongoSelector,
} from 'cozy-client'
import { USAGEEVENT_DOCTYPE } from 'doctypes'
import { UsageEventType } from 'enum/usageEvent.enum'
import { DateTime } from 'luxon'
import {
AddEventParams,
......@@ -60,6 +61,45 @@ export default class UsageEventService {
return null
}
/**
*
* @param {Client} client
* @param {string} konnectorSlug
* @returns
*/
static async udpateConnectionAttemptEvent(
client: Client,
konnectorSlug: string
): Promise<UsageEventEntity | undefined> {
try {
//Get last Connection attempt Event
const query: QueryDefinition = Q(USAGEEVENT_DOCTYPE)
.where({
type: UsageEventType.KONNECTOR_ATTEMPT_EVENT,
target: konnectorSlug,
result: 'error',
})
.sortBy([{ eventDate: 'desc' }])
.limitBy(1)
const {
data: [usageEventEntity],
}: QueryResult<UsageEventEntity[]> = await client.query(query)
if (usageEventEntity) {
const updatedEvent: UsageEventEntity = {
...usageEventEntity,
result: 'success',