Flare-k

[Add] File & Home

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