Skip to content

Commit

Permalink
Fix vouchers consumation
Browse files Browse the repository at this point in the history
  • Loading branch information
mmarchois committed Apr 5, 2021
1 parent 9c8f41d commit 8b578b3
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { ICommand } from 'src/Application/ICommand';
import { User } from 'src/Domain/User/User.entity';

export class AddUserToSchoolCommand implements ICommand {
constructor(
public readonly user: User,
public readonly userId: string,
public readonly schoolId: string
) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,35 @@ import { SchoolUserRepository } from 'src/Infrastructure/School/Repository/Schoo
import { SchoolUser } from 'src/Domain/School/SchoolUser.entity';
import { IsUserAlreadyAddedToSchool } from 'src/Domain/User/Specification/IsUserAlreadyAddedToSchool';
import { UserAlreadyAddedToSchoolException } from 'src/Domain/User/Exception/UserAlreadyAddedToSchoolException';
import { UserRepository } from 'src/Infrastructure/User/Repository/UserRepository';
import { UserNotFoundException } from 'src/Domain/User/Exception/UserNotFoundException';

describe('AddUserToSchoolCommandHandler', () => {
let schoolRepository: SchoolRepository;
let userRepository: UserRepository;
let schoolUserRepository: SchoolUserRepository;
let isUserAlreadyAddedToSchool: IsUserAlreadyAddedToSchool;
let school: School;
let handler: AddUserToSchoolCommandHandler;

const user = mock(User);
const createdSchoolUser = mock(SchoolUser);

const command = new AddUserToSchoolCommand(
instance(user),
'ee18bf86-c72a-4ed9-a6d1-212f4286759e',
'fcf9a99f-0c7b-45ca-b68a-bfd79d73a49f',
);

beforeEach(() => {
schoolRepository = mock(SchoolRepository);
userRepository = mock(UserRepository);
schoolUserRepository = mock(SchoolUserRepository);
isUserAlreadyAddedToSchool = mock(IsUserAlreadyAddedToSchool);
school = mock(School);

handler = new AddUserToSchoolCommandHandler(
instance(schoolRepository),
instance(userRepository),
instance(schoolUserRepository),
instance(isUserAlreadyAddedToSchool),
);
Expand All @@ -43,6 +48,8 @@ describe('AddUserToSchoolCommandHandler', () => {
when(user.getRole()).thenReturn(UserRole.DIRECTOR);
when(schoolRepository.findOneById('fcf9a99f-0c7b-45ca-b68a-bfd79d73a49f'))
.thenResolve(instance(school));
when(userRepository.findOneById('ee18bf86-c72a-4ed9-a6d1-212f4286759e'))
.thenResolve(instance(user));
when(isUserAlreadyAddedToSchool.isSatisfiedBy(instance(school), instance(user)))
.thenResolve(false);
when(schoolUserRepository.save(
Expand All @@ -53,6 +60,7 @@ describe('AddUserToSchoolCommandHandler', () => {
'0b1d9435-4258-42f1-882d-4f314f8fb57d'
);

verify(userRepository.findOneById('ee18bf86-c72a-4ed9-a6d1-212f4286759e')).once();
verify(schoolRepository.findOneById('fcf9a99f-0c7b-45ca-b68a-bfd79d73a49f')).once();
verify(isUserAlreadyAddedToSchool.isSatisfiedBy(instance(school), instance(user))).once();
verify(schoolUserRepository.save(
Expand All @@ -63,18 +71,38 @@ describe('AddUserToSchoolCommandHandler', () => {
it('testSchoolNotFound', async () => {
when(schoolRepository.findOneById('fcf9a99f-0c7b-45ca-b68a-bfd79d73a49f'))
.thenResolve(null);
when(userRepository.findOneById('ee18bf86-c72a-4ed9-a6d1-212f4286759e'))
.thenResolve(instance(user));
try {
expect(await handler.execute(command)).toBeUndefined();
} catch (e) {
expect(e).toBeInstanceOf(SchoolNotFoundException);
expect(e.message).toBe('schools.errors.not_found');
verify(userRepository.findOneById('ee18bf86-c72a-4ed9-a6d1-212f4286759e')).once();
verify(schoolRepository.findOneById('fcf9a99f-0c7b-45ca-b68a-bfd79d73a49f')).once();
verify(schoolUserRepository.save(anything())).never();
verify(isUserAlreadyAddedToSchool.isSatisfiedBy(anything(), anything())).never();
}
});

it('testUserNotFound', async () => {
when(userRepository.findOneById('ee18bf86-c72a-4ed9-a6d1-212f4286759e'))
.thenResolve(null);
try {
expect(await handler.execute(command)).toBeUndefined();
} catch (e) {
expect(e).toBeInstanceOf(UserNotFoundException);
expect(e.message).toBe('users.errors.not_found');
verify(userRepository.findOneById('ee18bf86-c72a-4ed9-a6d1-212f4286759e')).once();
verify(schoolRepository.findOneById('fcf9a99f-0c7b-45ca-b68a-bfd79d73a49f')).never();
verify(schoolUserRepository.save(anything())).never();
verify(isUserAlreadyAddedToSchool.isSatisfiedBy(anything(), anything())).never();
}
});

it('testUserAlreadyAdded', async () => {
when(userRepository.findOneById('ee18bf86-c72a-4ed9-a6d1-212f4286759e'))
.thenResolve(instance(user));
when(schoolRepository.findOneById('fcf9a99f-0c7b-45ca-b68a-bfd79d73a49f'))
.thenResolve(instance(school));
when(isUserAlreadyAddedToSchool.isSatisfiedBy(instance(school), instance(user)))
Expand All @@ -84,6 +112,7 @@ describe('AddUserToSchoolCommandHandler', () => {
expect(await handler.execute(command)).toBeUndefined();
} catch (e) {
expect(e).toBeInstanceOf(UserAlreadyAddedToSchoolException);
verify(userRepository.findOneById('ee18bf86-c72a-4ed9-a6d1-212f4286759e')).once();
expect(e.message).toBe('users.errors.already_assigned_to_school');
verify(schoolRepository.findOneById('fcf9a99f-0c7b-45ca-b68a-bfd79d73a49f')).once();
verify(schoolUserRepository.save(anything())).never();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { ISchoolRepository } from 'src/Domain/School/Repository/ISchoolRepositor
import { ISchoolUserRepository } from 'src/Domain/School/Repository/ISchoolUserRepository';
import { SchoolUser } from 'src/Domain/School/SchoolUser.entity';
import { UserAlreadyAddedToSchoolException } from 'src/Domain/User/Exception/UserAlreadyAddedToSchoolException';
import { UserNotFoundException } from 'src/Domain/User/Exception/UserNotFoundException';
import { IUserRepository } from 'src/Domain/User/Repository/IUserRepository';
import { IsUserAlreadyAddedToSchool } from 'src/Domain/User/Specification/IsUserAlreadyAddedToSchool';
import { AddUserToSchoolCommand } from './AddUserToSchoolCommand';

Expand All @@ -13,13 +15,20 @@ export class AddUserToSchoolCommandHandler {
constructor(
@Inject('ISchoolRepository')
private readonly schoolRepository: ISchoolRepository,
@Inject('IUserRepository')
private readonly userRepository: IUserRepository,
@Inject('ISchoolUserRepository')
private readonly schoolUserRepository: ISchoolUserRepository,
private readonly isUserAlreadyAddedToSchool: IsUserAlreadyAddedToSchool,
) {}

public async execute(command: AddUserToSchoolCommand): Promise<string> {
const { schoolId, user } = command;
const { schoolId, userId } = command;

const user = await this.userRepository.findOneById(userId);
if (!user) {
throw new UserNotFoundException();
}

const school = await this.schoolRepository.findOneById(schoolId);
if (!school) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { VoucherNotFoundException } from 'src/Domain/School/Exception/VoucherNotFoundException';
import { School } from 'src/Domain/School/School.entity';
import { Voucher } from 'src/Domain/School/Voucher.entity';
import { VoucherRepository } from 'src/Infrastructure/School/Repository/VoucherRepository';
import { mock, instance, when, verify } from 'ts-mockito';
Expand All @@ -15,13 +16,18 @@ describe('GetVoucherByCodeQueryHandler', () => {
const expectedResult = new VoucherView(
'eb9e1d9b-dce2-48a9-B64F-f0872f3157d2',
'xLKJS',
'[email protected]'
'[email protected]',
'ee18bf86-c72a-4ed9-a6d1-212f4286759e'
);

const voucher = mock(Voucher);
const school = mock(School);
when(school.getId()).thenReturn('ee18bf86-c72a-4ed9-a6d1-212f4286759e');

const voucher = mock(Voucher);
when(voucher.getId()).thenReturn('eb9e1d9b-dce2-48a9-B64F-f0872f3157d2');
when(voucher.getCode()).thenReturn('xLKJS');
when(voucher.getEmail()).thenReturn('[email protected]');
when(voucher.getSchool()).thenReturn(instance(school));
when(
voucherRepository.findOneByCode('eb9e1d9b-dce2-48a9-b64f-f0872f3157d2')
).thenResolve(instance(voucher));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class GetVoucherByCodeQueryHandler {
voucher.getId(),
voucher.getCode(),
voucher.getEmail(),
voucher.getSchool().getId(),
);
}
}
1 change: 1 addition & 0 deletions api/src/Application/School/View/VoucherView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export class VoucherView {
public readonly id: string,
public readonly code: string,
public readonly email: string,
public readonly schoolId: string,
) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class AddOrInviteUserToSchoolAction {
try {
const user: User = await this.queryBus.execute(new GetUserByEmailQuery(email));
if (user instanceof User) {
await this.commandBus.execute(new AddUserToSchoolCommand(user, id));
await this.commandBus.execute(new AddUserToSchoolCommand(user.getId(), id));
} else {
await this.commandBus.execute(new CreateVoucherCommand(id, email));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { VoucherView } from 'src/Application/School/View/VoucherView';
import { ConsumeVoucherDTO } from '../../DTO/ConsumeVoucherDTO';
import { UserRole } from 'src/Domain/User/User.entity';
import { RemoveVoucherCommand } from 'src/Application/School/Command/Voucher/RemoveVoucherCommand';
import { AddUserToSchoolCommand } from 'src/Application/School/Command/User/AddUserToSchoolCommand';

@Controller('vouchers')
@ApiTags('School voucher')
Expand All @@ -30,7 +31,7 @@ export class ConsumeVoucherAction {
@Post(':code/consume')
@ApiOperation({ summary: 'Consume voucher' })
public async index(
@Param() code: string,
@Param('code') code: string,
@Body() { firstName, lastName, password }: ConsumeVoucherDTO
): Promise<UserView> {
try {
Expand All @@ -39,7 +40,7 @@ export class ConsumeVoucherAction {
return;
}

await this.commandBus.execute(
const id = await this.commandBus.execute(
new CreateUserCommand(
firstName,
lastName,
Expand All @@ -49,6 +50,7 @@ export class ConsumeVoucherAction {
)
);

await this.commandBus.execute(new AddUserToSchoolCommand(id, voucher.schoolId));
await this.commandBus.execute(new RemoveVoucherCommand(voucher.id));
} catch (e) {
throw new BadRequestException(e.message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,14 @@ export class VoucherRepository implements IVoucherRepository {
public findOneByCode(code: string): Promise<Voucher | undefined> {
return this.repository
.createQueryBuilder('voucher')
.select([ 'voucher.id', 'voucher.code', 'voucher.email' ])
.select([
'voucher.id',
'voucher.code',
'voucher.email',
'school.id'
])
.where('voucher.code = :code', { code })
.innerJoin('voucher.school', 'school')
.getOne();
}

Expand Down
2 changes: 1 addition & 1 deletion client/src/routes/admin/schools/[id]/_SchoolUsers.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
`vouchers/${ident}` :
`schools/${id}/users/${ident}`
try {
schoolUsers = schoolUsers.filter((item) => item.id !== userId);
schoolUsers = schoolUsers.filter((item) => item.id !== ident);
await del(delPath);
} catch (e) {
errors = errorNormalizer(e);
Expand Down

0 comments on commit 8b578b3

Please sign in to comment.