-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FEATURE] Générer les identifiants en masse pour les élèves (PIX-12975)…
… (#10096) Co-authored-by: Marianne Bost <[email protected]>
- Loading branch information
Showing
44 changed files
with
1,585 additions
and
407 deletions.
There are no files selected for viewing
321 changes: 220 additions & 101 deletions
321
api/db/seeds/data/team-acces/build-sco-organization-learners.js
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,11 +2,17 @@ import { NON_OIDC_IDENTITY_PROVIDERS } from '../../../../src/identity-access-man | |
import { Membership } from '../../../../src/shared/domain/models/Membership.js'; | ||
import { PIX_PUBLIC_TARGET_PROFILE_ID, REAL_PIX_SUPER_ADMIN_ID } from '../common/constants.js'; | ||
import { PIX_ORGA_ADMIN_LEAVING_ID, PIX_ORGA_ALL_ORGA_ID } from './build-organization-users.js'; | ||
import { ACCESS_SCO_BAUDELAIRE_EXTERNAL_ID, SCO_ORGANIZATION_ID } from './constants.js'; | ||
import { | ||
ACCESS_SCO_BAUDELAIRE_EXTERNAL_ID, | ||
ACCESS_SCO_NO_GAR_EXTERNAL_ID, | ||
SCO_NO_GAR_ORGANIZATION_ID, | ||
SCO_ORGANIZATION_ID, | ||
} from './constants.js'; | ||
|
||
export function buildScoOrganizations(databaseBuilder) { | ||
_buildCollegeHouseOfTheDragonOrganization(databaseBuilder); | ||
_buildJosephineBaker(databaseBuilder); | ||
_buildScoManagingStudentsNoGarOrganization(databaseBuilder); | ||
} | ||
|
||
function _buildCollegeHouseOfTheDragonOrganization(databaseBuilder) { | ||
|
@@ -86,6 +92,28 @@ function _buildJosephineBaker(databaseBuilder) { | |
].forEach(_buildAdminMembership(databaseBuilder)); | ||
} | ||
|
||
function _buildScoManagingStudentsNoGarOrganization(databaseBuilder) { | ||
const organization = databaseBuilder.factory.buildOrganization({ | ||
id: SCO_NO_GAR_ORGANIZATION_ID, | ||
type: 'SCO', | ||
name: 'Lycée pas-GAR', | ||
isManagingStudents: true, | ||
email: '[email protected]', | ||
externalId: ACCESS_SCO_NO_GAR_EXTERNAL_ID, | ||
documentationUrl: 'https://pix.fr/', | ||
provinceCode: '13', | ||
createdBy: REAL_PIX_SUPER_ADMIN_ID, | ||
}); | ||
|
||
[ | ||
{ | ||
userId: PIX_ORGA_ALL_ORGA_ID, | ||
organizationId: organization.id, | ||
organizationRole: Membership.roles.ADMIN, | ||
}, | ||
].forEach(_buildAdminMembership(databaseBuilder)); | ||
} | ||
|
||
function _buildAdminMembership(databaseBuilder) { | ||
return function ({ userId, organizationId, organizationRole }) { | ||
databaseBuilder.factory.buildMembership({ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,11 @@ | ||
const ACCESS_SCO_BAUDELAIRE_EXTERNAL_ID = 'ACCESS_SCO_BAUDELAIRE'; | ||
const ACCESS_SCO_NO_GAR_EXTERNAL_ID = 'ACCESS_SCO_NO_GAR'; | ||
const SCO_ORGANIZATION_ID = 2023; | ||
const SCO_NO_GAR_ORGANIZATION_ID = 2024; | ||
|
||
export { ACCESS_SCO_BAUDELAIRE_EXTERNAL_ID, SCO_ORGANIZATION_ID }; | ||
export { | ||
ACCESS_SCO_BAUDELAIRE_EXTERNAL_ID, | ||
ACCESS_SCO_NO_GAR_EXTERNAL_ID, | ||
SCO_NO_GAR_ORGANIZATION_ID, | ||
SCO_ORGANIZATION_ID, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
159 changes: 159 additions & 0 deletions
159
api/lib/domain/usecases/generate-organization-learners-username-and-temporary-password.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import { OrganizationLearnerIdentities } from '../../../src/identity-access-management/domain/models/OrganizationLearnerIdentities.js'; | ||
import { UserNotAuthorizedToUpdatePasswordError } from '../../../src/shared/domain/errors.js'; | ||
import { OrganizationLearnerPasswordResetDTO } from '../../../src/shared/domain/models/OrganizationLearnerPasswordResetDTO.js'; | ||
import { | ||
ORGANIZATION_LEARNER_DOES_NOT_BELONG_TO_ORGANIZATION_CODE, | ||
ORGANIZATION_LEARNER_WITHOUT_USERNAME_CODE, | ||
} from '../constants/generate-organization-learners-username-and-temporary-password-errors.js'; | ||
|
||
const generateOrganizationLearnersUsernameAndTemporaryPassword = async function ({ | ||
organizationId, | ||
organizationLearnersId, | ||
userId, | ||
cryptoService, | ||
passwordGenerator, | ||
userReconciliationService, | ||
authenticationMethodRepository, | ||
organizationRepository, | ||
organizationLearnerIdentityRepository, | ||
userRepository, | ||
}) { | ||
const errorMessage = `User ${userId} cannot reset passwords of some students in organization ${organizationId}`; | ||
const organization = await organizationRepository.get(organizationId); | ||
const organizationLearnerIdentities = await _buildOrganizationLearnerIdentities({ | ||
errorMessage, | ||
organization, | ||
organizationLearnersId, | ||
organizationLearnerIdentityRepository, | ||
}); | ||
let organizationLearnerIdentitiesValues = organizationLearnerIdentities.values; | ||
|
||
if (!organizationLearnerIdentities.hasScoGarIdentityProvider) { | ||
organizationLearnerIdentitiesValues = await _generateAndUpdateUsernameForOrganizationLearnerIdentities({ | ||
organizationLearnerIdentities: organizationLearnerIdentitiesValues, | ||
userReconciliationService, | ||
userRepository, | ||
}); | ||
} | ||
|
||
const userIdWithPasswords = await _generateAndUpdateUsersWithTemporaryPassword({ | ||
errorMessage, | ||
organizationLearnerIdentities: organizationLearnerIdentitiesValues, | ||
authenticationMethodRepository, | ||
cryptoService, | ||
passwordGenerator, | ||
}); | ||
|
||
return _buildOrganizationLearnerPasswordResetDTOs({ | ||
organizationLearnerIdentities: organizationLearnerIdentitiesValues, | ||
userIdWithPasswords, | ||
}); | ||
}; | ||
|
||
async function _buildOrganizationLearnerIdentities({ | ||
errorMessage, | ||
organization, | ||
organizationLearnersId, | ||
organizationLearnerIdentityRepository, | ||
}) { | ||
try { | ||
const organizationLearnerIdentities = await organizationLearnerIdentityRepository.getByIds(organizationLearnersId); | ||
|
||
return new OrganizationLearnerIdentities({ | ||
id: organization.id, | ||
hasScoGarIdentityProvider: organization.hasGarIdentityProvider, | ||
values: organizationLearnerIdentities, | ||
}); | ||
} catch (error) { | ||
throw new UserNotAuthorizedToUpdatePasswordError( | ||
errorMessage, | ||
ORGANIZATION_LEARNER_DOES_NOT_BELONG_TO_ORGANIZATION_CODE, | ||
); | ||
} | ||
} | ||
|
||
async function _generateAndUpdateUsernameForOrganizationLearnerIdentities({ | ||
organizationLearnerIdentities, | ||
userReconciliationService, | ||
userRepository, | ||
}) { | ||
const result = []; | ||
for (const organizationLearnerIdentity of organizationLearnerIdentities) { | ||
const temporaryOrganizationLearnerIdentity = { ...organizationLearnerIdentity }; | ||
if (!organizationLearnerIdentity.username) { | ||
const username = await userReconciliationService.createUsernameByUser({ | ||
user: organizationLearnerIdentity, | ||
userRepository, | ||
}); | ||
temporaryOrganizationLearnerIdentity.username = username; | ||
await userRepository.updateUsername({ id: organizationLearnerIdentity.userId, username }); | ||
} | ||
|
||
result.push(temporaryOrganizationLearnerIdentity); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
async function _generateAndUpdateUsersWithTemporaryPassword({ | ||
errorMessage, | ||
organizationLearnerIdentities, | ||
authenticationMethodRepository, | ||
cryptoService, | ||
passwordGenerator, | ||
}) { | ||
_assertAllUsersHasAnUsername({ errorMessage, users: organizationLearnerIdentities }); | ||
|
||
const userIdWithPasswords = await _generateNewTemporaryPasswordForOrganizationLearnerIdentities({ | ||
organizationLearnerIdentities, | ||
passwordGenerator, | ||
cryptoService, | ||
}); | ||
await authenticationMethodRepository.batchUpsertPasswordThatShouldBeChanged({ | ||
usersToUpdateWithNewPassword: userIdWithPasswords, | ||
}); | ||
|
||
return userIdWithPasswords; | ||
} | ||
|
||
function _assertAllUsersHasAnUsername({ errorMessage, users }) { | ||
const usersHaveAnUsername = users.every((student) => student.username); | ||
|
||
if (!usersHaveAnUsername) { | ||
throw new UserNotAuthorizedToUpdatePasswordError(errorMessage, ORGANIZATION_LEARNER_WITHOUT_USERNAME_CODE); | ||
} | ||
} | ||
|
||
async function _generateNewTemporaryPasswordForOrganizationLearnerIdentities({ | ||
organizationLearnerIdentities, | ||
passwordGenerator, | ||
cryptoService, | ||
}) { | ||
return await Promise.all( | ||
organizationLearnerIdentities.map(async ({ userId }) => { | ||
const generatedPassword = passwordGenerator.generateSimplePassword(); | ||
const hashedPassword = await cryptoService.hashPassword(generatedPassword); | ||
|
||
return { userId, hashedPassword, generatedPassword }; | ||
}), | ||
); | ||
} | ||
|
||
function _buildOrganizationLearnerPasswordResetDTOs({ organizationLearnerIdentities, userIdWithPasswords }) { | ||
const userIdWithPasswordsMap = new Map( | ||
userIdWithPasswords.map(({ userId, generatedPassword }) => [userId, generatedPassword]), | ||
); | ||
|
||
return organizationLearnerIdentities.map( | ||
({ userId, division, firstName, lastName, username }) => | ||
new OrganizationLearnerPasswordResetDTO({ | ||
division, | ||
lastName, | ||
firstName, | ||
password: userIdWithPasswordsMap.get(userId), | ||
username, | ||
}), | ||
); | ||
} | ||
|
||
export { generateOrganizationLearnersUsernameAndTemporaryPassword }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 0 additions & 72 deletions
72
api/lib/domain/usecases/reset-organization-learners-password.js
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.