@@ -9,8 +9,15 @@ import { IndividualEnrollmentRepository } from '../repositories/IndividualEnroll
99import { Service } from 'typedi' ;
1010import { InjectRepository } from '../../typeorm-typedi-extensions' ;
1111import { HttpError } from 'routing-controllers' ;
12- import { MoocletValueRequestBody } from '../../types/Mooclet' ;
12+ import {
13+ MoocletPaginatedResponse ,
14+ MoocletRewardCountRequestBody ,
15+ MoocletValueRequestBody ,
16+ MoocletValueResponseDetails ,
17+ } from '../../types/Mooclet' ;
1318import { RewardValidator } from '../controllers/validators/RewardValidator' ;
19+ import { ExperimentRewardsByCondition , ExperimentRewardsSummary } from 'upgrade_types' ;
20+ import { MoocletExperimentService } from './MoocletExperimentService' ;
1421
1522export interface IRewardResponse {
1623 message : string ;
@@ -25,7 +32,8 @@ export class MoocletRewardsService {
2532 private moocletExperimentRefRepository : MoocletExperimentRefRepository ,
2633 @InjectRepository ( )
2734 private individualEnrollmentRepository : IndividualEnrollmentRepository ,
28- private moocletDataService : MoocletDataService
35+ private moocletDataService : MoocletDataService ,
36+ private moocletExperimentService : MoocletExperimentService
2937 ) { }
3038
3139 /**
@@ -204,6 +212,97 @@ export class MoocletRewardsService {
204212 return map . moocletVersionId ;
205213 }
206214
215+ public async getRewardsSummaryForExperiment (
216+ experimentId : string ,
217+ logger : UpgradeLogger
218+ ) : Promise < ExperimentRewardsSummary > {
219+ try {
220+ const moocletExperimentRef = await this . moocletExperimentService . getMoocletExperimentRefByUpgradeExperimentId (
221+ experimentId
222+ ) ;
223+ const rewards : MoocletValueResponseDetails [ ] = [ ] ;
224+ logger . info ( {
225+ message : `Fetching Rewards data from mooclet server.` ,
226+ experimentId,
227+ } ) ;
228+ let response = await this . fetchRewardsForExperiment ( moocletExperimentRef , logger ) ;
229+ if ( Array . isArray ( response . results ) ) {
230+ rewards . push ( ...response . results ) ;
231+ }
232+
233+ while ( response . next ) {
234+ logger . info ( {
235+ message : `But wait there's more (Fetching more Rewards data from Mooclet server for experiment...)` ,
236+ totalFound : response . count ,
237+ totalFetched : response . results . length ,
238+ next : response . next ,
239+ } ) ;
240+ response = await this . fetchRewardsForExperiment ( moocletExperimentRef , logger , response . next ) ;
241+ if ( Array . isArray ( response . results ) ) {
242+ rewards . push ( ...response . results ) ;
243+ }
244+ }
245+
246+ return this . createExperimentRewardsSummary ( moocletExperimentRef , rewards , logger ) ;
247+ } catch ( error ) {
248+ logger . error ( { message : 'Error fetching rewards summary for experiment' , experimentId, error } ) ;
249+ throw error ;
250+ }
251+ }
252+
253+ public async fetchRewardsForExperiment (
254+ moocletExperimentRef : MoocletExperimentRef ,
255+ logger : UpgradeLogger ,
256+ nextPageUrl ?: string
257+ ) : Promise < MoocletPaginatedResponse < MoocletValueResponseDetails > > {
258+ const requestBody : MoocletRewardCountRequestBody = {
259+ moocletId : moocletExperimentRef . moocletId ,
260+ variableName : moocletExperimentRef . outcomeVariableName ,
261+ } ;
262+
263+ return await this . moocletDataService . getRewardsForExperiment ( requestBody , logger , nextPageUrl ) ;
264+ }
265+
266+ public async createExperimentRewardsSummary (
267+ moocletExperimentRef : MoocletExperimentRef ,
268+ rewardsData : MoocletValueResponseDetails [ ] ,
269+ logger : UpgradeLogger
270+ ) : Promise < ExperimentRewardsSummary > {
271+ const rewards : MoocletValueResponseDetails [ ] = rewardsData ;
272+
273+ if ( ! rewardsData ) {
274+ logger . warn ( {
275+ message : 'No rewards data returned from Mooclet API' ,
276+ experimentId : moocletExperimentRef . experimentId ,
277+ } ) ;
278+ return [ ] ;
279+ }
280+
281+ const rewardsSummaries = moocletExperimentRef . versionConditionMaps . map (
282+ ( { experimentCondition, moocletVersionId } ) => {
283+ const versionRewards = rewards . filter ( ( reward ) => reward . version === moocletVersionId ) ;
284+ const successes = versionRewards . filter ( ( reward ) => reward . value === 1.0 ) . length ;
285+ const failures = versionRewards . filter ( ( reward ) => reward . value === 0.0 ) . length ;
286+ const total = successes + failures ;
287+ const percentSuccess = total > 0 ? ( successes / total ) * 100 : 0.0 ;
288+ const successRate = percentSuccess . toFixed ( 1 ) + '%' ;
289+
290+ const rewardsForCondition : ExperimentRewardsByCondition = {
291+ conditionCode : experimentCondition . conditionCode ,
292+ successes,
293+ failures,
294+ total,
295+ successRate,
296+ order : experimentCondition . order ,
297+ } ;
298+ return rewardsForCondition ;
299+ }
300+ ) ;
301+
302+ const orderedRewardsSummary = rewardsSummaries . sort ( ( a , b ) => a . order - b . order ) ;
303+ return orderedRewardsSummary ;
304+ }
305+
207306 /**
208307 * Throws a 409 data-conflict error for most unexpected cases
209308 */
0 commit comments