Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 70 additions & 70 deletions src/auth/oauth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { RedisService } from '../infra/redis/redis.service';
import { REFRESH_TOKEN_KEY } from './constants';
import { KakaoLoginRequest } from './dtos/request/kakao-login.request.dto';
import { KakaoLoginDto } from './dtos/kakao-login.dto';
import { PROVIDER } from '../users/constant/provider.constant';

@Injectable()
export class OAuthService {
Expand Down Expand Up @@ -97,61 +98,56 @@ export class OAuthService {
throw new BadRequestException('Please Agree to share your email');
}

let user = await this.userRepository.findOneByEmail(email);
const user = await this.userRepository.findOneByEmail(email);
if (user) {
return this.oauthLogin(user.email);
}

// 회원가입인 경우 기본 카테고리 생성 작업 진행
if (!user) {
user = new User();
user.email = email;
user.name = userInfo.kakao_account.profile.nickname;
user.profileImage = userInfo.kakao_account.profile?.profile_image_url;
user.password = this.encodePasswordFromEmail(
email,
process.env.KAKAO_JS_KEY,
);
const newUser = User.of({
email,
name: userInfo.kakao_account.profile.nickname,
profileImage: userInfo.kakao_account.profile?.profile_image_url,
password: this.encodePasswordFromEmail(email, process.env.KAKAO_JS_KEY),
provider: PROVIDER.KAKAO,
});

await this.userRepository.createOne(user);
await this.categoryRepository.createDefaultCategories(user);
}
await this.userRepository.createOne(newUser);
await this.categoryRepository.createDefaultCategories(newUser);

return this.oauthLogin(user.email);
return this.oauthLogin(newUser.email);
} catch (e) {
throw e;
}
}

async createOneWithKakao({ authorizationToken }: KakaoLoginDto) {
try {
const { userInfo } = await this.oauthUtil.getKakaoUserInfo(
authorizationToken,
);
const { userInfo } =
await this.oauthUtil.getKakaoUserInfo(authorizationToken);

const email = userInfo.kakao_account.email;
if (!email) {
throw new BadRequestException('Please Agree to share your email');
}

let user = await this.userRepository.findOneByEmail(email);

// 회원가입인 경우 기본 카테고리 생성 작업 진행
if (!user) {
user = new User();
user.email = email;
user.name = userInfo.kakao_account.profile.nickname;
user.profileImage = userInfo.kakao_account.profile?.profile_image_url;
user.password = this.encodePasswordFromEmail(
email,
process.env.KAKAO_JS_KEY,
);
const email = userInfo.kakao_account.email;
if (!email) {
throw new BadRequestException('Please Agree to share your email');
}

await this.userRepository.createOne(user);
await this.categoryRepository.createDefaultCategories(user);
}
const user = await this.userRepository.findOneByEmail(email);

if (user) {
return this.oauthLogin(user.email);
} catch (e) {
throw e;
}

// 회원가입인 경우 기본 카테고리 생성 작업 진행
const newUser = User.of({
email,
name: userInfo.kakao_account.profile.nickname,
profileImage: userInfo.kakao_account.profile?.profile_image_url,
password: this.encodePasswordFromEmail(email, process.env.KAKAO_JS_KEY),
provider: PROVIDER.KAKAO,
});

await this.userRepository.createOne(newUser);
await this.categoryRepository.createDefaultCategories(newUser);
return this.oauthLogin(newUser.email);
}

// Login with Google account info
Expand All @@ -160,28 +156,28 @@ export class OAuthService {
name,
picture,
}: googleUserInfo): Promise<LoginOutput> {
try {
let user = await this.userRepository.findOneByEmail(email);

// 회원가입인 경우 기본 카테고리 생성 작업 진행
if (!user) {
user = new User();
user.email = email;
user.name = name;
user.profileImage = picture;
user.password = this.encodePasswordFromEmail(
email,
process.env.GOOGLE_CLIENT_ID,
);

await this.userRepository.createOne(user);
await this.categoryRepository.createDefaultCategories(user);
}
const user = await this.userRepository.findOneByEmail(email);

if (user) {
return this.oauthLogin(user.email);
} catch (e) {
throw e;
}

// 회원가입인 경우 기본 카테고리 생성 작업 진행
const newUser = User.of({
email,
name,
profileImage: picture,
password: this.encodePasswordFromEmail(
email,
process.env.GOOGLE_CLIENT_ID,
),
provider: PROVIDER.GOOGLE,
});

await this.userRepository.createOne(newUser);
await this.categoryRepository.createDefaultCategories(newUser);

return this.oauthLogin(newUser.email);
}

private encodePasswordFromEmail(email: string, key?: string): string {
Expand Down Expand Up @@ -229,21 +225,25 @@ export class OAuthService {

const { sub: id, email } = this.jwtService.decode(data.id_token);

let user = await this.userRepository.findOneByEmail(email);
const user = await this.userRepository.findOneByEmail(email);

if (!user) {
user = new User();
user.email = email;
user.name = email.split('@')[0];
user.password = this.encodePasswordFromEmail(
if (user) {
return this.oauthLogin(user.email);
}

const newUser = User.of({
email,
name: email.split('@')[0],
password: this.encodePasswordFromEmail(
email,
process.env.APPLE_CLIENT_ID,
);
),
provider: PROVIDER.APPLE,
});

await this.userRepository.createOne(user);
await this.categoryRepository.createDefaultCategories(user);
}
await this.userRepository.createOne(newUser);
await this.categoryRepository.createDefaultCategories(newUser);

return this.oauthLogin(user.email);
return this.oauthLogin(newUser.email);
}
}
15 changes: 0 additions & 15 deletions src/categories/category.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,19 +157,4 @@ export class CategoryController {
): Promise<LoadFrequentCategoriesOutput> {
return this.categoryService.loadFrequentCategories(user);
}

@ApiOperation({
summary: '아티클 카테고리 자동 지정',
description:
'아티클에 적절한 카테고리를 유저의 카테고리 목록에서 찾는 메서드',
})
@ApiBearerAuth('Authorization')
@UseGuards(JwtAuthGuard)
@Get('auto-categorize')
async autoCategorize(
@AuthUser() user: User,
@Query() { link }: AutoCategorizeRequest,
): Promise<AutoCategorizeOutput> {
return this.categoryService.autoCategorize(user, link);
}
}
136 changes: 1 addition & 135 deletions src/categories/category.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,79 +414,6 @@ export class CategoryService {
}
}

async autoCategorize(
user: User,
link: string,
): Promise<AutoCategorizeOutput> {
try {
const userInDb = await this.userRepository.findOneWithCategories(user.id);
if (!userInDb) {
throw new NotFoundException('User not found');
}

if (!userInDb.categories) {
throw new NotFoundException('Categories not found');
}
const categories: string[] = [];
userInDb.categories.forEach((category) => {
if (!category.parentId) {
categories.push(category.name);
}
});
const { title, siteName, description } = await getLinkInfo(link);

const content = await getLinkContent(link);

const questionLines = [
"You are a machine tasked with auto-categorizing articles based on information obtained through web scraping. You can only answer a single category name. Here is the article's information:",
];

if (title) {
questionLines.push(
`The article in question is titled "${title.trim()}"`,
);
}

if (content) {
const contentLength = content.length / 2;
questionLines.push(
`The 150 characters of the article is, "${content
.replace(/\s/g, '')
.slice(contentLength - 150, contentLength + 150)
.trim()}"`,
);
}

if (description) {
questionLines.push(`The description is ${description.trim()}"`);
}

if (siteName) {
questionLines.push(`The site's name is "${siteName.trim()}"`);
}

// Add the category options to the end of the list
questionLines.push(
`Please provide the most suitable category among the following. Here is Category options: [${categories.join(
', ',
)}, None]`,
);

// Join all lines together into a single string
const question = questionLines.join(' ');
console.log(question);

const response = await this.openaiService.createChatCompletion({
question,
temperature: 0,
});

return { category: response.choices[0].message?.content || 'None' };
} catch (e) {
throw e;
}
}

async autoCategorizeWithId(user: User, link: string) {
const _categories = await this.categoryRepository.findByUserId(user.id);
if (_categories.length === 0) {
Expand Down Expand Up @@ -539,6 +466,7 @@ Given the categories below, please provide suitable category for the article fol


Present your reply options in JSON format below.
- If there's no suitable category, must provide reply with "None".
\`\`\`json
{
"id": id,
Expand Down Expand Up @@ -569,66 +497,4 @@ Present your reply options in JSON format below.
throw e;
}
}

async autoCategorizeForTest(
autoCategorizeBody: AutoCategorizeBodyDto,
): Promise<AutoCategorizeOutput> {
try {
const { link, categories } = autoCategorizeBody;
const { title, siteName, description } = await getLinkInfo(link);

/**
* TODO: 본문 크롤링 개선 필요
* 현재 p 태그만 크롤링하는데, 불필요한 내용이 포함되는 경우가 많음
* 그러나 하나하나 예외 처리하는 방법을 제외하곤 방법을 못 찾은 상황
*/
const content = await getLinkContent(link);

const questionLines = [
"You are a machine tasked with auto-categorizing articles based on information obtained through web scraping. You can only answer a single category name. Here is the article's information:",
];

if (title) {
questionLines.push(
`The article in question is titled "${title.trim()}"`,
);
}

if (content) {
const contentLength = content.length / 2;
questionLines.push(
`The 150 characters of the article is, "${content
.replace(/\s/g, '')
.slice(contentLength - 150, contentLength + 150)
.trim()}"`,
);
}

if (description) {
questionLines.push(`The description is ${description.trim()}"`);
}

if (siteName) {
questionLines.push(`The site's name is "${siteName.trim()}"`);
}

// Add the category options to the end of the list
questionLines.push(
`Please provide the most suitable category among the following. Here is Category options: [${categories.join(
', ',
)}, None]`,
);

// Join all lines together into a single string
const question = questionLines.join(' ');

const response = await this.openaiService.createChatCompletion({
question,
});

return { category: response.choices[0].message?.content || 'None' };
} catch (e) {
throw e;
}
}
}
15 changes: 0 additions & 15 deletions src/test/test.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ import {
} from '@nestjs/swagger';
import { ErrorOutput } from '../common/dtos/output.dto';
import { ContentsService } from '../contents/contents.service';
import {
AutoCategorizeBodyDto,
AutoCategorizeOutput,
} from '../categories/dtos/category.dto';
import {
SummarizeContentOutput,
SummarizeContentBodyDto,
Expand Down Expand Up @@ -43,15 +39,4 @@ export class TestController {
): Promise<SummarizeContentOutput> {
return this.contentsService.testSummarizeContent(content);
}

@ApiOperation({
summary: '아티클 카테고리 자동 지정 (테스트용)',
description: 'url을 넘기면 적절한 아티클 카테고리를 반환하는 메서드',
})
@Post('auto-categorize')
async autoCategorize(
@Body() autoCategorizeBody: AutoCategorizeBodyDto,
): Promise<AutoCategorizeOutput> {
return this.categoryService.autoCategorizeForTest(autoCategorizeBody);
}
}
7 changes: 7 additions & 0 deletions src/users/constant/provider.constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const PROVIDER = {
GOOGLE: 'google',
KAKAO: 'kakao',
APPLE: 'apple',
} as const;

export type PROVIDER = (typeof PROVIDER)[keyof typeof PROVIDER];
Loading
Loading