Skip to content

Commit

Permalink
feat: 도어락 비밀번호 업데이트 구현 (#71)
Browse files Browse the repository at this point in the history
  • Loading branch information
Coalery authored Oct 13, 2024
2 parents 3b61c5a + 57c92b6 commit c9e5289
Show file tree
Hide file tree
Showing 11 changed files with 330 additions and 6 deletions.
88 changes: 84 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@
"@nestjs/core": "^10.0.0",
"@nestjs/cqrs": "^10.2.5",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/swagger": "^7.4.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"nestjs-cls": "^3.5.1",
"php-serialize": "^5.0.1",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1"
"rxjs": "^7.8.1",
"ulid": "^2.3.0"
},
"devDependencies": {
"@faker-js/faker": "^8.0.2",
Expand Down
19 changes: 19 additions & 0 deletions src/__test__/fixtures/CacheFixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { faker } from '@faker-js/faker';

import {
Cache,
CacheConstructorParams,
} from '@khlug/app/domain/cache/model/Cache';

function generator(params: Partial<CacheConstructorParams> = {}): Cache {
return new Cache({
id: params.id ?? faker.string.numeric(3),
name: params.name ?? faker.string.alpha(10),
content: params.content ?? faker.string.alpha(10),
updatedAt: params.updatedAt ?? new Date(),
});
}

export const CacheFixture = {
raw: generator,
};
7 changes: 6 additions & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { MikroOrmModule } from '@mikro-orm/nestjs';
import { Module } from '@nestjs/common';

import { CoreModule } from '@khlug/core/core.module';

import { Cache } from '@khlug/app/domain/cache/model/Cache';

@Module({
imports: [],
imports: [CoreModule, MikroOrmModule.forFeature([Cache])],
controllers: [],
providers: [],
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Typeof } from '@khlug/util/types';

export class UpdateDoorLockPasswordCommand {
readonly master: string;
readonly forJajudy: string;
readonly forFacilityTeam: string;

constructor(params: Typeof<UpdateDoorLockPasswordCommand>) {
this.master = params.master;
this.forJajudy = params.forJajudy;
this.forFacilityTeam = params.forFacilityTeam;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { EntityRepository } from '@mikro-orm/mysql';
import { getRepositoryToken } from '@mikro-orm/nestjs';
import { Test } from '@nestjs/testing';
import { advanceTo, clear } from 'jest-date-mock';

import { UpdateDoorLockPasswordCommand } from '@khlug/app/application/infraBlue/command/updateDoorLockPassword/UpdateDoorLockPasswordCommand';
import {
FACILITY_TEAM_PASSWORD_CACHE_ID,
JAJUDY_PASSWORD_CACHE_ID,
MASTER_PASSWORD_CACHE_ID,
UpdateDoorLockPasswordCommandHandler,
} from '@khlug/app/application/infraBlue/command/updateDoorLockPassword/UpdateDoorLockPasswordCommandHandler';

import { Cache } from '@khlug/app/domain/cache/model/Cache';

import { CacheFixture } from '@khlug/__test__/fixtures/CacheFixture';
import { Message } from '@khlug/constant/message';

describe('UpdateDoorLockPasswordCommandHandler', () => {
let handler: UpdateDoorLockPasswordCommandHandler;
let cacheRepository: jest.Mocked<EntityRepository<Cache>>;

beforeEach(async () => {
advanceTo(new Date());

const testModule = await Test.createTestingModule({
providers: [
UpdateDoorLockPasswordCommandHandler,
{
provide: getRepositoryToken(Cache),
useValue: {
find: jest.fn(),
getEntityManager: () => ({ persistAndFlush: jest.fn() }),
},
},
],
}).compile();

handler = testModule.get(UpdateDoorLockPasswordCommandHandler);
cacheRepository = testModule.get(getRepositoryToken(Cache));
});

afterEach(() => clear());

describe('execute', () => {
test('비밀번호 정보가 존재하지 않으면 예외를 발생시켜야 한다', async () => {
cacheRepository.find.mockResolvedValue([]);

const command = new UpdateDoorLockPasswordCommand({
master: 'master',
forJajudy: 'jajudy',
forFacilityTeam: 'facilityTeam',
});
await expect(handler.execute(command)).rejects.toThrow(
Message.SOME_DOOR_LOCK_PASSWORD_NOT_FOUND,
);
});

test('비밀번호를 변경해야 한다', async () => {
const masterPassword = CacheFixture.raw({
id: MASTER_PASSWORD_CACHE_ID,
content: 'oldMaster',
});
const jajudyPassword = CacheFixture.raw({
id: JAJUDY_PASSWORD_CACHE_ID,
content: 'oldJajudy',
});
const facilityTeamPassword = CacheFixture.raw({
id: FACILITY_TEAM_PASSWORD_CACHE_ID,
content: 'oldFacilityTeam',
});

cacheRepository.find.mockResolvedValue([
masterPassword,
jajudyPassword,
facilityTeamPassword,
]);

const command = new UpdateDoorLockPasswordCommand({
master: 'newMaster',
forJajudy: 'newJajudy',
forFacilityTeam: 'newFacilityTeam',
});
await handler.execute(command);

expect(masterPassword.content).toBe('newMaster');
expect(jajudyPassword.content).toBe('newJajudy');
expect(facilityTeamPassword.content).toBe('newFacilityTeam');
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { EntityRepository } from '@mikro-orm/mysql';
import { InjectRepository } from '@mikro-orm/nestjs';
import { NotFoundException } from '@nestjs/common';
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';

import { UpdateDoorLockPasswordCommand } from '@khlug/app/application/infraBlue/command/updateDoorLockPassword/UpdateDoorLockPasswordCommand';

import { Cache } from '@khlug/app/domain/cache/model/Cache';

import { Message } from '@khlug/constant/message';

export const MASTER_PASSWORD_CACHE_ID = '100';
export const JAJUDY_PASSWORD_CACHE_ID = '101';
export const FACILITY_TEAM_PASSWORD_CACHE_ID = '102';

@CommandHandler(UpdateDoorLockPasswordCommand)
export class UpdateDoorLockPasswordCommandHandler
implements ICommandHandler<UpdateDoorLockPasswordCommand, void>
{
constructor(
@InjectRepository(Cache)
private readonly cacheRepository: EntityRepository<Cache>,
) {}

async execute(command: UpdateDoorLockPasswordCommand): Promise<void> {
const { master, forJajudy, forFacilityTeam } = command;

const passwords = await this.cacheRepository.find({
id: {
$in: [
MASTER_PASSWORD_CACHE_ID,
JAJUDY_PASSWORD_CACHE_ID,
FACILITY_TEAM_PASSWORD_CACHE_ID,
],
},
});

const masterPassword = passwords.find(
(password) => password.id === MASTER_PASSWORD_CACHE_ID,
);
const jajudyPassword = passwords.find(
(password) => password.id === JAJUDY_PASSWORD_CACHE_ID,
);
const facilityTeamPassword = passwords.find(
(password) => password.id === FACILITY_TEAM_PASSWORD_CACHE_ID,
);

if (!masterPassword || !jajudyPassword || !facilityTeamPassword) {
throw new NotFoundException(Message.SOME_DOOR_LOCK_PASSWORD_NOT_FOUND);
}

masterPassword.updateContent(master);
jajudyPassword.updateContent(forJajudy);
facilityTeamPassword.updateContent(forFacilityTeam);

await this.cacheRepository
.getEntityManager()
.persistAndFlush([masterPassword, jajudyPassword, facilityTeamPassword]);
}
}
1 change: 1 addition & 0 deletions src/constant/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const Message = {
USER_NOT_FOUND: 'User not found',
SOME_INTERESTS_NOT_FOUND: 'Some interests not found',
GROUP_NOT_FOUND: 'Group not found',
SOME_DOOR_LOCK_PASSWORD_NOT_FOUND: '일부 도어락 비밀번호가 존재하지 않습니다',

// 422 Unprocessable Entity
GRADUATED_USER_ONLY_CAN_CHANGE_EMAIL: 'Graduated user only can change email',
Expand Down
Loading

0 comments on commit c9e5289

Please sign in to comment.