정소현

new file: app.js

	new file:   bin/www
	new file:   models/boardsSchema.js
	new file:   package.json
	new file:   public/images/noImage.jpg
	new file:   "public/images/\352\263\240\354\247\204\353\247\216\353\217\204\354\213\234\353\235\2751\355\216\270.jpg"
	new file:   "public/images/\352\263\240\354\266\224\354\260\270\354\271\230\354\202\274\352\260\201\352\271\200\353\260\245.jpg"
	new file:   "public/images/\353\215\224\355\201\260)\353\266\210\352\263\240\352\270\260\354\243\274\353\250\271\353\260\2451\355\216\270.jpg"
	new file:   "public/images/\353\215\224\355\201\260)\353\266\210\355\203\200\353\212\224\353\252\205\353\236\200\353\247\210\354\232\2241\355\216\270.jpg"
	new file:   "public/images/\353\221\220\355\210\274\355\225\234\353\223\261\354\213\254\353\217\210\352\260\200\354\212\244.jpg"
	new file:   "public/images/\353\247\245\354\225\244\354\271\230\354\246\210\355\225\240\353\235\274\355\224\274\353\207\250\354\203\214\353\223\2341\355\216\270.jpg"
	new file:   "public/images/\353\260\224\353\262\240\355\201\220\355\217\255\353\246\275\353\217\204\354\213\234\353\235\275.jpg"
	new file:   "public/images/\353\271\204\353\271\224\355\226\204\354\260\270\354\271\230\354\243\274\353\250\271\353\260\245.jpg"
	new file:   "public/images/\354\212\244\355\214\270\354\203\214\353\223\234\354\234\204\354\271\230.jpg"
	new file:   "public/images/\354\225\274\354\261\204\354\260\270\354\271\230\354\202\274\352\260\201\352\271\200\353\260\245.jpg"
	new file:   "public/images/\354\226\221\353\205\220\354\210\257\353\266\210\352\260\210\353\271\204\353\247\233.jpg"
	new file:   "public/images/\354\230\254\355\217\254\354\234\2401\355\216\270.jpg"
	new file:   "public/images/\354\260\270\354\271\230\352\271\200\354\271\230\353\263\266\354\235\214.jpg"
	new file:   "public/images/\354\271\230\354\246\210\352\260\220\355\212\200\354\203\214\353\223\234\354\234\204\354\271\230.jpg"
	new file:   "public/images/\355\206\265\354\203\210\354\232\260&\354\227\220\352\267\270\354\203\220\353\237\254\353\223\234\354\203\214\353\223\234.jpg"
	new file:   "public/images/\355\230\234\353\246\254)New11\354\260\254\353\217\204\354\213\234\353\235\275.jpg"
	new file:   "public/images/\355\230\234\353\246\254)\353\202\250\353\217\204\353\226\241\352\260\210\353\271\204\353\217\204\354\213\234\353\235\275.jpg"
	new file:   "public/images/\355\230\234\353\246\254)\354\255\210\352\276\270\353\257\270\353\266\210\352\263\240\352\270\260\353\271\204\353\271\224\353\260\245.jpg"
	new file:   public/stylesheets/style.css
	new file:   routes/contents.js
	new file:   routes/index.js
	new file:   views/.DS_Store
	new file:   views/board.ejs
	new file:   views/boardDetail.ejs
	new file:   views/error.ejs
1 +var express = require('express');
2 +var path = require('path');
3 +var favicon = require('serve-favicon');
4 +var logger = require('morgan');
5 +var cookieParser = require('cookie-parser');
6 +var bodyParser = require('body-parser');
7 +
8 +var mongoose = require('mongoose'); //**** mongodb를 연결하기 위함 ****/
9 +
10 +var routes = require('./routes/index'); // 기본 설정
11 +var boards = require('./routes/contents'); //**** board는 contents.js 파일로 연결하여 라우팅 ****/
12 +
13 +
14 +var app = express();
15 +
16 +//***** connect mongodb *****/
17 +mongoose.connect('mongodb://2014104145:pw@ds163301.mlab.com:63301/foodrank/food');
18 +
19 +var db = mongoose.connection;
20 +db.on('error', console.error.bind(console, 'connection error:'));
21 +db.once('open', function() {
22 + console.log("connected");
23 +});
24 +
25 +// view engine setup
26 +app.set('views', path.join(__dirname, 'views'));
27 +app.set('view engine', 'ejs');
28 +
29 +// uncomment after placing your favicon in /public
30 +//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
31 +app.use(logger('dev'));
32 +app.use(bodyParser.json());
33 +app.use(bodyParser.urlencoded({ extended: false }));
34 +app.use(cookieParser());
35 +app.use(express.static(path.join(__dirname, 'public')));
36 +
37 +app.use('/', routes);
38 +app.use('/boards', boards); //*** '/boards' 주소로 들어오면 var boards = require('./routes/contents');에서 설정한 주소로 넘어가게 됨 ***/
39 +
40 +// file upload multer
41 +//app.use(upload.array('UploadFile',10));
42 +
43 +// catch 404 and forward to error handler
44 +app.use(function(req, res, next) {
45 + var err = new Error('Not Found');
46 + err.status = 404;
47 + next(err);
48 +});
49 +
50 +
51 +// error handlers
52 +
53 +// development error handler
54 +// will print stacktrace
55 +if (app.get('env') === 'development') {
56 + app.use(function(err, req, res, next) {
57 + res.status(err.status || 500);
58 + res.render('error', {
59 + message: err.message,
60 + error: err
61 + });
62 + });
63 +}
64 +
65 +// production error handler
66 +// no stacktraces leaked to user
67 +app.use(function(err, req, res, next) {
68 + res.status(err.status || 500);
69 + res.render('error', {
70 + message: err.message,
71 + error: {}
72 + });
73 +});
74 +
75 +
76 +module.exports = app;
1 +#!/usr/bin/env node
2 +
3 +/**
4 + * Module dependencies.
5 + */
6 +
7 +var app = require('../app');
8 +var debug = require('debug')('foodrank:server');
9 +var http = require('http');
10 +
11 +/**
12 + * Get port from environment and store in Express.
13 + */
14 +
15 +var port = normalizePort(process.env.PORT || '3000');
16 +app.set('port', port);
17 +
18 +/**
19 + * Create HTTP server.
20 + */
21 +
22 +var server = http.createServer(app);
23 +
24 +/**
25 + * Listen on provided port, on all network interfaces.
26 + */
27 +
28 +server.listen(port);
29 +server.on('error', onError);
30 +server.on('listening', onListening);
31 +
32 +/**
33 + * Normalize a port into a number, string, or false.
34 + */
35 +
36 +function normalizePort(val) {
37 + var port = parseInt(val, 10);
38 +
39 + if (isNaN(port)) {
40 + // named pipe
41 + return val;
42 + }
43 +
44 + if (port >= 0) {
45 + // port number
46 + return port;
47 + }
48 +
49 + return false;
50 +}
51 +
52 +/**
53 + * Event listener for HTTP server "error" event.
54 + */
55 +
56 +function onError(error) {
57 + if (error.syscall !== 'listen') {
58 + throw error;
59 + }
60 +
61 + var bind = typeof port === 'string'
62 + ? 'Pipe ' + port
63 + : 'Port ' + port;
64 +
65 + // handle specific listen errors with friendly messages
66 + switch (error.code) {
67 + case 'EACCES':
68 + console.error(bind + ' requires elevated privileges');
69 + process.exit(1);
70 + break;
71 + case 'EADDRINUSE':
72 + console.error(bind + ' is already in use');
73 + process.exit(1);
74 + break;
75 + default:
76 + throw error;
77 + }
78 +}
79 +
80 +/**
81 + * Event listener for HTTP server "listening" event.
82 + */
83 +
84 +function onListening() {
85 + var addr = server.address();
86 + var bind = typeof addr === 'string'
87 + ? 'pipe ' + addr
88 + : 'port ' + addr.port;
89 + debug('Listening on ' + bind);
90 +}
1 +/*** 게시물 db 스키마 ***/
2 +
3 +
4 +var mongoose = require('mongoose');
5 +
6 +var boardSchema = mongoose.Schema({
7 + name: String,
8 + company: String,
9 + category: String,
10 + price: String,
11 + average:Number,
12 + comments: [{
13 + grade: Number,
14 + memo: String
15 + }]
16 +
17 +});
18 +
19 +module.exports = mongoose.model('BoardContents', boardSchema);
1 +{
2 + "name": "foodrank",
3 + "version": "0.0.0",
4 + "private": true,
5 + "scripts": {
6 + "start": "node ./bin/www"
7 + },
8 + "dependencies": {
9 + "body-parser": "~1.17.1",
10 + "cookie-parser": "~1.4.3",
11 + "debug": "~2.6.3",
12 + "ejs": "~2.5.6",
13 + "express": "~4.15.2",
14 + "mongoose": "^4.10.5",
15 + "morgan": "~1.8.1",
16 + "multer": "^1.3.0",
17 + "serve-favicon": "~2.4.2"
18 + }
19 +}
This diff is collapsed. Click to expand it.
1 +var express = require('express');
2 +var BoardContents = require('../models/boardsSchema'); //db를 사용하기 위한 변수
3 +var fs = require('fs');
4 +var router = express.Router();
5 +
6 +router.get('/', function(req,res){
7 + // 처음 index로 접속 했을시 나오는 부분
8 + // db에서 게시글 리스트 가져와서 출력
9 + // pagination 추가 -> 11/17
10 + // page는 1-5까지 보여줌 -> db에서 총 갯수 잡아와서 10으로 나눠서 올림해야함
11 + // 한페이지에 10개의 게시글: limit: 10, skip: (page-1)*10 이면 될 듯
12 + // page number는 param으로 받아오기 가장 처음엔 param 없으니까 그땐 자동 1로 설정
13 +
14 + var page = req.param('page');
15 + if(page == null) {page = 1;}
16 +
17 + var skipSize = (page-1)*10;
18 + var limitSize = 10;
19 + var pageNum = 1;
20 +
21 +
22 + BoardContents.count({},function(err, totalCount){
23 + // db에서 날짜 순으로 데이터들을 가져옴
24 + if(err) throw err;
25 +
26 + pageNum = Math.ceil(totalCount/limitSize);
27 + BoardContents.find({}).sort({average:-1}).skip(skipSize).limit(limitSize).exec(function(err, pageContents) {
28 + if(err) throw err;
29 + res.render('board', {title: "Board", page : page, contents: pageContents, pagination: pageNum, searchWord: ''});
30 + });
31 + });
32 +});
33 +
34 +router.get('/search', function(req, res){
35 + // 글 검색하는 부분
36 + var search_word = req.param('searchWord');
37 + var search_company = req.param('company');
38 + var search_category = req.param('category');
39 + var searchCondition = {$regex:''};
40 + var searchCompany = {$regex:''};
41 + var searchCategory = {$regex:''};
42 +
43 + if(search_word!='')
44 + searchCondition = {$regex:search_word};
45 + if(search_company!='all')
46 + searchCompany = {$regex:search_company};
47 + if(search_category!='all')
48 + searchCategory = {$regex:search_category};
49 +
50 + var page = req.param('page');
51 + if(page == null) {page = 1;}
52 + var skipSize = (page-1)*10;
53 + var limitSize = 10;
54 + var pageNum = 1;
55 +
56 +
57 + BoardContents.count({$and:[{name:searchCondition},{company:searchCompany},{category:searchCategory}]},function(err, searchCount){
58 + if(err) throw err;
59 + pageNum = Math.ceil(searchCount/limitSize);
60 +
61 + BoardContents.find({$and:[{name:searchCondition},{company:searchCompany},{category:searchCategory}]}).sort({average:-1}).skip(skipSize).limit(limitSize).exec(function(err, searchContents){
62 + if(err) throw err;
63 +
64 + res.render('board', {title: "Board", page : page,contents: searchContents, pagination: pageNum, searchWord: search_word});
65 + });
66 + });
67 +});
68 +
69 +
70 +router.post('/', function(req, res){
71 + //field name은 form의 input file의 name과 같아야함
72 + // 글 작성하고 submit하게 되면 저장이 되는 부분
73 + // 글 수정하고 submit하면 수정된 결과가 저장되는 부분
74 + var mode = req.param('mode');
75 +
76 + var addNewName = req.body.addContentName;
77 + var addNewCompany = req.body.addContentCompany;
78 + var addNewCategory = req.body.addContentCategory;
79 + var addNewPrice = req.body.addContentPrice;
80 +
81 + if(mode == 'add') {
82 + addBoard(addNewName, addNewCompany, addNewCategory, addNewPrice);
83 + res.redirect('/boards');
84 + }
85 +});
86 +
87 +router.post('/reply', function(req, res){
88 + // 댓글 다는 부분
89 + var reply_grade = req.body.replyGrade;
90 + var reply_comment= req.body.replyComment;
91 + var reply_id = req.body.replyId;
92 +
93 + addComment(reply_id, reply_grade, reply_comment,function(){
94 + res.redirect('/boards/view?id='+reply_id);
95 + });
96 +
97 +});
98 +
99 +
100 +router.get('/view', function(req, res){
101 + // 글 보는 부분. 글 내용을 출력하고 조회수를 늘려줘야함
102 + // 댓글 페이지 추가 해줌, 5개씩 출력함
103 +
104 + var contentId = req.param('id');
105 +
106 + BoardContents.findOne({_id:contentId}, function(err, rawContent){
107 + if(err) throw err;
108 +
109 + rawContent.save(function(err){
110 + if(err) throw err;
111 +
112 + res.render('boardDetail',{title: "Board", content:rawContent});
113 + });
114 + })
115 +});
116 +
117 +
118 +
119 +module.exports = router;
120 +
121 +function addComment(id, grade, comment,callback) {
122 + BoardContents.findOne({_id: id}, function(err, rawContent){
123 + if(err) throw err;
124 + var sum = 0;
125 + rawContent.comments.unshift({grade:grade, memo: comment});
126 + for(var j = 0;j<rawContent.comments.length;j++)
127 + {
128 + sum += rawContent.comments[j].grade;
129 + }
130 + rawContent.average = sum/rawContent.comments.length;
131 + rawContent.save(function(err){
132 + if(err) throw err;
133 + else callback();
134 + });
135 + });
136 +}
137 +function addBoard(name, company, category, price){
138 +
139 + var newBoardContents = new BoardContents;
140 + newBoardContents.name = name;
141 + newBoardContents.company = company;
142 + newBoardContents.category = category;
143 + newBoardContents.price = price;
144 + newBoardContents.average = 0;
145 +
146 + newBoardContents.save(function (err) {
147 + if (err) throw err;
148 + BoardContents.findOne({_id: newBoardContents._id}, {_id: 1}, function (err, newBoardId) {
149 + if (err) throw err;
150 + })
151 + });
152 + }
1 +var express = require('express');
2 +var router = express.Router();
3 +
4 +/* GET home page. */
5 +router.get('/', function(req, res, next) {
6 + res.render('index', { title: 'Express' });
7 +});
8 +
9 +module.exports = router;
No preview for this file type
1 +<!DOCTYPE html>
2 +<html>
3 +<head>
4 + <title><%= title %></title>
5 + <link rel='stylesheet' href='/stylesheets/style.css' />
6 + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
7 +
8 + <script>
9 + $(function(){ // pagination 현재 페이지 활성화 시킴
10 + var page = location.href.split("page=")[1]; // url에 page 넘버로 구분
11 + var index = page-1; // 0부터 시작이므로 1 빼줌
12 +
13 + if(page == null) { // 메인화면에서는 page 쿼리가 없으므로 빈값일 때
14 + $(".pagination a:eq(0)").attr('class', 'current-page');
15 + }
16 +
17 + $(".pagination a:eq(" + index + ")").attr('class', 'current-page');
18 + });
19 +
20 + function searchContent() {
21 + if($('#searchWord').val == ''){
22 + alert("검색어를 입력해주세요!!!");
23 + } else {
24 + $('#searchAction').submit();
25 + }
26 + }
27 + function submitContents() {
28 + var name = $('#addContentName').val();
29 + var company = $('#addContentCompany').val();
30 + var category = $('#addContentCategory').val();
31 + var price = $('#addContentPrice').val();
32 +
33 + // 새 글 등록 시
34 + if(name == '' || company == '' || category == '' || price == '') {
35 + alert("이름, 회사, 카테고리, 가격 모두 있어야합니다.");
36 + return;
37 + } else {
38 + $('#writeAction').submit();
39 + }
40 + }
41 + </script>
42 +</head>
43 +<body>
44 +<div class="main">
45 + <a href="/boards"><h2>게시판</h2></a>
46 + <table class="board_list">
47 + <tr>
48 + <th>Rank</th>
49 + <th>Name</th>
50 + <th>Company</th>
51 + <th>Category</th>
52 + <th>Price</th>
53 + </tr>
54 + <%if(contents.length>0){%>
55 + <%var i = 0;%>
56 + <%contents.forEach(function(item){%>
57 + <%i++;%>
58 + <tr>
59 + <td class="number"><%=(page-1)*10+i%></td>
60 + <td class="name"><a href="/boards/view?id=<%=item._id%>"><%=item.name%> [<%=item.comments.length%>]&nbsp;&nbsp;</a></td>
61 + <td class="company"><%=item.company%></td>
62 + <td class="category"><%=item.category%></td>
63 + <td class="average"><%=item.average%></td>
64 + </tr>
65 + <%})%>
66 + <%} else {%>
67 + <tr>
68 + <td colspan="5">게시물이 없습니다.</td>
69 + </tr>
70 + <%}%>
71 + </table>
72 +
73 + <div class="pagination">
74 + <%
75 + if(searchWord != '') {
76 + for(var i=1; i<=pagination; i++){
77 + %>
78 + <a href="/boards/search?searchWord=<%=searchWord%>&page=<%=i%>" class="next-page"><%=i%></a>
79 + <%
80 + }
81 + } else {
82 + for(var i=1; i<=pagination; i++){
83 + %>
84 + <a href="/boards?page=<%=i%>" class="next-page"><%=i%></a>
85 + <%}}%>
86 + </div>
87 +
88 + <div class="btn_group">
89 + <div class="search">
90 + <form action="/boards/search" method="get" id="searchAction" name="searchAction">
91 + <input type="text" class="search_word" id="searchWord" name="searchWord">
92 + <input type="radio" name="company" value="CU">CU</input>
93 + <input type="radio" name="company" value="GS25">GS25</input>
94 + <input type="radio" name="company" value="SevenEleven">SevenEleven</input>
95 + <input type="radio" name="company" value="all" style="visibility:hidden" checked="true"></input>
96 + <br>
97 + <input type="radio" name="category" value="주먹밥">주먹밥</input>
98 + <input type="radio" name="category" value="샌드위치">샌드위치</input>
99 + <input type="radio" name="category" value="도시락">도시락</input>
100 + <input type="radio" name="category" value="all" style="visibility:hidden" checked="true"></input>
101 + <a href="#" onclick="searchContent();"><div class="search_btn">검색</div></a>
102 + </form>
103 + </div>
104 + </div>
105 + <!-- new content write form-->
106 + <div class="write_form">
107 + <form id="writeAction" action="/boards?mode=add" method="post">
108 + <input type="text" class="inputName" id="addContentName" name="addContentName" placeholder="name">
109 + <input type="text" class="inputCompany" id="addContentCompany" name="addContentCompany" placeholder="company">
110 + <input type="text" class="inputCategory" id="addContentCategory" name="addContentCategory" placeholder="category">
111 + <input type="text" class="inputPrice" id="addContentPrice" name="addContentPrice" placeholder="price"></textarea>
112 +
113 + <div id = "new" class="addBtngroup">
114 + <a onclick="submitContents();"><div>SUBMIT</div></a>
115 + <a onclick="cancelWriteForm('cancel');"><div>CANCEL</div></a>
116 + </div>
117 + </form>
118 + </div>
119 + <!-- write form end-->
120 +
121 +</div>
122 +</body>
123 +</html>
1 +<!DOCTYPE html>
2 +<html>
3 +<head>
4 + <title><%=title%></title>
5 + <link rel='stylesheet' href='/stylesheets/style.css' />
6 +<body>
7 +<div class="main">
8 + <a href="/boards"><h2>게시판</h2></a>
9 + <div class="content_box">
10 + <!-- content box-->
11 + <div class="content_detail">
12 +
13 + <div class="content-pic"><img src='../images/<%=content.name%>.jpg' width="340" height="340" onError="this.src='../images/noImage.jpg';"></div>
14 + <div class="content-title"><%=content.name%></div>
15 + <div class="content-info">
16 + <%=content.company%> / <%=content.category%>
17 + </div>
18 + <div class="content-text">
19 + <%=content.price%>
20 + </div>
21 + <div class="addBtngroup" style="margin-left:450px;">
22 + <a href="/boards">확인</a>
23 + </div>
24 + </div>
25 + <!-- content box end -->
26 +
27 + <!-- 혁신의 끝을 달리는 옆에서 달아주는 댓글 창-->
28 + <div class="reply">
29 + <div class="reply_form">
30 + <form id="replyAction" action="/boards/reply" method="post">
31 + <div class="reply_grade">
32 + <SELECT size=1 class="replyGrade" id="replyGrade" name="replyGrade">
33 + <OPTION VALUE=1>1</OPTION>
34 + <OPTION VALUE=2>2</OPTION>
35 + <OPTION VALUE=3>3</OPTION>
36 + <OPTION VALUE=4>4</OPTION>
37 + <OPTION VALUE=5>5</OPTION>
38 + </SELECT></div>
39 + <div class="reply_comment">
40 + <textarea class="replyComment" id="replyComment" name="replyComment" rows="3" cols="30"></textarea>
41 + </div>
42 + <input type="hidden" name="replyId" id="replyId" value="<%=content._id%>">
43 + <button type="submit">댓글 작성</button>
44 + </form>
45 + </div>
46 + <div class="reply_list">
47 + <%if(content.comments.length>0){%>
48 + <%var commentsList = content.comments;%>
49 + <%for(var i=0; i<commentsList.length; i++){%>
50 + %>
51 + <div class="reply_content">
52 + <div class="reply_info"><%=commentsList[i].grade%> / <%=commentsList[i].memo%></div>
53 + </div>
54 + <%}%>
55 + <%} else {%>
56 + <div class="reply_content">
57 + <div class="reply_info">댓글이 없습니다</div>
58 + </div>
59 + <%}%>
60 + </div>
61 +
62 + </div>
63 + <!-- end -->
64 +
65 +</div>
66 +</body>
67 +</html>
1 +<h1><%= message %></h1>
2 +<h2><%= error.status %></h2>
3 +<pre><%= error.stack %></pre>