Skip to content

Commit

Permalink
[FEATURE] affiche aussi les participations à des campagnes de collect…
Browse files Browse the repository at this point in the history
…e de profil (PIX-15798)

 #10871
  • Loading branch information
pix-service-auto-merge authored Dec 20, 2024
2 parents 64fe168 + b38415a commit b4f2d16
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import crypto from 'node:crypto';

class CampaignParticipationForUserManagement {
constructor({
id,
campaignParticipationId,
participantExternalId,
status,
Expand All @@ -13,7 +14,7 @@ class CampaignParticipationForUserManagement {
organizationLearnerFirstName,
organizationLearnerLastName,
} = {}) {
this.id = id;
this.id = crypto.randomUUID();
this.campaignParticipationId = campaignParticipationId;
this.createdAt = createdAt;
this.participantExternalId = null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { knex } from '../../../../../db/knex-database-connection.js';
import { Assessment } from '../../../../shared/domain/models/Assessment.js';
import { CampaignTypes } from '../../../shared/domain/constants.js';
import { CampaignParticipationForUserManagement } from '../../domain/models/CampaignParticipationForUserManagement.js';

const findByUserId = async function (userId) {
const campaignParticipations = await knex('assessments')
.select({
id: 'assessments.id',
campaignParticipationId: 'campaign-participations.id',
participantExternalId: 'campaign-participations.participantExternalId',
status: 'campaign-participations.status',
campaignId: 'campaigns.id',
campaignCode: 'campaigns.code',
createdAt: 'assessments.createdAt',
createdAt: knex.raw('COALESCE("campaign-participations"."createdAt", assessments."createdAt")'),
sharedAt: 'campaign-participations.sharedAt',
deletedAt: 'campaign-participations.deletedAt',
updatedAt: 'assessments.updatedAt',
Expand All @@ -27,9 +27,32 @@ const findByUserId = async function (userId) {
)
.where('assessments.userId', userId)
.where('assessments.type', Assessment.types.CAMPAIGN)
.orderBy('campaign-participations.createdAt', 'desc')
.union(function () {
this.select({
campaignParticipationId: 'campaign-participations.id',
participantExternalId: 'campaign-participations.participantExternalId',
status: 'campaign-participations.status',
campaignId: 'campaigns.id',
campaignCode: 'campaigns.code',
createdAt: 'campaign-participations.createdAt',
sharedAt: 'campaign-participations.sharedAt',
deletedAt: 'campaign-participations.deletedAt',
updatedAt: 'campaign-participations.deletedAt',
organizationLearnerFirstName: 'view-active-organization-learners.firstName',
organizationLearnerLastName: 'view-active-organization-learners.lastName',
})
.from('campaign-participations')
.leftJoin('campaigns', 'campaigns.id', 'campaign-participations.campaignId')
.leftJoin(
'view-active-organization-learners',
'view-active-organization-learners.id',
'campaign-participations.organizationLearnerId',
)
.where({ 'campaign-participations.userId': userId, type: CampaignTypes.PROFILES_COLLECTION });
})
.orderBy('createdAt', 'desc')
.orderBy('campaignCode', 'asc')
.orderBy('campaign-participations.sharedAt', 'desc');
.orderBy('sharedAt', 'desc');

return campaignParticipations.map((attributes) => new CampaignParticipationForUserManagement(attributes));
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
import crypto from 'node:crypto';

import { Assessment } from '../../../../../src/shared/domain/models/Assessment.js';
import {
createServer,
databaseBuilder,
expect,
generateValidRequestAuthorizationHeader,
sinon,
} from '../../../../test-helper.js';

describe('Acceptance | Controller | GET /api/admin/users/{userId}/participations', function () {
let server;
let server, randomUUIDStub;

beforeEach(async function () {
server = await createServer();
randomUUIDStub = sinon.stub(crypto, 'randomUUID');
randomUUIDStub.returns('1234');
});

afterEach(function () {
sinon.restore();
});

it('should return participations', async function () {
Expand All @@ -23,7 +32,7 @@ describe('Acceptance | Controller | GET /api/admin/users/{userId}/participations
campaignId: campaign.id,
organizationLearnerId: organizationLearner.id,
});
const assessment = databaseBuilder.factory.buildAssessment({
databaseBuilder.factory.buildAssessment({
userId: user.id,
campaignParticipationId: campaignParticipation.id,
type: Assessment.types.CAMPAIGN,
Expand All @@ -43,7 +52,7 @@ describe('Acceptance | Controller | GET /api/admin/users/{userId}/participations
expect(response.result).to.deep.equal({
data: [
{
id: assessment.id.toString(),
id: '1234',
type: 'user-participations',
attributes: {
'campaign-participation-id': campaignParticipation.id,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import crypto from 'node:crypto';

import { CampaignParticipationForUserManagement } from '../../../../../../src/prescription/campaign-participation/domain/models/CampaignParticipationForUserManagement.js';
import * as participationsForUserManagementRepository from '../../../../../../src/prescription/campaign-participation/infrastructure/repositories/participations-for-user-management-repository.js';
import { CampaignParticipationStatuses } from '../../../../../../src/prescription/shared/domain/constants.js';
import {
CampaignParticipationStatuses,
CampaignTypes,
} from '../../../../../../src/prescription/shared/domain/constants.js';
import { Assessment } from '../../../../../../src/shared/domain/models/Assessment.js';
import { databaseBuilder, expect } from '../../../../../test-helper.js';
import { databaseBuilder, expect, sinon } from '../../../../../test-helper.js';

const { SHARED } = CampaignParticipationStatuses;

Expand All @@ -13,6 +18,7 @@ describe('Integration | Repository | Participations-For-User-Management', functi
beforeEach(async function () {
userId = databaseBuilder.factory.buildUser().id;
await databaseBuilder.commit();
sinon.stub(crypto, 'randomUUID').returns(1234);
});

context('when the given user has no participations', function () {
Expand Down Expand Up @@ -67,8 +73,7 @@ describe('Integration | Repository | Participations-For-User-Management', functi
campaignParticipation.participantExternalId,
);
});

it('should return participations with all attributes', async function () {
it('should return both assessment and profiles collection participations with all attributes', async function () {
// given
const campaign = databaseBuilder.factory.buildCampaign({ code: 'FUNCODE' });
const organizationLearner = databaseBuilder.factory.buildOrganizationLearner({
Expand All @@ -85,11 +90,24 @@ describe('Integration | Repository | Participations-For-User-Management', functi
createdAt: new Date('2010-10-10'),
sharedAt: new Date('2010-10-11'),
});
const assessment = databaseBuilder.factory.buildAssessment({
databaseBuilder.factory.buildAssessment({
campaignParticipationId: campaignParticipation.id,
type: Assessment.types.CAMPAIGN,
userId,
});
const profilesCollectionCampaign = databaseBuilder.factory.buildCampaign({
code: 'HIHACODE',
type: CampaignTypes.PROFILES_COLLECTION,
});
const profilesCollectionParticipation = databaseBuilder.factory.buildCampaignParticipation({
userId,
organizationLearnerId: organizationLearner.id,
campaignId: profilesCollectionCampaign.id,
participantExternalId: '345',
status: SHARED,
createdAt: new Date('2010-10-12'),
sharedAt: new Date('2010-10-13'),
});
await databaseBuilder.commit();

// when
Expand All @@ -98,11 +116,23 @@ describe('Integration | Repository | Participations-For-User-Management', functi
// then
expect(participationsForUserManagement[0]).to.be.instanceOf(CampaignParticipationForUserManagement);
expect(participationsForUserManagement[0]).to.deep.includes({
id: assessment.id,
id: 1234,
campaignParticipationId: profilesCollectionParticipation.id,
participantExternalId: profilesCollectionParticipation.participantExternalId,
status: profilesCollectionParticipation.status,
createdAt: profilesCollectionParticipation.createdAt,
sharedAt: profilesCollectionParticipation.sharedAt,
campaignId: profilesCollectionCampaign.id,
campaignCode: profilesCollectionCampaign.code,
organizationLearnerFullName: `${organizationLearner.firstName} ${organizationLearner.lastName}`,
});
expect(participationsForUserManagement[1]).to.be.instanceOf(CampaignParticipationForUserManagement);
expect(participationsForUserManagement[1]).to.deep.includes({
id: 1234,
campaignParticipationId: campaignParticipation.id,
participantExternalId: campaignParticipation.participantExternalId,
status: campaignParticipation.status,
createdAt: assessment.createdAt,
createdAt: campaignParticipation.createdAt,
sharedAt: campaignParticipation.sharedAt,
campaignId: campaign.id,
campaignCode: campaign.code,
Expand Down Expand Up @@ -131,7 +161,7 @@ describe('Integration | Repository | Participations-For-User-Management', functi
deletedAt: new Date('2010-10-12'),
deletedBy: deletingUser.id,
});
const assessment = databaseBuilder.factory.buildAssessment({
databaseBuilder.factory.buildAssessment({
campaignParticipationId: campaignParticipation.id,
type: Assessment.types.CAMPAIGN,
userId,
Expand All @@ -144,20 +174,22 @@ describe('Integration | Repository | Participations-For-User-Management', functi

// then
expect(participationsForUserManagement[0]).to.deep.includes({
id: assessment.id,
id: 1234,
campaignParticipationId: campaignParticipation.id,
participantExternalId: campaignParticipation.participantExternalId,
status: SHARED,
createdAt: assessment.createdAt,
createdAt: campaignParticipation.createdAt,
sharedAt: campaignParticipation.sharedAt,
campaignId: campaign.id,
campaignCode: campaign.code,
deletedAt: campaignParticipation.deletedAt,
organizationLearnerFullName: `${organizationLearner.firstName} ${organizationLearner.lastName}`,
});
});
});

it('should return participation is deleted and anonymized', async function () {
context('When a participation is deleted and anonymised', function () {
it('should return participation with deletion attributes', async function () {
// given
const assessment = databaseBuilder.factory.buildAssessment({
type: Assessment.types.CAMPAIGN,
Expand All @@ -171,7 +203,7 @@ describe('Integration | Repository | Participations-For-User-Management', functi

// then
expect(participationsForUserManagement[0]).to.deep.includes({
id: assessment.id,
id: 1234,
campaignParticipationId: null,
participantExternalId: null,
status: null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import crypto from 'node:crypto';

import { CampaignParticipationForUserManagement } from '../../../../../../src/prescription/campaign-participation/domain/models/CampaignParticipationForUserManagement.js';
import { expect } from '../../../../../test-helper.js';
import { expect, sinon } from '../../../../../test-helper.js';

describe('Unit | Domain | Models | CampaignParticipationForUserManagement', function () {
beforeEach(function () {
sinon.stub(crypto, 'randomUUID').returns(1234);
});

describe('#constructor', function () {
it('should not return campaign participation informations when campaignParticipationId is missing', function () {
// given
const campaignParticipation = new CampaignParticipationForUserManagement({
id: 1,
campaignParticipationId: null,
participantExternalId: 'externalId',
status: 'TOTO',
Expand All @@ -21,7 +26,7 @@ describe('Unit | Domain | Models | CampaignParticipationForUserManagement', func
});

// then
expect(campaignParticipation.id).to.be.deep.equals(1);
expect(campaignParticipation.id).to.be.deep.equals(1234);
expect(campaignParticipation.createdAt).to.be.deep.equals(new Date('2020-01-01'));
expect(campaignParticipation.deletedAt).to.be.deep.equals(new Date('2022-01-01'));
expect(campaignParticipation.organizationLearnerFullName).to.be.equals('-');
Expand Down

0 comments on commit b4f2d16

Please sign in to comment.