Skip to content

Commit

Permalink
Merge pull request #130 from GDSC-PKNU-Official/dev
Browse files Browse the repository at this point in the history
부리미 서버 1.02v 배포
  • Loading branch information
pp449 authored Oct 10, 2023
2 parents fa3af32 + 81bc862 commit 9bd5585
Show file tree
Hide file tree
Showing 13 changed files with 397 additions and 262 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ dist-ssr
.env*
.flaskenv*
!.env.project
!.env.vault
!.env.vault
tmp
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ services:
- --collation-server=utf8mb4_unicode_ci
volumes:
- ./sqls:/docker-entrypoint-initdb.d
- ./tmp:/var/lib/mysql

networks:
mysql_db:
16 changes: 15 additions & 1 deletion src/apis/notice/controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { getNotices, getSchoolNotices, getWhalebe } from '@apis/notice/service';
import {
getLanguage,
getNotices,
getSchoolNotices,
getWhalebe,
} from '@apis/notice/service';
import express, { Request, Response } from 'express';

const router = express.Router();
Expand Down Expand Up @@ -26,4 +31,13 @@ router.get('/whalebe', async (req: Request, res: Response) => {
}
});

router.get('/language', async (req: Request, res: Response) => {
try {
const languageNoti = await getLanguage();
res.json(languageNoti);
} catch (err) {
res.json();
}
});

export default router;
19 changes: 17 additions & 2 deletions src/apis/notice/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ export const getWhalebe = async (): Promise<WhalebeData[]> => {
if (err) notificationToSlack('웨일비 조회 실패');
const whalebeData = res as WhalebeData[];
const today = new Date();
const todayString = `${today.getFullYear()}-${String(
const todayString = `${today.getFullYear()}.${String(
today.getMonth() + 1,
).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
).padStart(2, '0')}.${String(today.getDate()).padStart(2, '0')}`;

const filteredData = whalebeData
.filter((data) => data.date >= todayString)
Expand All @@ -63,3 +63,18 @@ export const getWhalebe = async (): Promise<WhalebeData[]> => {
});
});
};

export const getLanguage = async (): Promise<Notice[]> => {
const query = `SELECT * FROM 어학공지 ORDER BY STR_TO_DATE(uploadDate, '%Y-%m-%d') DESC;`;
return new Promise<Notice[]>((resolve) => {
db.query(query, (err, res) => {
if (err) {
notificationToSlack('어학 공지 응답 실패');
resolve([]);
return;
}
const languageNoti = res as Notice[];
resolve(languageNoti);
});
});
};
6 changes: 6 additions & 0 deletions src/config/crawlingURL.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const PKNU_URL = {
LANGUAGE_NOTICE_EXCHANGE_STUDENT:
'https://www.pknu.ac.kr/main/163?pageIndex=1&bbsId=2&searchCondition=title&searchKeyword=교환학생&cd=',
LANGUAGE_NOTICE_LANGUAGE_TRANING:
'https://www.pknu.ac.kr/main/163?pageIndex=1&bbsId=2&searchCondition=title&searchKeyword=어학연수&cd=',
};
4 changes: 3 additions & 1 deletion src/crawling/noticeCrawling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const noticeCrawling = async (college: College): Promise<string> => {

export const noticeListCrawling = async (
link: string,
inputHostLink?: string,
): Promise<NoticeLists> => {
const response = await axios.get(link);
const hostLink =
Expand Down Expand Up @@ -77,7 +78,8 @@ export const noticeListCrawling = async (
const anchorElement = $(element).find('a');
let tmpLink = anchorElement.attr('href');

if (tmpLink[0] === '?') tmpLink = link + tmpLink;
if (inputHostLink) tmpLink = inputHostLink + tmpLink;
else if (tmpLink[0] === '?') tmpLink = link + tmpLink;
else if (tmpLink[0] === '/') tmpLink = hostLink + tmpLink;

const findDate = $(element)
Expand Down
237 changes: 0 additions & 237 deletions src/db/data/handler.ts
Original file line number Diff line number Diff line change
@@ -1,237 +0,0 @@
import {
noticeContentCrawling,
noticeCrawling,
noticeListCrawling,
} from '@crawling/noticeCrawling';
import { whalebeCrawling } from '@crawling/whalebeCrawling';
import { RowDataPacket } from 'mysql2';
import { College, Notice } from 'src/@types/college';
import db from 'src/db';
import notificationToSlack from 'src/hooks/notificateToSlack';

export interface PushNoti {
[key: string]: string[];
}

export const saveDepartmentToDB = async (college: College[]): Promise<void> => {
const saveCollegePromises = college.map((data) => {
const saveCollegeQuery = `INSERT INTO departments (collegeName, departmentName, departmentSubName, departmentLink) VALUES ('${data.collegeName}', '${data.departmentName}', '${data.departmentSubName}', '${data.departmentLink}');`;
return new Promise<void>((resolve) => {
db.query(saveCollegeQuery, async (error) => {
if (error) {
await notificationToSlack(`DB에 학과 삽입 실패`);
resolve();
return;
}
console.log('단과대 입력 성공!');
resolve();
});
});
});

await Promise.all(saveCollegePromises);
};

const saveNotice = (notice: Notice, major: string): Promise<void> => {
const saveNoticeQuery =
'INSERT INTO ' + major + ' (title, link, uploadDate) VALUES (?, ?, ?)';
const values = [notice.title, notice.path, notice.date];

return new Promise((resolve) => {
db.query(saveNoticeQuery, values, (err) => {
if (err) {
console.log(`${major} 공지사항 입력 실패`);
resolve();
return;
}
console.log(`${major} 공지사항 입력 성공`);
resolve();
});
});
};

export const saveNoticeToDB = async (): Promise<PushNoti> => {
const selectQuery = 'SELECT * FROM departments;';
const results = await new Promise<College[]>((resolve) => {
db.query(selectQuery, (error, results) => {
if (error) {
notificationToSlack(selectQuery + '실패');
resolve([]);
return;
}
resolve(results as College[]);
});
});

const savePromises: Promise<void>[] = [];
const newNoticeMajor: PushNoti = {};

for (const row of results) {
const college: College = {
collegeName: row.collegeName,
departmentName: row.departmentName,
departmentSubName: row.departmentSubName,
departmentLink: row.departmentLink,
};

const noticeLink = await noticeCrawling(college);
const noticeLists = await noticeListCrawling(noticeLink);
if (
noticeLists.normalNotice.length === 0 &&
noticeLists.pinnedNotice.length === 0
) {
notificationToSlack(`${noticeLink} 크롤링 실패`);
continue;
}

const major =
college.departmentSubName === '-'
? college.departmentName
: college.departmentSubName;

if (noticeLists.pinnedNotice !== undefined) {
const pinnedNotiQuery = `SELECT link FROM ${major}고정;`;
db.query(pinnedNotiQuery, async (err, res) => {
if (err) {
await notificationToSlack(pinnedNotiQuery.split('ORDER')[0] + '에러');
return;
}
const rows = res as RowDataPacket[];
let pinnedNotiLink: string[] = [];

if (Array.isArray(rows) && rows.length > 0)
pinnedNotiLink = rows.map((row) => row.link);

for (const notice of noticeLists.pinnedNotice) {
const result = await noticeContentCrawling(notice);
if (result.path === '') {
notificationToSlack(`${notice} 콘텐츠 크롤링 실패`);
continue;
}
if (!pinnedNotiLink.includes(result.path)) {
savePromises.push(saveNotice(result, major + '고정'));
}
}
});
}

const normalNotiQuery = `SELECT link FROM ${major}일반;`;
db.query(normalNotiQuery, async (err, res) => {
if (err) {
await notificationToSlack(normalNotiQuery.split('ORDER')[0] + '에러');
return;
}

const rows = res as RowDataPacket[];
let normalNotiLink: string[] = [];
if (Array.isArray(rows) && rows.length > 0)
normalNotiLink = rows.map((row) => row.link);

for (const notice of noticeLists.normalNotice) {
const result = await noticeContentCrawling(notice);
if (result.path === '') {
notificationToSlack(`${notice} 콘텐츠 크롤링 실패`);
continue;
}

if (!normalNotiLink.includes(result.path)) {
if (!newNoticeMajor[major]) newNoticeMajor[major] = [];

newNoticeMajor[major].push(result.title);
savePromises.push(saveNotice(result, major + '일반'));
}
}
});
}

await Promise.all(savePromises);
return newNoticeMajor;
};

const saveSchoolNotice = async (
notices: string[],
mode: string,
): Promise<Promise<void>[]> => {
const query = `SELECT link FROM 학교${mode} ORDER BY STR_TO_DATE(uploadDate, '%Y-%m-%d') DESC LIMIT 1;`;
const res = await new Promise<string>((resolve) => {
db.query(query, async (err, res) => {
if (err) {
await notificationToSlack(query.split('ORDER')[0]);
resolve('');
return;
}
const rows = res as RowDataPacket[];
if (Array.isArray(rows) && rows.length > 0) {
const link = rows[0].link;
resolve(link);
}
resolve('');
});
});

const saveNoticeQuery = `INSERT INTO 학교${mode} (title, link, uploadDate) VALUES (?, ?, ?);`;
const savePromises: Promise<void>[] = [];

for (const list of notices) {
const notice = await noticeContentCrawling(list);
if (notice.path === '') {
notificationToSlack(`${notice} 콘텐츠 크롤링 실패`);
continue;
}
if (res === notice.path) break;

savePromises.push(
new Promise<void>((resolve) => {
const values = [notice.title, notice.path, notice.date];
db.query(saveNoticeQuery, values, async (error) => {
if (error) {
console.log('학교 공지사항 입력 실패!');
resolve();
return;
}
console.log('학교 공지사항 입력 성공!');
resolve();
});
}),
);
}

return savePromises;
};

export const saveSchoolNoticeToDB = async (): Promise<void> => {
const savePromises: Promise<void>[] = [];
const pknuNoticeLink = 'https://www.pknu.ac.kr/main/163';
const noticeLists = await noticeListCrawling(pknuNoticeLink);
if (noticeLists.pinnedNotice !== undefined) {
const pinnedNoticePromises = await saveSchoolNotice(
noticeLists.pinnedNotice,
'고정',
);
savePromises.push(...pinnedNoticePromises);
}
const normalNoticePromises = await saveSchoolNotice(
noticeLists.normalNotice,
'일반',
);
savePromises.push(...normalNoticePromises);

await Promise.all(savePromises);
};

export const saveWhalebeToDB = async (): Promise<void> => {
const query = 'INSERT INTO 웨일비 (title, date, imgUrl) VALUES (?, ?, ?)';
const whalebeDatas = await whalebeCrawling();

const promises = whalebeDatas.map((data) => {
const values = [data.title, data.date, data.imgUrl];

return new Promise<void>((resolve) => {
db.query(query, values, () => {
resolve();
});
});
});

Promise.all(promises);
};
Loading

0 comments on commit 9bd5585

Please sign in to comment.