Commit 6b56633c authored by Yoon, Daeki's avatar Yoon, Daeki 😅
Browse files

아바타 파일 업로드 로직 구현

parent a0a0c03e
import { connect } from "mongoose";
import { mongoUri } from "../src/config";
import { Role, User } from "../src/models";
import { userDb } from "../src/db";
const roles = [
["admin", 1],
["manager", 10],
["staff", 100],
["user", 1000],
["guest", 10000],
];
connect(mongoUri)
.then(async (mongoose) => {
const adminRole = await Role.findOne({ name: "admin" });
await userDb.createUser({
email: "admin@example.com",
name: "admin",
role: adminRole?._id,
password: "asdfasdf",
});
await mongoose.disconnect();
})
.catch((error) => console.log("롤 초기 생성 에러", error));
...@@ -50,7 +50,11 @@ export const hasRole = (roleName: string) => { ...@@ -50,7 +50,11 @@ export const hasRole = (roleName: string) => {
if (!req.auth) { if (!req.auth) {
return res.status(401).send("로그인이 필요합니다"); return res.status(401).send("로그인이 필요합니다");
} }
const { userId } = req.auth; const { userId } = req.auth;
if (!(await userDb.isValidUserId(userId))) {
return res.status(401).send("유효한 사용자가 아닙니다");
}
const userRole = await roleDb.findRoleByUserId(userId); const userRole = await roleDb.findRoleByUserId(userId);
const maxRole = await roleDb.findRoleByName(roleName); const maxRole = await roleDb.findRoleByName(roleName);
if (maxRole && Number(maxRole.priority) >= Number(userRole.priority)) { if (maxRole && Number(maxRole.priority) >= Number(userRole.priority)) {
......
import { NextFunction, Request, Response } from "express";
import formidable from "formidable"; import formidable from "formidable";
import { isEmpty } from "../helpers";
import { asyncWrap } from "../helpers/asyncWrap"; import { asyncWrap } from "../helpers/asyncWrap";
import { TypedRequest } from "../types";
interface TypedRequest extends Request { export const uploadAvatar = asyncWrap(async (reqExp, res, next) => {
auth: any; const req = reqExp as TypedRequest;
user: any; const form = formidable({ multiples: false, uploadDir: "uploads" });
files: any;
}
export const fileUpload = asyncWrap(async (req, res, next) => {
const typedReq = req as TypedRequest;
const form = formidable();
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
form.parse(req, (err, fields, files) => { form.parse(req, (err, fields, files) => {
if (err) { if (err) {
...@@ -20,15 +13,11 @@ export const fileUpload = asyncWrap(async (req, res, next) => { ...@@ -20,15 +13,11 @@ export const fileUpload = asyncWrap(async (req, res, next) => {
return; return;
} }
console.log("fields", fields); // console.log("fields", fields);
console.log("files", files); // console.log("files", files);
typedReq.body = fields; req.body = fields;
req.files = files;
if (isEmpty(files)) {
typedReq.files = null;
} else {
typedReq.files = files;
}
resolve(files); resolve(files);
}); });
}); });
......
import { NextFunction, Request, Response } from "express"; import { NextFunction, Request, Response } from "express";
import { userDb } from "../db"; import formidable from "formidable";
import fs from "fs/promises";
import { fileDb, userDb } from "../db";
import { asyncWrap } from "../helpers/asyncWrap"; import { asyncWrap } from "../helpers/asyncWrap";
import { FileInfo } from "../models";
import { TypedRequest } from "../types";
import { TypedRequestAuth } from "./auth.controller"; import { TypedRequestAuth } from "./auth.controller";
interface TypedRequest extends Request {
auth: any;
user: any;
files: any;
}
export const createUser = asyncWrap(async (reqExp, res) => { export const createUser = asyncWrap(async (reqExp, res) => {
const req = reqExp as TypedRequest; const req = reqExp as TypedRequest;
const user = req.body; const user = req.body;
console.log("user body", user); // console.log("user body", user);
console.log("files ", req.files); // console.log("files ", req.files);
const newUser = await userDb.createUser(user); const file = req.files.avatar as formidable.File;
return res.json(newUser); let avatar;
try {
// 1) 아바타 이미지 저장
if (file) {
avatar = new FileInfo({
name: file.originalFilename,
url: file.newFilename,
isNew: true,
});
await fileDb.save(avatar);
// 2) 사용자에 아바타 항목 추가
user.avatar = avatar;
}
// 3) 사용자 만들기
const newUser = await userDb.createUser(user);
// 주의: ref는 반드시 save를 해야 디비에 생성이 됩니다.
return res.json(newUser);
} catch (error: any) {
console.log("error in create user:", error);
// 오류 발생시 저장된 파일 제거
if (file) {
avatar && (await fileDb.deleteFileById(avatar._id.toString()));
await fs.unlink(file.filepath);
}
res.status(422).send(error.message || "사용자 생성 오류");
}
}); });
export const deleteUser = asyncWrap(async (req, res) => { export const deleteUser = asyncWrap(async (req, res) => {
......
import formidable from "formidable";
import { HydratedDocument } from "mongoose";
import { FileInfo, IFileInfo } from "../models";
export const createFile = async (file: formidable.File) => {
const newFile = new FileInfo({
name: file.originalFilename,
url: file.newFilename,
});
const retFile = await newFile.save();
return retFile;
};
export const deleteFileById = async (fileId: string) => {
return await FileInfo.findByIdAndDelete(fileId);
};
export const save = async (fileInfo: HydratedDocument<IFileInfo>) => {
return await fileInfo.save();
};
export * as roleDb from "./role.db"; export * as fileDb from "./file.db";
export * as questionDb from "./question.db"; export * as questionDb from "./question.db";
export * as roleDb from "./role.db";
export * as surveyDb from "./survey.db"; export * as surveyDb from "./survey.db";
export * as userDb from "./user.db"; export * as userDb from "./user.db";
...@@ -15,6 +15,7 @@ export const createUser = async (user: IUser) => { ...@@ -15,6 +15,7 @@ export const createUser = async (user: IUser) => {
email: user.email, email: user.email,
password: hash, password: hash,
role: userRole, role: userRole,
avatar: user.avatar,
isNew: true, isNew: true,
}); });
const retUser = await newUser.save(); const retUser = await newUser.save();
...@@ -45,7 +46,10 @@ export const findUserByEmail = async ( ...@@ -45,7 +46,10 @@ export const findUserByEmail = async (
}; };
export const getUsers = async () => { export const getUsers = async () => {
const users = await User.find({}); const users = await User.find({}).populate({
path: "avatar",
select: "_id name url",
});
return users; return users;
}; };
...@@ -57,3 +61,12 @@ export const isUser = async (email: string) => { ...@@ -57,3 +61,12 @@ export const isUser = async (email: string) => {
return false; return false;
} }
}; };
export const isValidUserId = async (userId: string) => {
const user = await User.findById(userId);
if (user) {
return true;
} else {
return false;
}
};
import { model, Schema } from "mongoose"; import { model, Schema } from "mongoose";
interface IFile { export interface IFileInfo {
name: string; name: string;
path: string; url: string;
} }
const schema = new Schema<IFile>( const schema = new Schema<IFileInfo>(
{ {
name: { type: String }, name: { type: String },
path: { type: String }, url: { type: String },
}, },
{ timestamps: true, toJSON: { versionKey: false } } { timestamps: true, toJSON: { versionKey: false } }
); );
export default model<IFile>("File", schema); export default model<IFileInfo>("FileInfo", schema);
export { default as File } from "./file.model"; export { default as FileInfo, IFileInfo } from "./fileinfo.model";
export { default as Question, IQuestion } from "./question.model"; export { default as Question, IQuestion } from "./question.model";
export { default as Role } from "./role.model"; export { default as Role } from "./role.model";
export { default as Survey, ISurvey } from "./survey.model"; export { default as Survey, ISurvey } from "./survey.model";
......
...@@ -24,7 +24,7 @@ const schema = new Schema<IUser>( ...@@ -24,7 +24,7 @@ const schema = new Schema<IUser>(
name: { type: String }, name: { type: String },
password: { type: String, required: true, select: false }, password: { type: String, required: true, select: false },
role: { type: Schema.Types.ObjectId, ref: "Role" }, role: { type: Schema.Types.ObjectId, ref: "Role" },
avatar: { type: Schema.Types.ObjectId, ref: "File" }, avatar: { type: Schema.Types.ObjectId, ref: "FileInfo" },
}, },
{ {
toJSON: { toJSON: {
......
...@@ -6,7 +6,12 @@ const router = express.Router(); ...@@ -6,7 +6,12 @@ const router = express.Router();
router router
.route("/") .route("/")
.get(authCtrl.requireLogin, userCtrl.getUsers) .get(authCtrl.requireLogin, userCtrl.getUsers)
.post(authCtrl.requireLogin, fileCtrl.fileUpload, userCtrl.createUser); .post(
authCtrl.requireLogin,
authCtrl.hasRole("admin"),
fileCtrl.uploadAvatar,
userCtrl.createUser
);
router router
.route("/:userId") .route("/:userId")
......
import { Request } from "express";
import { Files } from "formidable";
export interface TypedRequest extends Request {
auth: any;
user: any;
files: Files;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment