Skip to content

Commit

Permalink
feat(api): add sixth grade attestation script
Browse files Browse the repository at this point in the history
  • Loading branch information
Guillaume committed Dec 16, 2024
1 parent 70c5490 commit a1916d8
Show file tree
Hide file tree
Showing 2 changed files with 451 additions and 0 deletions.
132 changes: 132 additions & 0 deletions api/src/profile/scripts/sixth-grade-attestation-reward.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import dayjs from 'dayjs';

import { CampaignParticipationStatuses } from '../../prescription/shared/domain/constants.js';
import { usecases } from '../../quest/domain/usecases/index.js';
import { isoDateParser } from '../../shared/application/scripts/parsers.js';
import { Script } from '../../shared/application/scripts/script.js';
import { ScriptRunner } from '../../shared/application/scripts/script-runner.js';
import { DomainTransaction } from '../../shared/domain/DomainTransaction.js';

export const PRODUCTION_SIXTH_GRADE_TARGET_PROFILE_IDS = [
1000000, 1000001, 1000002, 1000003, 1000004, 1000005, 1000006, 1000007, 1100001, 1100002, 1100003, 1100004, 1100005,
];

const options = {
start: {
type: 'string',
describe: 'Date de début de la période à traiter, jour inclus, format "YYYY-MM-DD", (ex: "2024-01-20")',
demandOption: false,
requiresArg: true,
coerce: isoDateParser(),
},
end: {
type: 'string',
describe: 'Date de fin de la période à traiter, jour inclus, format "YYYY-MM-DD", (ex: "2024-02-27")',
demandOption: true,
requiresArg: true,
coerce: isoDateParser(),
},
limit: {
type: 'number',
describe: 'Nombre de jours maximum entre les deux dates, par défaut 7',
demandOption: false,
requiresArg: false,
default: 7,
coerce: Number,
},
};

/**
* Fetch the userIDs of the users who have already completed a campaign linked to the specified target profiles.
*
* @param {Date} startDate
* @param {Date} endDate
*
* @returns {Promise<[number]>}
*/
export const fetchUserIds = async (startDate, endDate) => {
endDate.setDate(endDate.getDate() + 1);
const knexConnection = DomainTransaction.getConnection();
const users = await knexConnection('campaign-participations')
.select('campaign-participations.userId')
.join('campaigns', 'campaign-participations.campaignId', 'campaigns.id')
.join('target-profiles', 'campaigns.targetProfileId', 'target-profiles.id')
.where('campaign-participations.createdAt', '>=', startDate)
.where('campaign-participations.createdAt', '<=', endDate)
.where('campaign-participations.status', '<>', CampaignParticipationStatuses.STARTED)
.whereIn('campaigns.targetProfileId', PRODUCTION_SIXTH_GRADE_TARGET_PROFILE_IDS);

return users.map(({ userId }) => userId);
};

/**
* Check if the end date is before the start date.
*
* @param {Date} startDate
* @param {Date} endDate
*/
const checkEndDateBeforeStartDate = (startDate, endDate) => {
if (endDate < startDate) {
throw new Error('The end date must be greater than the start date');
}
};

/**
* Check if the difference between the two dates is less than the limit in days.
*
* @param {Date} startDate
* @param {Date} endDate
* @param {number} limitInDays
*
* @throws {Error}
*/
const checkDifferenceBetweenDates = (startDate, endDate, limitInDays) => {
if (dayjs(endDate).diff(startDate, 'day') >= limitInDays) {
throw new Error('The difference between the two dates must be less than 7 days');
}
};

/**
* Script to reward sixth-grade students who have already completed a campaign linked to a specific target profile.
*/
export class SixthGradeAttestationRewardScript extends Script {
constructor() {
super({
description:
'This script process attestations rewards for users who have already completed a campaign linked to specific target profiles.',
permanent: false,
options,
});
}

/**
* Handles the core logic of the script.
*
* @param {{start: Date, end: Date, limit: number}} options
* @param {{info: function}} logger
* @param {function} rewardUser
* @returns {Promise<void>}
*/
async handle({ options, logger, rewardUser = usecases.rewardUser }) {
checkEndDateBeforeStartDate(options.start, options.end);
checkDifferenceBetweenDates(options.start, options.end, options.limit);

const users = await fetchUserIds(options.start, options.end);

if (users.length === 0) {
logger.info('No user found');
return;
}

logger.info(`${users.length} users found`);

for (const userId of users) {
logger.info(`Processing user ${userId}`);
await rewardUser({
userId,
});
}
}
}

await ScriptRunner.execute(import.meta.url, SixthGradeAttestationRewardScript);
Loading

0 comments on commit a1916d8

Please sign in to comment.