From d1f8541e92d9c51ae26222a210baf1fff4e77601 Mon Sep 17 00:00:00 2001 From: "Kim, MinGyu" Date: Fri, 22 Jul 2022 16:42:00 +0900 Subject: [PATCH] =?UTF-8?q?admin=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- frontend/src/App.tsx | 13 +- frontend/src/apis/mainimg.api.ts | 16 +- frontend/src/auth/admin.tsx | 352 ++++++++++++++------------ frontend/src/auth/index.tsx | 3 +- frontend/src/auth/search.tsx | 12 + frontend/src/home/header.tsx | 12 +- frontend/src/types/index.tsx | 5 +- src/app.ts | 1 + src/controllers/mainimg.controller.ts | 68 +++-- src/controllers/user.controller.ts | 2 +- src/db/mainimg.db.ts | 20 +- src/db/user.db.ts | 6 +- src/models/mainimg.model.ts | 36 ++- 14 files changed, 309 insertions(+), 240 deletions(-) create mode 100644 frontend/src/auth/search.tsx diff --git a/.gitignore b/.gitignore index d810139..bf0775b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules/ .vscode/ package-lock.json dist/ -uploads/ \ No newline at end of file +uploads/ +adminpics \ No newline at end of file diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index ced8e42..887c7a3 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -2,7 +2,15 @@ import React from "react"; import { BrowserRouter, Route, Routes } from "react-router-dom"; import "tailwindcss/tailwind.css"; import { IntoPost } from "./post/intopost"; -import { Login, Profile, RequireAuth, Signup, Admin, ImgRewrite } from "./auth"; +import { + Login, + Profile, + RequireAuth, + Signup, + Admin, + ImgRewrite, + Search, +} from "./auth"; import { Header, Body } from "./home"; import { Board } from "./board"; import Posting from "./post/posting"; @@ -39,7 +47,8 @@ export const App = () => { } /> } /> - }/> + } /> + } /> diff --git a/frontend/src/apis/mainimg.api.ts b/frontend/src/apis/mainimg.api.ts index 3a7679e..1debcd8 100644 --- a/frontend/src/apis/mainimg.api.ts +++ b/frontend/src/apis/mainimg.api.ts @@ -2,17 +2,17 @@ import axios from "axios"; import { MainimgType } from "../types"; import baseUrl from "./baseUrl"; -export const mainimg = async (mainimg: MainimgType) => { - const { data } = await axios.post(`${baseUrl}/mainimg`, mainimg); - return data; +export const mainimg = async (formdata: FormData) => { + const { data } = await axios.post(`${baseUrl}/mainimg`, formdata); + return data; }; -export const delmainimg = async (_id : string) => { - const { data } = await axios.delete(`${baseUrl}/mainimg/${_id}`); - return data; +export const delmainimg = async (_id: string) => { + const { data } = await axios.delete(`${baseUrl}/mainimg/${_id}`); + return data; }; export const getmainimg = async () => { - const { data } = await axios.get(`${baseUrl}/mainimg`); - return data; + const { data } = await axios.get(`${baseUrl}/mainimg`); + return data; }; diff --git a/frontend/src/auth/admin.tsx b/frontend/src/auth/admin.tsx index efa323e..b138153 100644 --- a/frontend/src/auth/admin.tsx +++ b/frontend/src/auth/admin.tsx @@ -1,190 +1,206 @@ import React, { FormEvent, useEffect, useState, MouseEvent } from "react"; import { Link } from "react-router-dom"; import { mainimgApi } from "../apis"; +import { picture } from "../apis/profile.api"; import { catchErrors } from "../helpers"; import { MainimgType } from "../types"; import { MySlide } from "./adminslide"; export default function Admin() { - // 이미지 전체 불러오기 - const [getimgs, setGetimgs] = useState([]); + // 이미지 전체 불러오기 + const [getimgs, setGetimgs] = useState([]); - async function imgsData() { - const imgs = await mainimgApi.getmainimg(); - setGetimgs(imgs) - }; + async function imgsData() { + const imgs = await mainimgApi.getmainimg(); + setGetimgs(imgs); + } - useEffect(() => { - imgsData(); - }, []); + useEffect(() => { + imgsData(); + }, []); + console.log(getimgs); + // 이미지 추가하기 + const [addimg, setAddimg] = useState({ + _id: "", + theme: "", + city: "", + title: "", + pic: { originalfilename: "", newfilename: "" }, + }); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); + const [addSuccess, setAddSuccess] = useState(false); + const [delSuccess, setDelSuccess] = useState(false); + const [file, setFile] = useState(); - // 이미지 추가하기 - const [addimg, setAddimg] = useState({ - _id: "", - theme: "", - city: "", - url: "", - title: "", - }); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(""); - const [addSuccess, setAddSuccess] = useState(false); - const [delSuccess, setDelSuccess] = useState(false); + function handleSelectChange(event: React.ChangeEvent) { + const { name, value } = event.currentTarget; + console.log(value); + setAddimg({ ...addimg, [name]: value }); + } - function handleSelectChange(event: React.ChangeEvent) { - const { name, value } = event.currentTarget; - setAddimg({ ...addimg, [name]: value }); - } - function handleInputeChange(event: React.ChangeEvent) { - const { name, value } = event.currentTarget; - setAddimg({ ...addimg, [name]: value }); + function handleInputeChange(event: React.ChangeEvent) { + const { name, value } = event.currentTarget; + setAddimg({ ...addimg, [name]: value }); + } + function handleFileChange(e: React.ChangeEvent) { + const file = e.target.files?.[0]; + if (!(file === undefined)) { + setFile(file); } + } - async function handleSubmit(event: FormEvent) { - event.preventDefault(); - try { - setError(""); - console.log("img data", addimg); - setLoading(true); - const res = await mainimgApi.mainimg(addimg); - console.log("서버연결됬나요", res); - setAddSuccess(true); - setError(""); - } catch (error) { - console.log("에러발생"); - catchErrors(error, setError); - } finally { - setLoading(false); - } - } + async function handleSubmit(event: FormEvent) { + event.preventDefault(); - if (addSuccess) { - alert("img 추가되었습니다"); + const formdata = new FormData(); + console.log(addimg); + formdata.append("city", addimg.city); + formdata.append("theme", addimg.theme); + formdata.append("title", addimg.title); + if (!(file === undefined)) { + formdata.append("mainimg", file); + console.log(formdata); + const res = await mainimgApi.mainimg(formdata); + console.log("확인 중 ", res); } - // 이미지 삭제하기 - async function handleDeleteClick(event: MouseEvent) { - try { - if (confirm("삭제하시겠습니까?") == true) { - const picId = event.currentTarget.id; - console.log("picId : ", picId) - const res = await mainimgApi.delmainimg(picId); - console.log("delete img", res); - setDelSuccess(true); - setError(""); - } else { - return false; - } - } - catch (error) { - console.log("에러발생"); - catchErrors(error, setError); - } finally { - setLoading(false); - }; - }; - if (delSuccess) { - alert("img 삭제되었습니다"); - } - - let limit = 15; - const numPages = Math.ceil(getimgs.length / 15); + } - const slides = [] - for (let i = 0; i < numPages; i++) { - const k = [ - getimgs.slice(i * limit, i * limit + limit).map((pic, index: number) => ( -
-
- -

{pic.title}

-
-
- - -
-
- ))] - slides.push(k); + if (addSuccess) { + alert("img 추가되었습니다"); + } + // 이미지 삭제하기 + async function handleDeleteClick(event: MouseEvent) { + try { + if (confirm("삭제하시겠습니까?") == true) { + const picId = event.currentTarget.id; + console.log("picId : ", picId); + const res = await mainimgApi.delmainimg(picId); + console.log("delete img", res); + setDelSuccess(true); + setError(""); + } else { + return false; + } + } catch (error) { + console.log("에러발생"); + catchErrors(error, setError); + } finally { + setLoading(false); } + } + if (delSuccess) { + alert("img 삭제되었습니다"); + } - return ( -
-
-
-
- - -
-

url :

- - {/* type="file"/> */} -
-
-

title :

- -
-
-
- -
-
-
-
- + let limit = 15; + const numPages = Math.ceil(getimgs.length / 15); + const slides = []; + for (let i = 0; i < numPages; i++) { + const k = [ + getimgs + .slice(i * limit, i * limit + limit) + .map((picture, index: number) => ( +
+
+ +

{picture.title}

+
+
+ + +
+
+ )), + ]; + slides.push(k); + } + + return ( +
+
+
+
+ + +
+ + +
+
+

title :

+
+
+
+ +
- ); -}; +
+
+ +
+
+ ); +} diff --git a/frontend/src/auth/index.tsx b/frontend/src/auth/index.tsx index 9cb287a..a69d6e8 100644 --- a/frontend/src/auth/index.tsx +++ b/frontend/src/auth/index.tsx @@ -3,4 +3,5 @@ export { default as Signup } from "./signup"; export { default as Profile } from "./profile"; export { RequireAuth } from "./RequireAuth"; export { default as Admin } from "./admin"; -export {default as ImgRewrite} from "./imgrewrite" +export { default as ImgRewrite } from "./imgrewrite"; +export { default as Search } from "./search"; diff --git a/frontend/src/auth/search.tsx b/frontend/src/auth/search.tsx new file mode 100644 index 0000000..2a53bae --- /dev/null +++ b/frontend/src/auth/search.tsx @@ -0,0 +1,12 @@ +import React from "react"; +import { useLocation } from "react-router-dom"; + +export default function Search() { + const a = useLocation().state; + + return ( +
+
+
+ ); +} diff --git a/frontend/src/home/header.tsx b/frontend/src/home/header.tsx index 0b44993..3cc75f1 100644 --- a/frontend/src/home/header.tsx +++ b/frontend/src/home/header.tsx @@ -6,6 +6,13 @@ import "tailwindcss/tailwind.css"; export default function Header() { const { logout } = useAuth(); + const [search, setSearch] = useState(""); + + const handleChange = (e: React.ChangeEvent) => { + const newvalue = e.target.value; + setSearch(newvalue); + }; + return (
@@ -18,9 +25,12 @@ export default function Header() {
diff --git a/frontend/src/types/index.tsx b/frontend/src/types/index.tsx index 0047911..c95f450 100644 --- a/frontend/src/types/index.tsx +++ b/frontend/src/types/index.tsx @@ -43,6 +43,9 @@ export interface MainimgType { _id: string; theme: string; city: string; - url: string; title: string; + pic: { + originalfilename: string; + newfilename: string; + }; } diff --git a/src/app.ts b/src/app.ts index b1c55bf..365b117 100644 --- a/src/app.ts +++ b/src/app.ts @@ -12,6 +12,7 @@ app.use(cookieParser()); app.use("/api", router); app.use("/images", express.static(path.join(__dirname, "..", "/uploads"))); +app.use("/images", express.static(path.join(__dirname, "..", "/adminpics"))); app.use((err: any, req: Request, res: Response, next: NextFunction) => { console.log("익스프레스 에러: ", err); diff --git a/src/controllers/mainimg.controller.ts b/src/controllers/mainimg.controller.ts index edb21d3..83836e0 100644 --- a/src/controllers/mainimg.controller.ts +++ b/src/controllers/mainimg.controller.ts @@ -4,35 +4,53 @@ import { TypedRequestAuth } from "./auth.controller"; import { asyncWrap } from "../helpers"; import { mainimgDb } from "../db"; import { TypedRequest } from "../types"; +import { ObjectId } from "mongoose"; +import formidable from "formidable"; -export const createMainimg = asyncWrap(async (reqExp, res, next) => { - const req = reqExp as TypedRequestAuth<{ userId: string }>; +export const createMainimg = asyncWrap(async (reqExp, res) => { + const req = reqExp as TypedRequestAuth<{ userId: ObjectId }>; + const { userId } = req.auth; - const { theme, city, url, title } = req.body as { - theme: string; - city: string; - url: string; - title: string; - }; - - console.log("body", req.body); - - if (!isLength(url ?? "", { min: 1 })) { - return res.status(422).send("이미지 url을 입력해주세요"); - } + const form = formidable({ + uploadDir: "adminpics", + keepExtensions: true, + multiples: false, + }); - if (!isLength(title ?? "", { min: 1 })) { - return res.status(422).send("이미지 제목을 입력해주세요"); - } + form.parse(req, (err, fields, files) => { + if (!Array.isArray(files.mainimg)) { + //파일 좁히기 중 + if ( + !( + Array.isArray(fields.city) || + Array.isArray(fields.title) || + Array.isArray(fields.theme) + ) + ) { + const city = fields.city; + const title = fields.title; + const theme = fields.theme; - const newMainimg = await mainimgDb.createMainimg({ - theme, - city, - url, - title, + // if (!isLength(title ?? "", { min: 1 })) { + // return res.status(422).send("이미지 제목을 입력해주세요"); + // } + console.log(files); + const originalfilename = files.mainimg?.originalFilename; + const newfilename = files.mainimg.newFilename; + if (!(originalfilename === null || newfilename === undefined)) { + mainimgDb.createMainimg( + { city, title, theme }, + { + originalfilename, + newfilename, + } + ); + } + } + } }); - return res.json(newMainimg); + res.json(); }); export const getMainimg = asyncWrap(async (req, res) => { @@ -40,7 +58,6 @@ export const getMainimg = asyncWrap(async (req, res) => { return res.json(mainimgs); }); - export const deleteMainimg = asyncWrap(async (req, res) => { const { imgId } = req.params; console.log(imgId); @@ -48,6 +65,3 @@ export const deleteMainimg = asyncWrap(async (req, res) => { return res.json(deleteCount); }); - - - diff --git a/src/controllers/user.controller.ts b/src/controllers/user.controller.ts index 070b6e2..cc157cb 100644 --- a/src/controllers/user.controller.ts +++ b/src/controllers/user.controller.ts @@ -1,7 +1,7 @@ import { userDb } from "../db"; import { asyncWrap } from "../helpers/asyncWrap"; import { Request } from "express"; -import formidable, { Fields, Files } from "formidable"; +import formidable from "formidable"; import { ObjectId } from "mongoose"; import fs from "fs"; diff --git a/src/db/mainimg.db.ts b/src/db/mainimg.db.ts index 924b3d0..6da5569 100644 --- a/src/db/mainimg.db.ts +++ b/src/db/mainimg.db.ts @@ -1,19 +1,27 @@ -import { Mainimg, MainimgType } from "../models"; +import { ObjectId } from "mongoose"; +import { Avatar, IAvatar, Mainimg, MainimgType } from "../models"; + +export const createMainimg = async (mainimg: MainimgType, pic: IAvatar) => { + const newPic = await Avatar.create({ + originalfilename: pic.originalfilename, + newfilename: pic.newfilename, + pictureauth: pic.picturepath, + }); -export const createMainimg = async (mainimg: MainimgType) => { const newMainimg = await Mainimg.create({ theme: mainimg.theme, city: mainimg.city, - url: mainimg.url, + pic: newPic._id, title: mainimg.title, }); return newMainimg; }; export const getMainimg = async () => { - const users = await Mainimg.find({}); - return users; - }; + const img = await Mainimg.find({}).populate("pic"); + + return img; +}; export const deleteOneMainimg = async (_id: string) => { const res = await Mainimg.deleteOne({ _id: _id }); diff --git a/src/db/user.db.ts b/src/db/user.db.ts index f05c955..e4c1c55 100644 --- a/src/db/user.db.ts +++ b/src/db/user.db.ts @@ -1,7 +1,7 @@ import bcrypt from "bcryptjs"; import { ObjectId } from "mongoose"; import { IUser, Role, Post, User, Avatar } from "../models"; -import fs from "fs"; +import fs from "fs/promises"; export const createUser = async (user: IUser) => { // 비밀번호 암호화 @@ -106,9 +106,7 @@ export const deleteUser = async (userId: ObjectId) => { const user = await User.findById(userId); if (!(user?.avatar === undefined)) { const ref = await Avatar.findById(user.avatar._id); - fs.unlink("../travel/uploads/" + ref?.newfilename, (err) => { - console.log(err); - }); + await fs.unlink("../travel/uploads/" + ref?.newfilename); await Avatar.deleteOne({ _id: user.avatar._id }); await User.deleteOne({ _id: userId }); } diff --git a/src/models/mainimg.model.ts b/src/models/mainimg.model.ts index 70b1e4d..da24530 100644 --- a/src/models/mainimg.model.ts +++ b/src/models/mainimg.model.ts @@ -1,28 +1,24 @@ -import {model, Schema } from "mongoose"; +import { model, Schema, Types } from "mongoose"; export interface MainimgType { - - theme: string; - city: string; - url: string; - title: string; + theme: string; + city: string; + title: string; + pic?: Types.ObjectId; } const MainimgSchema = new Schema({ - theme: { - type: String, - }, - city: { - type: String, - }, - url : { - type: String, - }, - title: { - type: String, - required: true, - }, - + theme: { + type: String, + }, + city: { + type: String, + }, + title: { + type: String, + required: true, + }, + pic: { type: Schema.Types.ObjectId, ref: "Avatar" }, }); export default model("Mainimg", MainimgSchema); -- GitLab