Skip to content

Commit

Permalink
chore: api: migrate publish related methods from repository
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandrecoin committed Oct 8, 2024
1 parent 5fa5c71 commit b9e6029
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 143 deletions.
38 changes: 1 addition & 37 deletions api/lib/infrastructure/repositories/certification-repository.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,7 @@
import { knex } from '../../../db/knex-database-connection.js';

const publishCertificationCourses = async function (certificationStatuses) {
const certificationDataToUpdate = certificationStatuses.map(({ certificationCourseId }) => ({
id: certificationCourseId,
isPublished: true,
updatedAt: new Date(),
version: -1, // Version number used to meet requirements regarding the version column non-null constraint in the insert request below
}));

// Trick to .batchUpdate(), which does not exist in knex per say
await knex('certification-courses')
.insert(certificationDataToUpdate)
.onConflict('id')
.merge(['isPublished', 'updatedAt']);
};

const getStatusesBySessionId = async function (sessionId) {
return knex('certification-courses')
.select({
certificationCourseId: 'certification-courses.id',
isCancelled: 'certification-courses.isCancelled',
pixCertificationStatus: 'assessment-results.status',
})
.where('certification-courses.sessionId', sessionId)
.join('assessments', 'assessments.certificationCourseId', 'certification-courses.id')
.leftJoin(
'certification-courses-last-assessment-results',
'certification-courses.id',
'certification-courses-last-assessment-results.certificationCourseId',
)
.leftJoin(
'assessment-results',
'assessment-results.id',
'certification-courses-last-assessment-results.lastAssessmentResultId',
);
};

const unpublishCertificationCoursesBySessionId = async function (sessionId) {
await knex('certification-courses').where({ sessionId }).update({ isPublished: false, updatedAt: new Date() });
};

export { getStatusesBySessionId, publishCertificationCourses, unpublishCertificationCoursesBySessionId };
export { unpublishCertificationCoursesBySessionId };
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
assessmentRepository,
assessmentResultRepository,
certificationChallengeRepository,
certificationRepository,
challengeRepository,
competenceMarkRepository,
cpfExportRepository,
Expand All @@ -39,6 +40,7 @@ import { cpfReceiptsStorage } from '../../infrastructure/storage/cpf-receipts-st
* @typedef {import('../../infrastructure/repositories/index.js').AssessmentResultRepository} AssessmentResultRepository
* @typedef {import('../../infrastructure/repositories/index.js').CompetenceMarkRepository} CompetenceMarkRepository
* @typedef {import('../../infrastructure/repositories/index.js').ChallengeRepository} ChallengeRepository
* @typedef {import('../../infrastructure/repositories/index.js').CertificationRepository} CertificationRepository
* @typedef {import('../../infrastructure/repositories/index.js').AnswerRepository} AnswerRepository
* @typedef {import('../../infrastructure/repositories/index.js').IssueReportCategoryRepository} IssueReportCategoryRepository
* @typedef {import('../../infrastructure/repositories/index.js').CertificationIssueReportRepository} CertificationIssueReportRepository
Expand Down Expand Up @@ -76,6 +78,7 @@ import { cpfReceiptsStorage } from '../../infrastructure/storage/cpf-receipts-st
* @typedef {certificationOfficerRepository} CertificationOfficerRepository
* @typedef {certificationChallengeRepository} CertificationChallengeRepository
* @typedef {challengeRepository} ChallengeRepository
* @typedef {certificationRepository} CertificationRepository
* @typedef {finalizedSessionRepository} FinalizedSessionRepository
* @typedef {juryCertificationRepository} JuryCertificationRepository
* @typedef {jurySessionRepository} JurySessionRepository
Expand Down Expand Up @@ -107,6 +110,7 @@ const dependencies = {
answerRepository,
sharedCompetenceMarkRepository,
challengeRepository,
certificationRepository,
competenceMarkRepository,
cpfReceiptsStorage,
cpfExportsStorage,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @typedef {import ('../../../../../lib/domain/usecases/index.js').CertificationRepository} CertificationRepository
* @typedef {import ('../../../../../src/certification/session-management/domain/usecases/index.js').CertificationRepository} CertificationRepository
* @typedef {import ('../../../../../lib/domain/usecases/index.js').FinalizedSessionRepository} FinalizedSessionRepository
* @typedef {import ('../../../../../lib/domain/usecases/index.js').SharedSessionRepository} SharedSessionRepository
* @typedef {import ('../../../../../lib/domain/usecases/index.js').SessionRepository} SessionRepository
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { knex } from '../../../../../db/knex-database-connection.js';

const getStatusesBySessionId = async function (sessionId) {
return knex('certification-courses')
.select({
certificationCourseId: 'certification-courses.id',
isCancelled: 'certification-courses.isCancelled',
pixCertificationStatus: 'assessment-results.status',
})
.where('certification-courses.sessionId', sessionId)
.join('assessments', 'assessments.certificationCourseId', 'certification-courses.id')
.leftJoin(
'certification-courses-last-assessment-results',
'certification-courses.id',
'certification-courses-last-assessment-results.certificationCourseId',
)
.leftJoin(
'assessment-results',
'assessment-results.id',
'certification-courses-last-assessment-results.lastAssessmentResultId',
);
};

const publishCertificationCourses = async function (certificationStatuses) {
const certificationDataToUpdate = certificationStatuses.map(({ certificationCourseId }) => ({
id: certificationCourseId,
isPublished: true,
updatedAt: new Date(),
version: -1, // Version number used to meet requirements regarding the version column non-null constraint in the insert request below
}));

// Trick to .batchUpdate(), which does not exist in knex per say
await knex('certification-courses')
.insert(certificationDataToUpdate)
.onConflict('id')
.merge(['isPublished', 'updatedAt']);
};

export { getStatusesBySessionId, publishCertificationCourses };
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import * as flashAlgorithmConfigurationRepository from '../../../shared/infrastr
import * as certificationCandidateForSupervisingRepository from './certification-candidate-for-supervising-repository.js';
import * as certificationCandidateRepository from './certification-candidate-repository.js';
import * as certificationOfficerRepository from './certification-officer-repository.js';
import * as certificationRepository from './certification-repository.js';
import * as competenceMarkRepository from './competence-mark-repository.js';
import * as courseAssessmentResultRepository from './course-assessment-result-repository.js';
import * as cpfExportRepository from './cpf-export-repository.js';
Expand Down Expand Up @@ -54,6 +55,7 @@ import * as v3CertificationCourseDetailsForAdministrationRepository from './v3-c
* @typedef {sessionRepository} SessionRepository
* @typedef {supervisorAccessRepository} SupervisorAccessRepository
* @typedef {certificationReportRepository} CertificationReportRepository
* @typedef {certificationRepository} CertificationRepository
* @typedef {v3CertificationCourseDetailsForAdministrationRepository} V3CertificationCourseDetailsForAdministrationRepository
* @typedef {competenceRepository} CompetenceRepository
* @typedef {challengeRepository} ChallengeRepository
Expand Down Expand Up @@ -113,6 +115,7 @@ export {
assessmentRepository,
assessmentResultRepository,
certificationChallengeRepository,
certificationRepository,
challengeRepository,
competenceMarkRepository,
cpfExportRepository,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import * as certificationRepository from '../../../../../../src/certification/session-management/infrastructure/repositories/certification-repository.js';
import { AssessmentResult, status } from '../../../../../../src/shared/domain/models/AssessmentResult.js';
import { databaseBuilder, expect, knex, sinon } from '../../../../../test-helper.js';

describe('Integration | Repository | Certification', function () {
describe('#getStatusesBySessionId', function () {
it('should get status information', async function () {
// given
const sessionId = 200;
databaseBuilder.factory.buildSession({ id: sessionId + 1 });
databaseBuilder.factory.buildSession({ id: sessionId });
_buildValidatedCertification({ id: 1, sessionId, isPublished: false });
_buildValidatedCertification({ id: 2, sessionId: sessionId + 1, isPublished: false });
_buildRejectedCertification({ id: 3, sessionId, isPublished: false });
_buildCancelledCertification({ id: 4, sessionId, isPublished: false });
await databaseBuilder.commit();

// when
const statuses = await certificationRepository.getStatusesBySessionId(sessionId);

// then

expect(statuses).to.have.length(3);
expect(statuses).to.deep.equal([
{
certificationCourseId: 1,
isCancelled: false,
pixCertificationStatus: AssessmentResult.status.VALIDATED,
},
{
certificationCourseId: 3,
isCancelled: false,
pixCertificationStatus: AssessmentResult.status.REJECTED,
},
{
certificationCourseId: 4,
isCancelled: true,
pixCertificationStatus: null,
},
]);
});
});

describe('#publishCertificationCoursesBySessionId', function () {
const sessionId = 200;

beforeEach(function () {
databaseBuilder.factory.buildSession({ id: sessionId });
_buildValidatedCertification({ id: 1, sessionId, isPublished: false });
_buildRejectedCertification({ id: 2, sessionId, isPublished: false });
_buildCancelledCertification({ id: 3, sessionId, isPublished: false });
return databaseBuilder.commit();
});

context(
'when all certification latest assessment result are validated, rejected or certification is cancelled',
function () {
let clock;
const now = new Date('2022-12-25');

beforeEach(function () {
clock = sinon.useFakeTimers({
now,
toFake: ['Date'],
});
});

afterEach(async function () {
clock.restore();
});

it('should set certifications as published within the session and update pixCertificationStatus according to assessment result status', async function () {
// when
await certificationRepository.publishCertificationCourses([
{ certificationCourseId: 1 },
{ certificationCourseId: 2 },
{ certificationCourseId: 3 },
]);

// then
const certifications = await knex('certification-courses')
.select('id', 'isPublished', 'updatedAt', 'version')
.where({ sessionId });
expect(certifications).to.deep.equal([
{
id: 1,
isPublished: true,
updatedAt: now,
version: 2,
},
{
id: 2,
isPublished: true,
updatedAt: now,
version: 2,
},
{
id: 3,
isPublished: true,
updatedAt: now,
version: 2,
},
]);
});
},
);
});
});

function _buildValidatedCertification({ id, sessionId, isPublished }) {
_buildCertification({ id, sessionId, isPublished, status: status.VALIDATED });
}

function _buildRejectedCertification({ id, sessionId, isPublished }) {
_buildCertification({ id, sessionId, isPublished, status: status.REJECTED });
}

function _buildCancelledCertification({ id, sessionId, isPublished }) {
_buildCertification({ id, sessionId, isPublished, isCancelled: true, status: null });
}

function _buildCertification({ id, sessionId, status, isPublished, isCancelled = false }) {
databaseBuilder.factory.buildCertificationCourse({ id, sessionId, isPublished, isCancelled });
databaseBuilder.factory.buildAssessment({ id, certificationCourseId: id });
if (status) {
// not the latest
databaseBuilder.factory.buildAssessmentResult({
assessmentId: id,
createdAt: new Date('2020-01-01'),
status,
});
// the latest
databaseBuilder.factory.buildAssessmentResult.last({
certificationCourseId: id,
assessmentId: id,
createdAt: new Date('2021-01-01'),
status,
});
}
}
Loading

0 comments on commit b9e6029

Please sign in to comment.