Skip to content

Commit

Permalink
refactor(api): migrate mass create user accounts script
Browse files Browse the repository at this point in the history
  • Loading branch information
bpetetot authored Nov 14, 2024
1 parent bd43f7a commit 5b10faf
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 119 deletions.
Original file line number Diff line number Diff line change
@@ -1,86 +1,63 @@
/* eslint-disable no-console */
import Joi from 'joi';

import * as url from 'node:url';

import { disconnect } from '../../../db/knex-database-connection.js';
import { parseCsvWithHeader } from '../../../scripts/helpers/csvHelpers.js';
import { csvFileParser } 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';
import { cryptoService } from '../../shared/domain/services/crypto-service.js';
import * as userService from '../../shared/domain/services/user-service.js';
import * as authenticationMethodRepository from '../infrastructure/repositories/authentication-method.repository.js';
import { userToCreateRepository } from '../infrastructure/repositories/user-to-create.repository.js';

function prepareDataForInsert(rawUsers) {
return rawUsers.map(({ firstName, lastName, email, password }) => {
return {
firstName: firstName.trim(),
lastName: lastName.trim(),
email: email.trim().toLowerCase(),
password: password.trim(),
};
});
}

async function createUsers({ usersInRaw }) {
await DomainTransaction.execute(async () => {
const now = new Date();

for (const userDTO of usersInRaw) {
const userToCreate = {
firstName: userDTO.firstName,
lastName: userDTO.lastName,
email: userDTO.email,
createAt: now,
updatedAt: now,
cgu: true,
lang: 'fr',
};
const hashedPassword = await cryptoService.hashPassword(userDTO.password);

await userService.createUserWithPassword({
user: userToCreate,
hashedPassword,
userToCreateRepository,
authenticationMethodRepository,
});
}
});
}

const modulePath = url.fileURLToPath(import.meta.url);
const isLaunchedFromCommandLine = process.argv[1] === modulePath;

async function main() {
console.log('Starting creating users accounts for contest.');

const filePath = process.argv[2];

console.log('Reading and parsing csv data file... ');
const csvData = await parseCsvWithHeader(filePath);
console.log('ok');

console.log('Preparing data... ');
const usersInRaw = prepareDataForInsert(csvData);
console.log('ok');

console.log('Creating users...');
await createUsers({ usersInRaw });
console.log('\nDone.');
}

(async () => {
if (isLaunchedFromCommandLine) {
try {
await main();
} catch (error) {
console.error(error);
process.exitCode = 1;
} finally {
await disconnect();
}
export const csvSchemas = [
{ name: 'firstName', schema: Joi.string().trim().required() },
{ name: 'lastName', schema: Joi.string().trim().required() },
{ name: 'email', schema: Joi.string().trim().lowercase().email().required() },
{ name: 'password', schema: Joi.string().trim().required() },
];

export class MassCreateUserAccountsScript extends Script {
constructor() {
super({
description: 'This script allows you to create Pix user accounts with email/password',
permanent: true,
options: {
file: {
type: 'string',
describe: 'CSV file path',
demandOption: true,
coerce: csvFileParser(csvSchemas),
},
},
});
}
})();

/* eslint-enable no-console */
async handle({ options }) {
const { file } = options;

await DomainTransaction.execute(async () => {
const now = new Date();

for (const userDTO of file) {
const userToCreate = {
firstName: userDTO.firstName,
lastName: userDTO.lastName,
email: userDTO.email,
createAt: now,
updatedAt: now,
cgu: true,
lang: 'fr',
};
const hashedPassword = await cryptoService.hashPassword(userDTO.password);

await userService.createUserWithPassword({
user: userToCreate,
hashedPassword,
userToCreateRepository,
authenticationMethodRepository,
});
}
});
}
}

export { createUsers, prepareDataForInsert };
await ScriptRunner.execute(import.meta.url, MassCreateUserAccountsScript);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
firstName,lastName,email,password
Dik,Tektive,[email protected],P@ssW0rd
Foo , Bar , [email protected] , barbarbar
Original file line number Diff line number Diff line change
@@ -1,16 +1,51 @@
import { createUsers } from '../../../../src/identity-access-management/scripts/mass-create-user-accounts.js';
import * as url from 'node:url';

import { MassCreateUserAccountsScript } from '../../../../src/identity-access-management/scripts/mass-create-user-accounts.js';
import { expect, knex, sinon } from '../../../test-helper.js';

describe('Acceptance | Identity Access Management | Scripts | mass-create-user-accounts', function () {
describe('#createUsers', function () {
const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url));

describe('Integration | Identity Access Management | Scripts | mass-create-user-accounts', function () {
describe('Options', function () {
it('has the correct options', function () {
const script = new MassCreateUserAccountsScript();

const { options } = script.metaInfo;
expect(options.file).to.deep.include({
type: 'string',
describe: 'CSV file path',
demandOption: true,
});
});

it('parses CSV data correctly', async function () {
const testCsvFile = `${currentDirectory}files/mass-create-user-accounts.csv`;

const script = new MassCreateUserAccountsScript();

const { options } = script.metaInfo;
const parsedData = await options.file.coerce(testCsvFile);
expect(parsedData).to.be.an('array').that.deep.includes({
firstName: 'Dik',
lastName: 'Tektive',
email: '[email protected]',
password: 'P@ssW0rd',
});
expect(parsedData).to.be.an('array').that.deep.includes({
firstName: 'Foo',
lastName: 'Bar',
email: '[email protected]',
password: 'barbarbar',
});
});
});

describe('#handle', function () {
const now = new Date();
let clock;

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

afterEach(async function () {
Expand All @@ -35,7 +70,8 @@ describe('Acceptance | Identity Access Management | Scripts | mass-create-user-a
];

// when
await createUsers({ usersInRaw });
const script = new MassCreateUserAccountsScript();
await script.handle({ options: { file: usersInRaw } });

// then
const firstUserFound = await knex('users').where({ lastName: 'Kilo' }).first();
Expand Down Expand Up @@ -87,7 +123,8 @@ describe('Acceptance | Identity Access Management | Scripts | mass-create-user-a
];

// when
await createUsers({ usersInRaw });
const script = new MassCreateUserAccountsScript();
await script.handle({ options: { file: usersInRaw } });

// then
const usersInDatabases = await knex('authentication-methods');
Expand Down

This file was deleted.

0 comments on commit 5b10faf

Please sign in to comment.