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
70 changes: 70 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"form-data": "^4.0.0",
"ioredis": "^5.3.2",
"joi": "^17.6.0",
"open-graph-scraper": "^6.8.1",
"openai": "^3.3.0",
"passport": "^0.6.0",
"passport-google-oauth20": "^2.0.0",
Expand Down
2 changes: 1 addition & 1 deletion src/common/logger.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as winston from 'winston';
import * as DailyRotateFile from 'winston-daily-rotate-file';
import DailyRotateFile from 'winston-daily-rotate-file';

const { combine, label, printf, colorize } = winston.format;
const logFormat = printf(({ level, label, message }) => {
Expand Down
8 changes: 4 additions & 4 deletions src/contents/contents.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { LoadReminderCountOutput } from './dtos/load-personal-remider-count.dto'
import { UserRepository } from '../users/repository/user.repository';
import { ContentRepository } from './repository/content.repository';
import { CategoryRepository } from '../categories/category.repository';
import { getLinkInfo } from './util/content.util';
import { getOgData } from './util/content.util';
import { GetLinkInfoResponseDto } from './dtos/get-link.response.dto';
import { checkContentDuplicateAndAddCategorySaveLog } from '../categories/utils/category.util';
import { Transactional } from '../common/aop/transactional';
Expand Down Expand Up @@ -69,7 +69,7 @@ export class ContentsService {
siteName,
description,
coverImg,
} = await getLinkInfo(link);
} = await getOgData(link);
title = title ? title : linkTitle;

let category: Category | undefined = undefined;
Expand Down Expand Up @@ -132,7 +132,7 @@ export class ContentsService {

await Promise.all(
contentLinks.map(async (link) => {
const { title, description, coverImg, siteName } = await getLinkInfo(
const { title, description, coverImg, siteName } = await getOgData(
link,
);

Expand Down Expand Up @@ -391,7 +391,7 @@ export class ContentsService {
}

async getLinkInfo(link: string) {
const data = await getLinkInfo(link);
const data = await getOgData(link);

return new GetLinkInfoResponseDto(data);
}
Expand Down
14 changes: 7 additions & 7 deletions src/contents/dtos/get-link.response.dto.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { ApiPropertyOptional } from '@nestjs/swagger';
import { LinkInfo } from '../types/link-info.interface';

export class GetLinkInfoResponseDto {
@ApiProperty({
@ApiPropertyOptional({
description: '아티클 제목',
example: '[Terraform] 테라폼 훑어보기 — 턴태의 밑바닥부터 시작하는 de-vlog',
})
private readonly title: string;
private readonly title?: string;

@ApiProperty({
@ApiPropertyOptional({
description: '아티클 본문 일부',
example:
'인프라 구조마저 코드로 조작하고 있는 현재, 가장 많이 쓰이는 도구는 테라폼과 앤서블이 있습니다.',
})
private readonly description: string;
private readonly description?: string;

@ApiProperty({
@ApiPropertyOptional({
description: '썸네일/커버 이미지',
example:
'https://img1.daumcdn.net/thumb/R800x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz52vz%2FbtsCAOBzgTR%2FhFgGDKkr6iKWfU6eKeKUVk%2Fimg.png',
})
private readonly coverImg: string;
private readonly coverImg?: string;

@ApiPropertyOptional({
description: '아티클 사이트 주소',
Expand Down
6 changes: 3 additions & 3 deletions src/contents/types/link-info.interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export interface LinkInfo {
title: string;
description: string;
coverImg: string;
title?: string;
description?: string;
coverImg?: string;
siteName?: string;
}
24 changes: 24 additions & 0 deletions src/contents/util/content.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@ import { BadRequestException } from '@nestjs/common';
import * as cheerio from 'cheerio';
import axios from 'axios';

import ogs from 'open-graph-scraper';

export async function getOgData(link: string) {
try {
const { result } = await ogs({
url: link,
});

return {
title: result.ogTitle ?? '',
description: result.ogDescription ?? '',
coverImg: result.ogImage ? result.ogImage[0].url : '',
siteName: result.ogSiteName ?? '',
};
} catch {
return {
title: '',
description: '',
coverImg: '',
siteName: '',
};
}
}

export const getLinkInfo = async (link: string) => {
let title: string | undefined = '';
let coverImg: string | undefined = '';
Expand Down
2 changes: 1 addition & 1 deletion src/mail/mail.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { EmailVar, MailModuleOptions } from './mail.interface';
import axios from 'axios';
import * as FormData from 'form-data';
import FormData from 'form-data';
import { CONFIG_OPTIONS } from '../common/common.constants';

@Injectable()
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"strictBindCallApply": true,
"strictPropertyInitialization": false,
"noImplicitThis": true,
"alwaysStrict": true
"alwaysStrict": true,
"esModuleInterop": true
}
}