Skip to content

Commit

Permalink
fix: notice read controller (logic, caching)
Browse files Browse the repository at this point in the history
  • Loading branch information
ptyoiy committed May 5, 2024
1 parent 2fde152 commit cadd690
Show file tree
Hide file tree
Showing 14 changed files with 61 additions and 89 deletions.
19 changes: 10 additions & 9 deletions controllers/common_method/user_information.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,20 +121,21 @@ export async function getNoticeLikeInfo(userId: string) {
export async function getNoticeReadInfo(userId: string) {
const redisKey = `user:noticeReads:${userId}`;

const noticeReadsRedis = await redisClient.get(redisKey);
const noticeReadsRedis = await redisClient.sMembers(redisKey);
if (noticeReadsRedis) {
return JSON.parse(noticeReadsRedis);
return noticeReadsRedis;
}

const noticeReads = await Read.findAll({
const noticeReads = await Read.findOne({
where: { fk_user_id: userId },
include: [{ model: ReadAsset, as: 'ReadAssets' }]
});

if (noticeReads) {
await redisClient.set(redisKey, JSON.stringify(noticeReads), { EX: EXPIRE });
return noticeReads;
} else {
return [];
if (!noticeReads) {
// 없을 경우 잘못된 body
throw new Error(`잘못된 userId:${userId} 입니다.`)
}
const list = noticeReads.ReadAssets.map(ra => ra.fk_notice_id.toString());
await redisClient.sAdd(`user:noticeReads:${userId}`, list);

return list
}
8 changes: 4 additions & 4 deletions controllers/common_method/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ const modelMap = new Map([
]);

export interface IGenericUserRequest {
user_id?: number;
notice_id?: number;
event_id?: number;
user_id?: string;
notice_id?: string;
event_id?: string;
}

// Request body 검증 함수
Expand All @@ -36,7 +36,7 @@ export async function findObjectByPk(body: IGenericUserRequest) {
const Model = modelMap.get(key);
const object = await Model.findByPk(body[key]);
if (!object) {
errors.push(`${key}에 해당하는 객체를 찾을 수 없습니다.`);
errors.push(`${body[key]}:${key}에 해당하는 객체를 찾을 수 없습니다.`);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions controllers/event/event_bookmark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ export const setBookmark = async (
// 북마크에 이미 추가되어 있는지 확인
let [bookmark, created] = await Bookmark.findOrCreate({
where: { fk_user_id: user_id },
defaults: { fk_user_id: user_id },
defaults: { fk_user_id: +user_id },
transaction,
logging: console.log
})
// BookmarkAsset 테이블에 항목 추가
await BookmarkAsset.create({
fk_event_id: event_id,
fk_event_id: +event_id,
fk_bookmark_id: bookmark.id,
}, { transaction, ignoreDuplicates: true });

Expand Down
4 changes: 2 additions & 2 deletions controllers/event/event_like.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ async function updateLikeStatus(body: IEventUserRequest) {
},
defaults: { // 새로 생성될 때 사용할 기본 값들
like,
fk_event_id: event_id,
fk_user_id: user_id
fk_event_id: +event_id,
fk_user_id: +user_id
},
transaction,
logging: console.log
Expand Down
4 changes: 2 additions & 2 deletions controllers/event/request/request.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export interface IEventUserRequest {
event_id: number;
user_id: number;
event_id: string;
user_id: string;
like: "like" | "dislike" | null;
}
2 changes: 2 additions & 0 deletions controllers/jwt/jwt.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as Express from 'express';
import jwt from "jsonwebtoken";
import { mode } from '../../adminPage/components/index.js';
import { redisClient } from '../../redis/connect.js';

const ACCESS_EXPIRY = '1d';
Expand All @@ -16,6 +17,7 @@ enum TokenType {
}

export const verifyToken = (req: Express.Request, res, next) => {
if (mode == 'development') next();
const token = req.cookies.accessToken;
const id = req.cookies.id;
if (!token) {
Expand Down
5 changes: 3 additions & 2 deletions controllers/notice/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { setLike } from "./notice_like.js";
import { getUnread, setRead } from "./notice_read.js";
import { getRead, setRead } from "./notice_read.js";
import { getAlertAll, getNotice, getNoticeAll } from "./notice_search.js";

export {
getAlertAll,
getNotice, getNoticeAll, getUnread, setLike, setRead
getNotice, getNoticeAll, getRead, setLike, setRead
};

4 changes: 2 additions & 2 deletions controllers/notice/notice_like.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ async function updateLikeStatus(body: INoticeUserRequest) {
},
defaults: { // 새로 생성될 때 사용할 기본 값들
like,
fk_notice_id: notice_id,
fk_user_id: user_id
fk_notice_id: +notice_id,
fk_user_id: +user_id
},
transaction,
logging: console.log
Expand Down
77 changes: 21 additions & 56 deletions controllers/notice/notice_read.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import * as express from "express";
import { INoticeUserRequest } from "./request/request.js";
import { findObjectByPk, findUser, validateRequestBody } from "../common_method/validator.js";
import { Notice, Read, ReadAsset, sequelize } from "../../models/index.js";
import { IRead, IReadAsset } from "../../models/types.js";
import { Op } from "sequelize";
import { Read, ReadAsset, sequelize } from "../../models/index.js";
import { redisClient } from "../../redis/connect.js";
import { getNoticeReadInfo } from "../common_method/user_information.js";
import { findObjectByPk, validateRequestBody } from "../common_method/validator.js";
import { INoticeUserRequest } from "./request/request.js";

const bodyList = [
"notice_id",
Expand All @@ -15,8 +13,8 @@ const bodyList = [
const EXPIRE = 3600; // 유효시간 1시간

// GET /users/read
export const getUnread = async (
{ params, body }: express.Request<any, any, { user_id: number }>,
export const getRead = async (
{ params, body }: express.Request<any, any, { user_id: string }>,
res: express.Response,
next: any
) => {
Expand All @@ -25,32 +23,11 @@ export const getUnread = async (
if (!validateRequestBody(body, ["user_id"])) {
return res.status(404).json({ error: "잘못된 key 입니다." });
}
const user_id = body.user_id;

// DB에서 유저 찾기
await findUser(user_id);
const {user_id} = body;

// 해당 사용자의 Read 항목 찾기
const read = await Read.findOne({ where: { fk_user_id: user_id } }) as IRead | null;

if (!read) {
// Read 항목이 없으면 모든 공지 반환
const allNotices = await Notice.findAll();
return res.status(200).json(allNotices);
} else {
// ReadAsset 테이블에서 읽은 공지 목록 찾기
const readAssetsList = await ReadAsset.findAll({
where: { fk_read_id: read.id },
attributes: ['fk_notice_id']
}) as IReadAsset[];
const readNoticeIds = readAssetsList.map(asset => asset.fk_notice_id);

// 읽지 않은 공지 찾기
const unreadNotices = await Notice.findAll({
where: { id: { [Op.notIn]: readNoticeIds } }
});
return res.status(200).json(unreadNotices);
}
const read = await getNoticeReadInfo(user_id);
return res.status(200).json(read);
} catch (error) {
console.log(error);
return res.status(500).json({ error: "서버 내부 에러" });
Expand All @@ -70,47 +47,35 @@ export const setRead = async (
return res.status(404).json({ error: "잘못된 key 입니다." });
}
const { user_id, notice_id } = body;

// DB에서 공지와 유저 찾기
const errorMessage = await findObjectByPk(body);
if (errorMessage) {
return res.status(400).json({ error: errorMessage });
}

// Read 테이블이 생성되어 있는지 확인
let read = await Read.findOne({ where: { fk_user_id: user_id } }) as IRead | null;

// Read 테이블 생성이 안되어 있다면 새로 생성
if (!read) {
read = await Read.create({ fk_user_id: user_id }, { transaction }) as IRead;
}

// 해당 ReadAsset 항목이 이미 있는지 확인
const existingReadAsset = await ReadAsset.findOne({
where: {
fk_notice_id: notice_id,
fk_read_id: read.id
}
const read = await Read.findOne({
where: { fk_user_id: user_id },
include: [{model: ReadAsset, as: "ReadAssets"}],
transaction
});

// ReadAsset 항목이 존재하지 않으면 추가
if (!existingReadAsset) {
await ReadAsset.create({
fk_notice_id: notice_id,
fk_read_id: read.id,
}, { transaction });
}
// ReadAsset 항목 추가
await ReadAsset.create({
fk_notice_id: notice_id,
fk_read_id: read.id,
}, { transaction, ignoreDuplicates: true });

await transaction.commit();

const list = read.ReadAssets.map(ra => ra.fk_notice_id.toString());
if (!list.includes(notice_id)) list.push(notice_id.toString());
// Redis에 있는 해당 사용자의 읽음 정보 업데이트
const updatedReadAssets = await getNoticeReadInfo(user_id.toString());
await redisClient.set(`user:read:${user_id}`, JSON.stringify(updatedReadAssets), { EX: EXPIRE });
await redisClient.sAdd(`user:noticeReads:${user_id}`, list);

return res.status(200).json({ message: "읽음 설정 성공했습니다." });
} catch (error) {
await transaction.rollback();
console.log(error);
await transaction.rollback();
return res.status(500).json({ error: "서버 내부 에러" });
}
};
4 changes: 2 additions & 2 deletions controllers/notice/request/request.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export interface INoticeUserRequest {
notice_id: number;
user_id: number;
notice_id: string;
user_id: string;
like: 'like' | 'dislike' | null
}
3 changes: 2 additions & 1 deletion models/reads.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { DataTypes } from 'sequelize';
import { sequelize } from './sequelize.js';
import { IRead } from './types.js';

const Read = sequelize.define('Read', {
const Read = sequelize.define<IRead>('Read', {
id: {
type: DataTypes.INTEGER.UNSIGNED,
primaryKey: true,
Expand Down
7 changes: 4 additions & 3 deletions models/reads_assets.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { DataTypes } from 'sequelize';
import { sequelize } from './sequelize.js';
import Read from './reads.js';
import { sequelize } from './sequelize.js';
import { IReadAsset } from './types.js';

const ReadAsset = sequelize.define('Read', {
const ReadAsset = sequelize.define<IReadAsset>('Read', {
id: {
type: DataTypes.INTEGER.UNSIGNED,
primaryKey: true,
Expand Down Expand Up @@ -40,5 +41,5 @@ const ReadAsset = sequelize.define('Read', {
});

Read.hasMany(ReadAsset, { as: 'ReadAssets', foreignKey: 'fk_read_id' });

ReadAsset.belongsTo(Read, {foreignKey: 'fk_read_id'});
export default ReadAsset;
7 changes: 4 additions & 3 deletions models/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,12 @@ export interface IBookmarkAsset {
export interface IRead extends Model {
id: number;
fk_user_id: number;
ReadAssets?: IReadAsset[];
}

export interface IReadAsset extends Model {
id?: number;
fk_notice_id?: number;
fk_read_id?: number;
id: number;
fk_notice_id: number;
fk_read_id: number;
}

2 changes: 1 addition & 1 deletion routes/notice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ noticeRouter.get('/posts/notices/:noticeId', noticeController.getNotice);
noticeRouter.get('/posts/alerts/:noticeId', noticeController.getNotice);

/** 읽음 표시 */
noticeRouter.get('/users/read', verifyToken, noticeController.getUnread);
noticeRouter.get('/users/read', verifyToken, noticeController.getRead);
noticeRouter.post('/users/read', verifyToken, noticeController.setRead);

export default noticeRouter;

0 comments on commit cadd690

Please sign in to comment.