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

db 생성

parent 58a76189
......@@ -29,6 +29,7 @@
"webpack-dev-server": "^4.9.2"
},
"dependencies": {
"axios": "^0.27.2",
"react": "^18.2.0",
"react-dom": "^18.2.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() {
return(
<div className="flex flex-col border-3">
<form className="w-full items-center" >
<div className="flex flex-row relative">
<p className="basis-4/12 place-self-center">Id</p>
<p className="basis-8/12 invisible">empty</p>
<button data-dropdown-toggle="dropdownId"className="basis-1/12">Theme</button>
<p className="basis-1/12">city</p>
<button className="basis-1/12 ">글쓰기</button>
</div>
<div className="flex border-4">
<textarea placeholder="title" className="w-full h-8"></textarea>
</div>
<div className="flex border-2">
<textarea placeholder="body" className="w-full h-96"></textarea>
</div>
</form>
return (
<div className="flex flex-col border-3">
<form className="w-full items-center">
<div className="flex flex-row relative">
<p className="basis-1/12 gap-x-8">Id</p>
<p className="basis-8/12 invisible">empty</p>
<SelectCity />
<SelectTheme />
<button
type="submit"
className="border border-black basis-1/12 gap-x-8"
>
글쓰기
</button>
</div>
<div className="flex border-4">
<textarea
onChange={Title}
placeholder="title"
className="w-full h-8"
></textarea>
</div>
<div onChange={Body} className="flex border-2">
<textarea placeholder="body" className="w-full h-96"></textarea>
</div>
);
}
\ No newline at end of file
</form>
</div>
);
}
export interface PostType {
id: string;
title: string;
date: string;
counts: number;
}
\ No newline at end of file
id: string;
title: string;
date: string;
counts: number;
theme: string;
city: string;
}
......@@ -4,68 +4,116 @@ import { PostType } from "./typesrc";
import Post from "./post";
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 {
posts: PostType[];
posts: PostType[];
}
export const fakes = [
{ id: "a", title: '여행가고싶다...', date: '2022-06-30', counts: 0 },
{ id: "b", title: '바다!바다!바다!', date: '2022-08-01', counts: 0 },
{ id: "c", title: 'Jeju-island', date: '2022-9-10', counts: 0 },
{ id: "d", title: '마! 부싼 가봤나!', date: '2022-9-22', counts: 0 },
{ id: "e", title: 'Daegu', date: '2022-10-1', counts: 0 },
{ id: "f", title: '강원도 감자는 맛있다.', date: '2022-12-12', counts: 0 },
{ id: "g", title: '부산남자의 서울여행', date: '2022-12-25', counts: 0 }
{
id: "a",
title: "여행가고싶다...",
date: "2022-06-30",
counts: 0,
theme: "surfing",
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() {
const [posts, setPosts] = useState<PostType[]>(fakes);
const [posts, setPosts] = useState<PostType[]>(fakes);
const titleHandleClick = (event: MouseEvent<HTMLButtonElement>) => {
const postId = event.currentTarget.id;
const newposts = [...posts];
newposts.forEach((post) => {
if (post.id === postId) {
post.counts = post.counts + 1;
return;
}
});
setPosts(newposts);
};
const titleHandleClick = (event: MouseEvent<HTMLButtonElement>) => {
const postId = event.currentTarget.id
const newposts = [...posts]
newposts.forEach(post => {
if (post.id === postId) {
post.counts = post.counts + 1
return
}
})
setPosts(newposts)
}
return (
<div className="flex flex-col items-center">
<div className="flex flex-col items-center mt-6">
<div>`Travel Report's Board`</div>
<div>`여행지 후기를 남겨주세요!`</div>
</div>
return (
<div className="flex flex-col items-center">
<div className="flex flex-col items-center mt-6">
<div>
`Travel Report's Board`
</div>
<div>
`여행지 후기를 남겨주세요!`
</div>
</div>
<div className="flex flex-col w-10/12 mt-16">
<div className="flex justify-end">
<div className="border-2 mb-2"><Link to="/posting"><button>글쓰기+</button></Link></div> {/* Link */}
</div>
<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="basis-full">Title</div>
<div className="basis-3/12">Date</div>
<div className="basis-2/12">Clicks</div>
</div>
<div>
{posts.map((post) => (
<Post key={post.id} post={post} handleClick={titleHandleClick} />
))}
</div>
</div>
</div>
<div className="flex flex-col w-10/12 mt-16">
<div className="flex justify-end">
<div className="border-2 mb-2">
<Link to="/posting">
<button>글쓰기+</button>
</Link>
</div>{" "}
{/* Link */}
</div>
);
}
\ No newline at end of file
<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="basis-full">Title</div>
<div className="basis-3/12">Date</div>
<div className="basis-2/12">Clicks</div>
</div>
<div>
{posts.map((post) => (
<Post key={post.id} post={post} handleClick={titleHandleClick} />
))}
</div>
</div>
</div>
</div>
);
}
......@@ -14,6 +14,7 @@ export default function Header() {
<div className="flex flex-row-reverse">
<button className="px-5 py-2 bg-teal-400 rounded">
<Link to="/login" className="hover:bg-teal-100 focus:text-purple-500 ">Login</Link>
</button>
<button className="px-5 py-2 bg-purple-400 rounded">
<Link to="/board" className="hover:bg-purple-300 focus:text-purple-500 ">Board</Link>
......
import { Link, } from "react-router-dom";
import React, { useState } from "react";
import { Link } from "react-router-dom";
import React, { useState, FormEventHandler } from "react";
interface login {
id : string;
password : string;
id: string;
password: string;
}
const fake = {id : "asdf", password : "qwer"}
function Logindata(fake :login){
const [id, setId] = useState("");
const [password, setPassword] = useState("");
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
py-2 pl-9 pr-3
focus:border-black
" placeholder="Id" 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
py-2 pl-9 pr-3
focus:border-black
" placeholder="Password" type="text" name="Password"
onChange={(e) => setPassword(e.target.value)} />
// const fake = { id: "asdf", password: "qwer" };
function Logindata() {
const [id, setId] = useState("");
const [password, setPassword] = useState("");
function login() {
fetch(`http://localhost:3000/api/auth/login`, {
method: "POST",
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
py-2 pl-9 pr-3
focus:border-black
"
placeholder="Id"
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
py-2 pl-9 pr-3
focus:border-black
"
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>
)
);
}
export default function Login() {
return (
<div>
{/* <form onSubmit={loginsubmit}> */}
<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">
<Link to="/">Travel Report</Link>
</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 flex-col w-full md:flex-row md:p-20 md:gap-10">
<Logindata id={""} password={""} />
<button type="submit" className="md:w-1/3 bg-sky-600 hover:bg-sky-700 rounded-xl">
login
</button>
</div>
<div className="flex-row grid grid-cols-3">
<button className="bg-white bottom-0 right-0">
<Link to="/signup">회원가입</Link>
</button>
<div></div>
<button className="bg-white inset-x-0">
<Link to="/forgot">비밀번호 찾기</Link>
</button>
</div>
</div>
</div>
{/* </form> */}
</div> // Login Page
);
}
\ No newline at end of file
return (
<div>
{/* <form onSubmit={loginsubmit}> */}
<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">
<Link to="/">Travel Report</Link>
</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 flex-col w-full md:flex-row md:p-20 md:gap-10">
<Logindata />
</div>
<div className="flex-row grid grid-cols-3">
<button className="bg-white bottom-0 right-0">
<Link to="/signup">회원가입</Link>
</button>
<div></div>
<button className="bg-white inset-x-0">
<Link to="/forgot">비밀번호 찾기</Link>
</button>
</div>
</div>
</div>
{/* </form> */}
</div> // Login Page
);
}
......@@ -6,5 +6,13 @@ const common = require("./webpack.common.js");
module.exports = merge(common, {
mode: "development",
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());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
app.get('/', (req, res) => res.send('Hello World! 안녕하세요'))
app.use("/api", router);
app.use((err: any, req: Request, res: Response, next: NextFunction) => {
......
......@@ -25,15 +25,15 @@ export const login = asyncWrap(async (req, res) => {
return res.status(401).send("잘못된 비밀번호를 입력하셨습니다");
}
// 3) 비밀번호가 맞으면 토큰 생성
const token = jwt.sign({ userId: user.id }, jwtCofig.secret, {
const token = jwt.sign({ userId: user.id }, jwtCofig.secret, { //userId를 토큰에다 넣는 중.
expiresIn: jwtCofig.expires,
});
// 4) 토큰을 쿠키에 저장
res.cookie(cookieConfig.name, token, {
maxAge: cookieConfig.maxAge,
path: "/",
httpOnly: envConfig.mode === "production",
secure: envConfig.mode === "production",
res.cookie(cookieConfig.name, token, {//token은 쿠키에 무엇을 실렸는가 이다. 항상 갖고 있다가 홈페이지 들어가면 서버로 접속
maxAge: cookieConfig.maxAge,// 이 기간 한에서만 유효
path: "/",//어떠한 경로에 관해서만 쓴다. 지금은 전부에 쓴다.
httpOnly: envConfig.mode === "production", //false 면 브라우저에서 쿠키를 조작, true면 조작할 수 있다.
secure: envConfig.mode === "production", //true 면 https 를 통해서만 쿠키 전달, false면
});
// 5) 사용자 반환
res.json({
......@@ -51,15 +51,15 @@ export const requireLogin = asyncWrap(async (reqExp, res, next) => {
const req = reqExp as TypedRequestAuth<string | JwtPayload>;
try {
// 1) 쿠키 토큰 존재 여부 확인
const token = req.cookies[cookieConfig.name];
const token = req.cookies[cookieConfig.name]; //클라이언트 쪽에서 보낸 토큰을 받는중
if (!token) {
throw new Error("토큰이 존재하지 않습니다");
}
// 2) 쿠키 유효성 검사
const decodedUser = jwt.verify(token, jwtCofig.secret);
const decodedUser = jwt.verify(token, jwtCofig.secret); // 아까보낸 토근을 디코딩중.
// 3) 요청 객체에 토큰 사용자 객체 추가
req.auth = decodedUser;
next();
next();// 에러가 안나오면 next 사용, 나오면 catch쪽으로.
} catch (error) {
res.clearCookie(cookieConfig.name);
console.log("error in requreLogin===\n", error);
......
export * as userCtrl from "./user.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 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";
connect(mongoUri)
.then((mgs) => {
console.log(`Mongoose is connected with version: ${mgs.version}`);
app.listen(3000, () => {
console.log(`server is running on port ${3000}`);
});
......
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) => {
const schema = new Schema<IUser>({
email: {
type: String,
type: String,//mongoose type 인 String 으로 일반적인 string 과는 겉으로는 대문자 차이
rquired: true,
unique: true,
validate: [validateEmail, "이메일을 입력해주세요"],
......
import express from "express";
import userRouter from "./user.route";
import authRouter from "./auth.route";
import postRouter from "./post.route";
const router = express.Router();
router.use("/users", userRouter);
router.use("/auth", authRouter);
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