Flare-k

[Add] File & Home

......@@ -11,6 +11,8 @@ import flash from "express-flash";
import MongoStore from "connect-mongo";
import { localsMiddleware } from "./middlewares";
import routes from "./routes";
import globalRouter from "./routers/globalRouter";
import fileRouter from "./routers/fileRouter";
dotenv.config();
const app = express();
......@@ -35,9 +37,8 @@ app.use(
})
);
app.use(flash());
//app.use(passport.initialize());
//app.use(passport.session());
app.use(localsMiddleware);
app.use(routes.home, globalRouter);
app.use(routes.files, fileRouter);
export default app; // 파일을 불러올때 app object를 준다는 의미.
......
/* eslint-disable no-console */
import File from "../models/File";
export const home = async (req, res) => {
try {
const files = await File.find({}).sort({ _id: -1 }); // 모든 비디오를 가져온다.
res.render("home", { pageTitle: "Home", files }); // render DB에 저장된 video의 내용을 보여준다
} catch (error) {
console.log(error);
res.render("home", { pageTitle: "Home", files: [] });
}
};
export const search = async (req, res) => {
const {
query: { term: searchingBy },
} = req; // == const searchingBy = req.query.term;
let files = [];
try {
files = await File.find({
title: { $regex: searchingBy, $options: "i" }, // i를 옵션으로 추가하면 insensitive.. 대소문자 구분 안함.
});
} catch (error) {
console.log(error);
}
res.render("search", { pageTitle: "Search", searchingBy, files });
};
// upload 또한 upload를 준비하기 위한 get 페이지와 실제 데이터를 보내는 post 페이지가 필요하다.
export const getUpload = (req, res) =>
res.render("upload", { pageTitle: "Upload" });
export const postUpload = async (req, res) => {
// const {} 를 통해 body를 받아와 요청하는 정보들을 확인한다.
// 이는 pug와 db.js를 확인해야하는 듯 하다.
const {
body: { title, description },
file: { path }, // path로 할때는 로컬의 경로. S3는 location
} = req; // file에 path라는 요소가 있다.
const newVideo = await Video.create({
fileUrl: path,
title,
description,
creator: req.user.id,
// 여기있는 fileUrl, title, description은 videoDB의 속성이다.
});
// console.log(newVideo);
req.user.videos.push(newVideo.id); // user DB의 video atribute에 추가
req.user.save();
res.redirect(routes.videoDetail(newVideo.id)); // id는 DB의 id
// id는 mongoDB가 랜덤하게 만들어준다.
};
export const fileDetail = async (req, res) => {
// console.log(req.params); params에 id가 있다는걸 알게 됨
const {
params: { id },
} = req;
try {
const video = await Video.findById(id)
.populate("creator")
.populate("comments");
res.render("videoDetail", { pageTitle: video.title, video });
} catch (error) {
res.redirect(routes.home);
}
};
export const deleteFile = async (req, res) => {
const {
params: { id },
} = req;
try {
const video = await Video.findById(id);
// video를 받아서 render로 통해 템플릿으로 던져준다,
if (String(video.creator) !== req.user.id) {
throw Error();
} else {
await Video.findOneAndRemove({ _id: id });
}
} catch (error) {
console.log(error);
}
// 삭제를 실패하던 성공하던 home으로 redirect한다.
res.redirect(routes.home);
};
import dotenv from "dotenv";
import app from "./app"; // app.js에서 export default app했기 때문에 불러올 수 있다.
import "./db";
import "./models/File";
dotenv.config();
const PORT = process.env.PORT || 80;
......
......@@ -15,22 +15,8 @@ const s3 = new aws.S3({
export const localsMiddleware = (req, res, next) => {
res.locals.siteName = "my Storage";
res.locals.routes = routes;
res.locals.loggedUser = req.user || null;
// res.locals.loggedUser = req.user || null;
// console.log(req);
next();
};
export const onlyPublic = (req, res, next) => {
if (req.user) {
res.redirect(routes.home);
} else {
next();
}
};
export const onlyPrivate = (req, res, next) => {
if (req.user) {
next();
} else {
res.redirect(routes.home);
}
};
......
// DB 모델을 작성한다.
// File 자체를 DB에 저장하진 않을 것이다. 즉, byte를 저장하는 것이 아니라 file의 link를 저장한다.
import mongoose from "mongoose";
const FileSchema = new mongoose.Schema({
fileUrl: {
type: String,
required: "File URL is required", // url이 없으면 오류메시지 출력
},
title: {
type: String,
required: "Title is required",
},
createdAt: {
type: Date,
default: Date.now, // 현재 날짜를 반환하는 function
},
});
// 이제 이 스키마를 이용하여 model을 만들어준다.
// 모델의 이름은 "Video"
const model = mongoose.model("File", FileSchema);
export default model;
// 모델이 만들어짐을 알리기 위해 init.js에 import해준다.
import express from "express";
import routes from "../routes";
import {
getUpload,
postUpload,
fileDetail,
deleteFile,
} from "../controllers/homeController";
const fileRouter = express.Router();
// Upload
fileRouter.get(routes.upload, getUpload);
fileRouter.post(routes.upload, postUpload);
// File Detail
fileRouter.get(routes.fileDetail(), fileDetail);
// File Delete
fileRouter.get(routes.deleteFile(), deleteFile);
export default fileRouter;
import express from "express";
import routes from "../routes";
import {home, search} from "../controllers/homeController";
const globalRouter = express.Router();
globalRouter.get(routes.home, home);
globalRouter.get(routes.search, search);
export default globalRouter;
\ No newline at end of file
// Global
const HOME = "/";
const SEARCH = "/search";
// Files
const FILES = "/files";
const UPLOAD = "/upload";
const FILE_DETAIL = "/:id";
const DELETE_FILE = "/:id/delete";
const routes = {
home: HOME,
search: SEARCH,
files: FILES,
upload: UPLOAD,
fileDetail: (id) => {
if (id) {
return `/files/${id}`;
} else {
return FILE_DETAIL;
}
},
deleteFile: (id) => {
if (id) {
return `/files/${id}/delete`;
} else {
return DELETE_FILE;
}
},
};
// template에서 직접 접근이 필요한 경우 함수로 바꿔준다.
export default routes;
......
extends layouts/main
include mixins/fileBlock
block content
a(href=`/files${routes.upload}`) Upload
.home-files
each item in files
+fileBlock({
id: item.id,
title : item.title,
fileFile:item.fileUrl
})
\ No newline at end of file
//공통되는 코드가 필요한 경우div
include ../mixins/message
doctype html
html
head
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
title #{pageTitle} | #{siteName}
link(rel="stylesheet", href="/static/style.css")
body
if messages.error
+message({
type:'error',
text:messages.error
})
else if messages.info
+message({
type:'info',
text:messages.info
})
else if messages.success
+message({
type:'success',
text:messages.success
})
include ../partials/header
main
block content
include ../partials/footer
script(src="/static/main.js")
mixin fileBlock(file = {})
.fileBlock
a(href=routes.fileDetail(file.id))
h4.fileBlock__title=file.title
\ No newline at end of file
mixin message(message={})
.flash-message__container(class=message.type)
span.flash-message__text=message.text
footer.footer
.footer_icon
i.far.fa-file-alt
span.footer__text #{siteName} #{new Date().getFullYear()} &copy;
header.header
.header__wrapper
.header__column
a(href=routes.home)
i.far.fa-file-alt
.header__column
form(action=routes.search, method="get")
input(type="text", placeholder="Search by term...", name="term")
\ No newline at end of file
extends layouts/main
include mixins/videoBlock
block content
.search__header
h3 Searching for: #{searchingBy}
.search__videos
if videos.length === 0
h5 No Videos Found
each item in videos
+videoBlock({
title : item.title,
views: item.views,
videoFile:item.videoFile,
id: item.id
})
\ No newline at end of file
extends layouts/main
block content
.form-container
form(action=`/files${routes.upload}`, method="post", enctype="multipart/form-data")
div.fileUpload
label(for="file") File
input(type="file", id="file", name="file", required=true, accept = "file/*")
input(type="text", placeholder="Title", name="title", required=true)
input(type="submit", value="Upload File")
\ No newline at end of file