Skip to content

Commit

Permalink
feat(the-camp): the camp service login 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
WhiteKiwi committed Mar 1, 2022
1 parent f19b92e commit d00f792
Show file tree
Hide file tree
Showing 17 changed files with 231 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/core/http/cookie.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface Cookie {
key: string;
value: string;
}
3 changes: 3 additions & 0 deletions src/core/http/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './cookie';
export * from './parameter';
export * from './session';
16 changes: 16 additions & 0 deletions src/core/http/parameter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export class Parameter {
constructor(
private readonly data: Record<string, string | number | boolean>,
) {}

toString() {
const rows: string[] = [];
for (const key in this.data) {
rows.push(
`${encodeURIComponent(key)}=${encodeURIComponent(this.data[key])}`,
);
}

return rows.join('&');
}
}
5 changes: 5 additions & 0 deletions src/core/http/session.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Cookie } from './cookie';

export interface Session {
cookies: Cookie[];
}
4 changes: 4 additions & 0 deletions src/core/types/credential.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface Credential {
id: string;
password: string;
}
1 change: 1 addition & 0 deletions src/core/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './credential';
1 change: 1 addition & 0 deletions src/services/the-camp/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './the-camp.service';
1 change: 1 addition & 0 deletions src/services/the-camp/requesters/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './login';
1 change: 1 addition & 0 deletions src/services/the-camp/requesters/login/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './login.requester';
13 changes: 13 additions & 0 deletions src/services/the-camp/requesters/login/login.requester.e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { LoginRequester } from './login.requester';

describe.skip('LoginRequester e2e', () => {
it('성공', async () => {
const loginRequester = new LoginRequester();

const session = await loginRequester.request({
id: '',
password: '',
});
console.log('session', session);
});
});
65 changes: 65 additions & 0 deletions src/services/the-camp/requesters/login/login.requester.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Parameter, Session } from '@core/http';
import { Credential } from '@core/types';
import axios, { AxiosRequestConfig } from 'axios';

import { parseLogin } from './parse-login';

export class LoginRequester {
constructor(private readonly parse = parseLogin) {}

async request(credential: Credential): Promise<Session> {
const response = await axios.post(
'https://www.thecamp.or.kr/login/loginA.do',
this.createPayload(credential),
this.createOptions(),
);
return this.parse(response);
}

private createPayload(credential: Credential) {
return new Parameter({
userId: credential.id,
userPwd: credential.password,
state: 'email-login',
autoLoginYn: 'Y',
withdrawDate: '',
withdrawReason: '',
reCertYn: '',
telecomCd: '',
telecomNm: '',
osType: '',
osVersion: '',
deviceModel: '',
appVersion: '',
deviceWidth: '',
deviceHeight: '',
resultCd: '',
resultMsg: '',
findPwType: 'pwFind',
}).toString();
}

private createOptions(): 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/login/viewLogin.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',
},
};
}
}
export const loginRequester = new LoginRequester();
37 changes: 37 additions & 0 deletions src/services/the-camp/requesters/login/parse-login.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { parseLogin } from './parse-login';
import 성공 from './test/성공.json';
import 실패_credentail from './test/실패-credentail.json';
import 실패_가입회원아님 from './test/실패-가입회원아님.json';

describe('parseLogin', () => {
it('성공', () => {
const cookies = parseLogin(성공 as any);

expect(cookies).toEqual([
{ key: 'userId', value: 'paul2314%40naver.com' },
{ key: 'Token', value: 'sUl%2B4ShTmCqsX%2BXtf7X8MQ%3D%3D' },
{ key: 'iuid', value: '5302760' },
{
key: 'nickname',
value: '%EC%A0%95%EC%9B%90%EB%B0%B0_%28%EC%9D%BC%EB%B0%98%29',
},
{ key: 'name', value: '%EC%A0%95%EC%9B%90%EB%B0%B0' },
{ key: 'memberGradeCd', value: '0000340003' },
{ key: 'userId', value: 'paul2314%40naver.com' },
{ key: 'checkAutoLogin', value: 'off' },
{ key: 'checkSaveId', value: 'off' },
]);
});

it('실패_credentail', () => {
expect(() => parseLogin(실패_credentail as any)).toThrow(
'이메일 또는 비밀번호가 맞지 않습니다.',
);
});

it('실패_가입회원아님', () => {
expect(() => parseLogin(실패_가입회원아님 as any)).toThrow(
'가입된 계정이 아닙니다. 회원가입 후 이용해주세요.',
);
});
});
34 changes: 34 additions & 0 deletions src/services/the-camp/requesters/login/parse-login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Cookie, Session } from '@core/http';
import { AxiosResponse } from 'axios';

export function parseLogin(response: AxiosResponse): Session {
assertsResponse(response);

const cookies: Cookie[] = [];
const setCookie = response.headers['set-cookie'];
// TODO: asserts

if (!setCookie?.length) {
throw new Error('');
}

for (const cookie of setCookie) {
const [key, value] = cookie.split(';')[0].split('=');
cookies.push({ key, value });
}

return { cookies };
}

function assertsResponse(response: any) {
if (response.data.resultCd === '9000')
throw new Error('가입된 계정이 아닙니다. 회원가입 후 이용해주세요.');

if (response.data.resultCd === '9001')
throw new Error('이메일 또는 비밀번호가 맞지 않습니다.');

if (response.data.resultCd !== '0000')
throw new Error(
response.data?.resultMsg || '알 수 없는 오류가 발생하였습니다',
);
}
22 changes: 22 additions & 0 deletions src/services/the-camp/requesters/login/test/성공.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"headers": {
"set-cookie": [
"userId=paul2314%40naver.com; Max-Age=604800; Expires=Tue, 08-Mar-2022 11:48:42 GMT; Path=/",
"Token=sUl%2B4ShTmCqsX%2BXtf7X8MQ%3D%3D; Max-Age=604800; Expires=Tue, 08-Mar-2022 11:48:42 GMT; Path=/",
"iuid=5302760; Max-Age=604800; Expires=Tue, 08-Mar-2022 11:48:42 GMT; Path=/",
"nickname=%EC%A0%95%EC%9B%90%EB%B0%B0_%28%EC%9D%BC%EB%B0%98%29; Max-Age=604800; Expires=Tue, 08-Mar-2022 11:48:42 GMT; Path=/",
"name=%EC%A0%95%EC%9B%90%EB%B0%B0; Max-Age=604800; Expires=Tue, 08-Mar-2022 11:48:42 GMT; Path=/",
"memberGradeCd=0000340003; Max-Age=604800; Expires=Tue, 08-Mar-2022 11:48:42 GMT; Path=/",
"userId=paul2314%40naver.com; Max-Age=2592000; Expires=Thu, 31-Mar-2022 11:48:42 GMT; Path=/",
"checkAutoLogin=off; Max-Age=2592000; Expires=Thu, 31-Mar-2022 11:48:42 GMT; Path=/",
"checkSaveId=off; Max-Age=2592000; Expires=Thu, 31-Mar-2022 11:48:42 GMT; Path=/"
]
},
"data": {
"resultCd": "0000",
"resultMsg": "정상처리되었습니다.",
"reCertYn": "Y",
"iuid": "5302760",
"newCheck": false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"data": {
"resultCd": "9001",
"resultMsg": "이메일 또는 비밀번호가 맞지 않습니다. 다시 확인하여 입력해 주세요."
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"data": {
"resultCd": "9000",
"resultMsg": "캠프 가입회원이 아닙니다. 회원가입 후 이용해 주세요."
}
}
12 changes: 12 additions & 0 deletions src/services/the-camp/the-camp.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Session } from '@core/http';
import { Credential } from '@core/types';

import { loginRequester as _loginRequester } from './requesters';

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

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

0 comments on commit d00f792

Please sign in to comment.