Skip to content

Commit

Permalink
feat(the-camp): 군인 등록 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
WhiteKiwi committed Mar 1, 2022
1 parent ef9c084 commit aefedcf
Show file tree
Hide file tree
Showing 14 changed files with 259 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/core/types/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
export * from './credential';
export * from './관계';
export * from './군종';
export * from './성분';
export * from './입영부대';
10 changes: 10 additions & 0 deletions src/core/types/관계.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const 관계CodeMap = {
부모: '0000420001',
'형제/자매': '0000420002',
배우자: '0000420003',
친척: '0000420004',
애인: '0000420005',
'친구/지인': '0000420006',
: '0000420007',
} as const;
export type 관계 = keyof typeof 관계CodeMap;
8 changes: 8 additions & 0 deletions src/core/types/군종.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const 군종CodeMap = {
육군: '0000010001',
해군: '0000010002',
공군: '0000010003',
해병대: '0000010004',
} as const;

export type 군종 = keyof typeof 군종CodeMap;
10 changes: 10 additions & 0 deletions src/core/types/성분.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const 성분CodeMap = {
'예비군인/훈련병': '0000490001',
병사: '0000490002',
장교: '0000490003',
부사관: '0000490004',
군무원: '0000490005',
생도: '0000490006',
} as const;

export type 성분 = keyof typeof 성분CodeMap;
34 changes: 34 additions & 0 deletions src/core/types/입영부대.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export const 입영부대CodeMap = {
'육군훈련소-논산': '20020191700',
육군3사관학교: '20020920000',
'1사단-파주': '20121290100',
'2사단': '20121490100',
'3사단-철원': '20121590100',
'5사단-연천': '20121690200',
'6사단-철원': '20121590200',
'7사단-화천': '20121390100',
'9사단-고양': '20121290200',
'11사단': '20121790300',
'12사단-인제': '20121490200',
'15사단-화천': '20121390200',
'17사단': '20121190100',
'20사단': '20121790400',
'21사단-양구': '20121490300',
'22사단': '20121890100',
'23사단': '20121890200',
'25사단-양주': '20121290300',
'27사단-화천': '20121390300',
'28사단-파주': '20121690100',
'30사단': '20121290400',
'31사단-광주': '20220280100',
'32사단-세종': '20220280200',
'35사단-임실': '20220280300',
'36사단-원주': '20120180100',
'37사단-증평': '20220280400',
'39사단-함안': '20220280500',
'50사단-대구': '20220280600',
'51사단-화성': '20121190200',
'53사단-부산': '20220280700',
'55사단-용인': '20120180200',
} as const;
export type 입영부대 = keyof typeof 입영부대CodeMap;
1 change: 1 addition & 0 deletions src/services/the-camp/requesters/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './login';
export * from './register-soldier';
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { assertsResponse } from './asserts-response';
import 성공_신규등록 from './test/성공-신규등록.json';
import 성공_이미등록된군인 from './test/성공-이미등록된군인.json';

describe('assertsResponse', () => {
it('성공-신규등록', () => {
expect(() => assertsResponse(성공_신규등록 as any)).not.toThrow();
});

it('성공-이미등록된군인', () => {
expect(() => assertsResponse(성공_이미등록된군인 as any)).not.toThrow();
});

it('실패', () => {
expect(() =>
assertsResponse({
data: {
resultCd: '-1',
resultMsg: '알 수 없는 오류가 발생하였습니다.',
},
} as any),
).toThrow('알 수 없는 오류가 발생하였습니다.');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { AxiosResponse } from 'axios';

export function assertsResponse(response: AxiosResponse) {
const successCodes = ['0000', 'E001'];

if (!successCodes.includes(response.data.resultCd)) {
// TODO: 추가정보 로깅
throw new Error(
response.data.resultMsg || '알 수 없는 오류가 발생하였습니다.',
);
}
}
1 change: 1 addition & 0 deletions src/services/the-camp/requesters/register-soldier/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './register-soldier.requester'
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { loginRequester } from '../login';
import { registerSoldierRequester } from './register-soldier.requester';

describe.skip('RegisterSoldierRequester e2e', () => {
it('성공', async () => {
const session = await loginRequester.request({
id: '',
password: '',
});
await registerSoldierRequester.request(
{
성분: '예비군인/훈련병',
군종: '육군',
이름: '홍길동',
입영부대: '육군훈련소-논산',
관계: '팬',
생년월일: '2001-01-01',
입영일: '2022-02-14',
전화번호: '01012341234',
},
session,
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { TheCampSession } from '@common/types';
import { Parameter } from '@core/http';
import {
관계,
관계CodeMap,
군종,
군종CodeMap,
성분,
성분CodeMap,
입영부대,
입영부대CodeMap,
} from '@core/types';
import axios, { AxiosRequestConfig } from 'axios';

import { assertsResponse } from './asserts-response';

export class RegisterSoldierRequester {
constructor(private readonly asserts = assertsResponse) {}

async request(
dto: RegisterSoldierDto,
session: TheCampSession,
): Promise<void> {
const response = await axios.post(
'https://www.thecamp.or.kr/missSoldier/insertDirectMissSoldierA.do',
this.createPayload(dto, session),
this.createOptions(session),
);
this.asserts(response);
}

private createPayload(
{
성분,
군종,
이름,
입영부대,
관계,
생년월일,
입영일,
전화번호,
}: RegisterSoldierDto,
session: TheCampSession,
): string {
return new Parameter({
iuid: session.extra?.IUID || '',
missSoldierClassCdNm: 성분,
missSoldierClassCd: 성분CodeMap[성분],
grpCdNm: 군종,
grpCd: 군종CodeMap[군종],
trainUnitCd: 입영부대CodeMap[입영부대],
missSoldierRelationshipCd: 관계CodeMap[관계],
name: 이름,
birth: 생년월일,
enterDate: 입영일,
phoneNo: 전화번호 || '',
countryCode: '39|+82',
normalUnitCd: '',
normalUnitNm: '',
soldierClassCd: '',
}).toString();
}

private createOptions(session: TheCampSession): AxiosRequestConfig {
return {
headers: {
Accept: 'application/json, text/javascript, */*; q=0.01',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'User-Agent':
' Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.70 Whale/3.13.131.27 Safari/537.36',
Host: 'www.thecamp.or.kr',
Origin: 'https://www.thecamp.or.kr',
Referer:
' https://www.thecamp.or.kr/missSoldier/viewMissSoldierSearch.do',
'X-Requested-With': 'XMLHttpRequest',
'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="98", "Whale";v="3"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Dest': 'empty',
Cookie: session.cookies
.map(({ key, value }) => `${key}=${value}`)
.join('; '),
},
};
}
}

export interface RegisterSoldierDto {
성분: 성분;
군종: 군종;
관계: 관계;
입영부대: 입영부대;
이름: string;
생년월일: string; // yyyy-MM-dd
입영일: string; // yyyy-MM-dd
전화번호?: string;
}
export const registerSoldierRequester = new RegisterSoldierRequester();
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"data": { "resultCd": "0000", "resultMsg": "정상처리되었습니다." }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"data": {
"resultCd": "E001",
"resultMsg": "이미 등록된 군인입니다. 재등록하시려면 기존의 보고싶은 군인을 삭제해 주시기 바랍니다."
}
}
22 changes: 20 additions & 2 deletions src/services/the-camp/the-camp.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import { TheCampSession } from '@common/types';
import { Credential } from '@core/types';

import { loginRequester as _loginRequester } from './requesters';
import {
loginRequester as _loginRequester,
RegisterSoldierDto,
registerSoldierRequester as _registerSoldierRequester,
} from './requesters';

export class TheCampService {
constructor(private readonly loginRequester = _loginRequester) {}
constructor(
private readonly loginRequester = _loginRequester,
private readonly registerSoldierRequester = _registerSoldierRequester,
) {}

async login(credential: Credential): Promise<TheCampSession> {
return await this.loginRequester.request(credential);
}

/**
* 주의: 잘못된 정보여도 성공 응답이 옴
*/
async registerSoldier(
dto: RegisterSoldierDto,
session: TheCampSession,
): Promise<void> {
await this.registerSoldierRequester.request(dto, session);
}
}
export const theCampService = new TheCampService();

0 comments on commit aefedcf

Please sign in to comment.