Commit fc01d0b3 authored by Kim, MinGyu's avatar Kim, MinGyu
Browse files

db 생성

parent 58a76189
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
"webpack-dev-server": "^4.9.2" "webpack-dev-server": "^4.9.2"
}, },
"dependencies": { "dependencies": {
"axios": "^0.27.2",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router-dom": "^6.3.0" "react-router-dom": "^6.3.0"
......
import React from "react"; import React, { useState } from "react";
import Theme from "./theme";
import { PostType } from "./typesrc";
import axios from "axios";
function Title() {
const [title, setTitle] = useState<string>("질문종류");
function TitleChange(e: { target: { value: React.SetStateAction<string> } }) {
setTitle(e.target.value);
}
}
function Body() {
const [body, setBody] = useState<string>("질문종류");
function BodyChange(e: { target: { value: React.SetStateAction<string> } }) {
setBody(e.target.value);
}
}
function SelectCity() {
const [selectCity, setSelectCity] = useState<string>("질문종류");
function CityChange(e: { target: { value: React.SetStateAction<string> } }) {
setSelectCity(e.target.value);
}
return (
<select
id="Questions"
className="border border-3 border-black w-1/12"
onChange={CityChange}
defaultValue="질문종류"
>
<option value="질문종류">도시</option>
<option value="Seoul">서울</option>
<option value="Busan">부산</option>
<option value="Incheon">인천</option>
<option value="Daegoo">대구</option>
<option value="Kwangjoo">광주</option>
<option value="Daejeon">대전</option>
<option value="Woolsan">울산</option>
<option value="Sejong">세종</option>
<option value="Dokdo">독도</option>
<option value="Jeju">제주</option>
</select>
);
}
function SelectTheme() {
const [selectTheme, setSelectTheme] = useState<string>("질문종류");
function ThemeChange(e: { target: { value: React.SetStateAction<string> } }) {
setSelectTheme(e.target.value);
}
return (
<select
id="Questions"
className="border border-3 border-black w-1/12"
onChange={ThemeChange}
defaultValue="질문종류"
>
<option value="질문종류">테마</option>
<option value="cycling">사이클링</option>
<option value="surfing">서핑</option>
<option value="activity">액티비티</option>
<option value="camping">캠핑</option>
<option value="sking">스키</option>
<option value="boat">보트</option>
<option value="desert">사막</option>
<option value="golf">골프</option>
<option value="cave">동굴</option>
<option value="history">문화재</option>
<option value="zoo">동물원</option>
<option value="cycling">사이클링</option>
<option value="cycling">{selectTheme}</option>
</select>
);
}
// 눌렀다는 데이터가 어딘가에 있어야 한다. Map 객체를 이용해서 기타등등
// function postup() {
// axios.post("localhost:3000/api/post/up", {
// id: "a",
// title: title,
// body: body,
// date: `${() => new Date()}`,
// theme: selectTheme,
// city: selectCity,
// });
// }
export default function Posting() { export default function Posting() {
return( return (
<div className="flex flex-col border-3"> <div className="flex flex-col border-3">
<form className="w-full items-center" > <form className="w-full items-center">
<div className="flex flex-row relative"> <div className="flex flex-row relative">
<p className="basis-4/12 place-self-center">Id</p> <p className="basis-1/12 gap-x-8">Id</p>
<p className="basis-8/12 invisible">empty</p> <p className="basis-8/12 invisible">empty</p>
<SelectCity />
<SelectTheme />
<button data-dropdown-toggle="dropdownId"className="basis-1/12">Theme</button> <button
<p className="basis-1/12">city</p> type="submit"
<button className="basis-1/12 ">글쓰기</button> className="border border-black basis-1/12 gap-x-8"
>
글쓰기
</button>
</div> </div>
<div className="flex border-4"> <div className="flex border-4">
<textarea placeholder="title" className="w-full h-8"></textarea> <textarea
onChange={Title}
placeholder="title"
className="w-full h-8"
></textarea>
</div> </div>
<div className="flex border-2"> <div onChange={Body} className="flex border-2">
<textarea placeholder="body" className="w-full h-96"></textarea> <textarea placeholder="body" className="w-full h-96"></textarea>
</div> </div>
</form> </form>
......
...@@ -3,4 +3,6 @@ export interface PostType { ...@@ -3,4 +3,6 @@ export interface PostType {
title: string; title: string;
date: string; date: string;
counts: number; counts: number;
theme: string;
city: string;
} }
...@@ -4,7 +4,7 @@ import { PostType } from "./typesrc"; ...@@ -4,7 +4,7 @@ import { PostType } from "./typesrc";
import Post from "./post"; import Post from "./post";
function range(start: number, end: number) { function range(start: number, end: number) {
return (new Array(end - start + 1)).fill(undefined).map((_, i) => i + start); return new Array(end - start + 1).fill(undefined).map((_, i) => i + start);
} }
interface Posts { interface Posts {
...@@ -12,46 +12,94 @@ interface Posts { ...@@ -12,46 +12,94 @@ interface Posts {
} }
export const fakes = [ export const fakes = [
{ id: "a", title: '여행가고싶다...', date: '2022-06-30', counts: 0 }, {
{ id: "b", title: '바다!바다!바다!', date: '2022-08-01', counts: 0 }, id: "a",
{ id: "c", title: 'Jeju-island', date: '2022-9-10', counts: 0 }, title: "여행가고싶다...",
{ id: "d", title: '마! 부싼 가봤나!', date: '2022-9-22', counts: 0 }, date: "2022-06-30",
{ id: "e", title: 'Daegu', date: '2022-10-1', counts: 0 }, counts: 0,
{ id: "f", title: '강원도 감자는 맛있다.', date: '2022-12-12', counts: 0 }, theme: "surfing",
{ id: "g", title: '부산남자의 서울여행', date: '2022-12-25', counts: 0 } city: "seoul",
},
{
id: "b",
title: "바다!바다!바다!",
date: "2022-08-01",
counts: 0,
theme: "surfing",
city: "seoul",
},
{
id: "c",
title: "Jeju-island",
date: "2022-9-10",
counts: 0,
theme: "surfing",
city: "seoul",
},
{
id: "d",
title: "마! 부싼 가봤나!",
date: "2022-9-22",
counts: 0,
theme: "surfing",
city: "seoul",
},
{
id: "e",
title: "Daegu",
date: "2022-10-1",
counts: 0,
theme: "surfing",
city: "seoul",
},
{
id: "f",
title: "강원도 감자는 맛있다.",
date: "2022-12-12",
counts: 0,
theme: "surfing",
city: "seoul",
},
{
id: "g",
title: "부산남자의 서울여행",
date: "2022-12-25",
counts: 0,
theme: "surfing",
city: "seoul",
},
]; ];
export default function BoardPage() { export default function BoardPage() {
const [posts, setPosts] = useState<PostType[]>(fakes); const [posts, setPosts] = useState<PostType[]>(fakes);
const titleHandleClick = (event: MouseEvent<HTMLButtonElement>) => { const titleHandleClick = (event: MouseEvent<HTMLButtonElement>) => {
const postId = event.currentTarget.id const postId = event.currentTarget.id;
const newposts = [...posts] const newposts = [...posts];
newposts.forEach(post => { newposts.forEach((post) => {
if (post.id === postId) { if (post.id === postId) {
post.counts = post.counts + 1 post.counts = post.counts + 1;
return return;
}
})
setPosts(newposts)
} }
});
setPosts(newposts);
};
return ( return (
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<div className="flex flex-col items-center mt-6"> <div className="flex flex-col items-center mt-6">
<div> <div>`Travel Report's Board`</div>
`Travel Report's Board` <div>`여행지 후기를 남겨주세요!`</div>
</div>
<div>
`여행지 후기를 남겨주세요!`
</div>
</div> </div>
<div className="flex flex-col w-10/12 mt-16"> <div className="flex flex-col w-10/12 mt-16">
<div className="flex justify-end"> <div className="flex justify-end">
<div className="border-2 mb-2"><Link to="/posting"><button>글쓰기+</button></Link></div> {/* Link */} <div className="border-2 mb-2">
<Link to="/posting">
<button>글쓰기+</button>
</Link>
</div>{" "}
{/* Link */}
</div> </div>
<div className="sm:overflow-y-scroll"> <div className="sm:overflow-y-scroll">
<div className="flex flex-row divide-x-2 border-2 border-solid bg-gray-500 border-y-2 h-10 "> <div className="flex flex-row divide-x-2 border-2 border-solid bg-gray-500 border-y-2 h-10 ">
......
...@@ -14,6 +14,7 @@ export default function Header() { ...@@ -14,6 +14,7 @@ export default function Header() {
<div className="flex flex-row-reverse"> <div className="flex flex-row-reverse">
<button className="px-5 py-2 bg-teal-400 rounded"> <button className="px-5 py-2 bg-teal-400 rounded">
<Link to="/login" className="hover:bg-teal-100 focus:text-purple-500 ">Login</Link> <Link to="/login" className="hover:bg-teal-100 focus:text-purple-500 ">Login</Link>
</button> </button>
<button className="px-5 py-2 bg-purple-400 rounded"> <button className="px-5 py-2 bg-purple-400 rounded">
<Link to="/board" className="hover:bg-purple-300 focus:text-purple-500 ">Board</Link> <Link to="/board" className="hover:bg-purple-300 focus:text-purple-500 ">Board</Link>
......
import { Link, } from "react-router-dom"; import { Link } from "react-router-dom";
import React, { useState } from "react"; import React, { useState, FormEventHandler } from "react";
interface login { interface login {
id : string; id: string;
password : string; password: string;
} }
const fake = {id : "asdf", password : "qwer"} // const fake = { id: "asdf", password: "qwer" };
function Logindata(fake :login){ function Logindata() {
const [id, setId] = useState(""); const [id, setId] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
function login() {
return( <div className="flex flex-col md:w-2/3 md:gap-2"> fetch(`http://localhost:3000/api/auth/login`, {
method: "POST",
<input className="placeholder:text-slate-300
body: JSON.stringify({
email: `${id}`,
password: `${password}`,
}),
}).then((response) => {
console.log(response.json());
});
}
return (
<div className="flex flex-col md:w-2/3 md:gap-2">
<input
className="placeholder:text-slate-300
bg-white border border-slate-500 rounded-2xl bg-white border border-slate-500 rounded-2xl
py-2 pl-9 pr-3 py-2 pl-9 pr-3
focus:border-black focus:border-black
" placeholder="Id" type="text" name="Id" "
onChange={(e) => setId(e.target.value)} /> placeholder="Id"
<input className="placeholder:italic placeholder:text-slate-300 type="text"
name="Id"
onChange={(e) => setId(e.target.value)}
/>
<input
className="placeholder:italic placeholder:text-slate-300
bg-white border border-slate-500 rounded-2xl bg-white border border-slate-500 rounded-2xl
py-2 pl-9 pr-3 py-2 pl-9 pr-3
focus:border-black focus:border-black
" placeholder="Password" type="text" name="Password" "
onChange={(e) => setPassword(e.target.value)} /> placeholder="Password"
type="password"
name="Password"
onChange={(e) => setPassword(e.target.value)}
/>
<button
type="submit"
className="md:w-1/3 bg-sky-600 hover:bg-sky-700 rounded-xl"
onClick={login}
>
<Link to={"/"}>login</Link>
</button>
</div> </div>
);
)
} }
export default function Login() { export default function Login() {
return ( return (
<div> <div>
{/* <form onSubmit={loginsubmit}> */} {/* <form onSubmit={loginsubmit}> */}
<div className="flex flex-row grid grid-rows-2"> <div className="flex flex-row grid grid-rows-2">
<div className=" p-12 w-1/2 h-1/2 md:w-40 md:h-40 bg-red-400 place-self-center rounded-2xl"> <div className=" p-12 w-1/2 h-1/2 md:w-40 md:h-40 bg-red-400 place-self-center rounded-2xl">
<Link to="/">Travel Report</Link> <Link to="/">Travel Report</Link>
</div> </div>
<div className=" flex-row w-auto h-60 md:w-1/2 bg-white border-2 border-black grid place-items-center rounded-xl place-self-center"> <div className=" flex-row w-auto h-60 md:w-1/2 bg-white border-2 border-black grid place-items-center rounded-xl place-self-center">
<div className="flex flex-col w-full md:flex-row md:p-20 md:gap-10"> <div className="flex flex-col w-full md:flex-row md:p-20 md:gap-10">
<Logindata />
<Logindata id={""} password={""} />
<button type="submit" className="md:w-1/3 bg-sky-600 hover:bg-sky-700 rounded-xl">
login
</button>
</div> </div>
<div className="flex-row grid grid-cols-3"> <div className="flex-row grid grid-cols-3">
<button className="bg-white bottom-0 right-0"> <button className="bg-white bottom-0 right-0">
...@@ -65,8 +83,6 @@ export default function Login() { ...@@ -65,8 +83,6 @@ export default function Login() {
</button> </button>
</div> </div>
</div> </div>
</div> </div>
{/* </form> */} {/* </form> */}
</div> // Login Page </div> // Login Page
......
...@@ -6,5 +6,13 @@ const common = require("./webpack.common.js"); ...@@ -6,5 +6,13 @@ const common = require("./webpack.common.js");
module.exports = merge(common, { module.exports = merge(common, {
mode: "development", mode: "development",
devtool: "inline-source-map", devtool: "inline-source-map",
devServer: {historyApiFallback: true }, devServer: {
proxy : [
{
context : ["/api"],
target: "http://localhost:3000",
changeOrigin:true,
}
],
historyApiFallback: true },
}); });
...@@ -8,6 +8,8 @@ app.use(express.json()); ...@@ -8,6 +8,8 @@ app.use(express.json());
app.use(express.urlencoded({ extended: true })); app.use(express.urlencoded({ extended: true }));
app.use(cookieParser()); app.use(cookieParser());
app.get('/', (req, res) => res.send('Hello World! 안녕하세요'))
app.use("/api", router); app.use("/api", router);
app.use((err: any, req: Request, res: Response, next: NextFunction) => { app.use((err: any, req: Request, res: Response, next: NextFunction) => {
......
...@@ -25,15 +25,15 @@ export const login = asyncWrap(async (req, res) => { ...@@ -25,15 +25,15 @@ export const login = asyncWrap(async (req, res) => {
return res.status(401).send("잘못된 비밀번호를 입력하셨습니다"); return res.status(401).send("잘못된 비밀번호를 입력하셨습니다");
} }
// 3) 비밀번호가 맞으면 토큰 생성 // 3) 비밀번호가 맞으면 토큰 생성
const token = jwt.sign({ userId: user.id }, jwtCofig.secret, { const token = jwt.sign({ userId: user.id }, jwtCofig.secret, { //userId를 토큰에다 넣는 중.
expiresIn: jwtCofig.expires, expiresIn: jwtCofig.expires,
}); });
// 4) 토큰을 쿠키에 저장 // 4) 토큰을 쿠키에 저장
res.cookie(cookieConfig.name, token, { res.cookie(cookieConfig.name, token, {//token은 쿠키에 무엇을 실렸는가 이다. 항상 갖고 있다가 홈페이지 들어가면 서버로 접속
maxAge: cookieConfig.maxAge, maxAge: cookieConfig.maxAge,// 이 기간 한에서만 유효
path: "/", path: "/",//어떠한 경로에 관해서만 쓴다. 지금은 전부에 쓴다.
httpOnly: envConfig.mode === "production", httpOnly: envConfig.mode === "production", //false 면 브라우저에서 쿠키를 조작, true면 조작할 수 있다.
secure: envConfig.mode === "production", secure: envConfig.mode === "production", //true 면 https 를 통해서만 쿠키 전달, false면
}); });
// 5) 사용자 반환 // 5) 사용자 반환
res.json({ res.json({
...@@ -51,15 +51,15 @@ export const requireLogin = asyncWrap(async (reqExp, res, next) => { ...@@ -51,15 +51,15 @@ export const requireLogin = asyncWrap(async (reqExp, res, next) => {
const req = reqExp as TypedRequestAuth<string | JwtPayload>; const req = reqExp as TypedRequestAuth<string | JwtPayload>;
try { try {
// 1) 쿠키 토큰 존재 여부 확인 // 1) 쿠키 토큰 존재 여부 확인
const token = req.cookies[cookieConfig.name]; const token = req.cookies[cookieConfig.name]; //클라이언트 쪽에서 보낸 토큰을 받는중
if (!token) { if (!token) {
throw new Error("토큰이 존재하지 않습니다"); throw new Error("토큰이 존재하지 않습니다");
} }
// 2) 쿠키 유효성 검사 // 2) 쿠키 유효성 검사
const decodedUser = jwt.verify(token, jwtCofig.secret); const decodedUser = jwt.verify(token, jwtCofig.secret); // 아까보낸 토근을 디코딩중.
// 3) 요청 객체에 토큰 사용자 객체 추가 // 3) 요청 객체에 토큰 사용자 객체 추가
req.auth = decodedUser; req.auth = decodedUser;
next(); next();// 에러가 안나오면 next 사용, 나오면 catch쪽으로.
} catch (error) { } catch (error) {
res.clearCookie(cookieConfig.name); res.clearCookie(cookieConfig.name);
console.log("error in requreLogin===\n", error); console.log("error in requreLogin===\n", error);
......
export * as userCtrl from "./user.controller"; export * as userCtrl from "./user.controller";
export * as authCtrl from "./auth.controller"; export * as authCtrl from "./auth.controller";
export * as postCtrl from "./post.controller";
import { postDb } from "../db";
import { asyncWrap } from "../helpers/asyncWrap";
export const postup = asyncWrap(async (req, res) => {
const {id, title, date,body , theme, city }=req.body;
if (theme == "테마") {
return res.status(422).send("테마를 선택해주십시요.");
}else if(city =="도시"){
return res.status(422).send("도시를 선택해주십시요.");
}
const newPost = await postDb.createPost({
id, title, date, body,theme, city
});
res.json(newPost);
})
\ No newline at end of file
export * as userDb from "./user.db"; export * as userDb from "./user.db";
export * as postDb from "./post.db";
\ No newline at end of file
import { PostType, Post } from "../models";
export const createPost = async (post: PostType) => {
const newPost = await Post.create(post);
return newPost;
};
\ No newline at end of file
...@@ -5,6 +5,7 @@ import { mongoUri } from "./config"; ...@@ -5,6 +5,7 @@ import { mongoUri } from "./config";
connect(mongoUri) connect(mongoUri)
.then((mgs) => { .then((mgs) => {
console.log(`Mongoose is connected with version: ${mgs.version}`); console.log(`Mongoose is connected with version: ${mgs.version}`);
app.listen(3000, () => { app.listen(3000, () => {
console.log(`server is running on port ${3000}`); console.log(`server is running on port ${3000}`);
}); });
......
export { default as User, IUser } from "./user.model"; export { default as User, IUser } from "./user.model";
export { default as Post, PostType } from "./post.model";
import { model, Schema } from "mongoose";
export interface PostType {
id: string;
title: string;
date: Date;
body : string;
counts?: number;
theme: string;
city: string;
}
const schema = new Schema<PostType>({
id : {type: String},
title : { type: String },
date : {type: Date},
body : {type : String},
counts : {type: Number},
theme : {type: String},
city : {type: String},
});
export default model<PostType>("Post", schema);
...@@ -14,7 +14,7 @@ const validateEmail = (email: string) => { ...@@ -14,7 +14,7 @@ const validateEmail = (email: string) => {
const schema = new Schema<IUser>({ const schema = new Schema<IUser>({
email: { email: {
type: String, type: String,//mongoose type 인 String 으로 일반적인 string 과는 겉으로는 대문자 차이
rquired: true, rquired: true,
unique: true, unique: true,
validate: [validateEmail, "이메일을 입력해주세요"], validate: [validateEmail, "이메일을 입력해주세요"],
......
import express from "express"; import express from "express";
import userRouter from "./user.route"; import userRouter from "./user.route";
import authRouter from "./auth.route"; import authRouter from "./auth.route";
import postRouter from "./post.route";
const router = express.Router(); const router = express.Router();
router.use("/users", userRouter); router.use("/users", userRouter);
router.use("/auth", authRouter); router.use("/auth", authRouter);
export default router; export default router;
import express from "express";
import { postCtrl } from "../controllers";
const router = express.Router();
router.route("/").post(postCtrl.postup)
export default router
\ No newline at end of file
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