이승윤

Merge branch 'feat/Video' into 'develop'

Feat/video



See merge request !6
...@@ -28,7 +28,7 @@ var categori = require('./routes/categori'); ...@@ -28,7 +28,7 @@ var categori = require('./routes/categori');
28 var accounts = require('./routes/accounts'); 28 var accounts = require('./routes/accounts');
29 var auth = require('./routes/auth'); 29 var auth = require('./routes/auth');
30 var connectMongo = require('connect-mongo'); 30 var connectMongo = require('connect-mongo');
31 -var Search = require('./routes/Search'); 31 +var Video = require('./routes/Videos');
32 var MongoStore = connectMongo(session); 32 var MongoStore = connectMongo(session);
33 33
34 app.set('views', path.join(__dirname, 'views')); 34 app.set('views', path.join(__dirname, 'views'));
...@@ -68,7 +68,7 @@ app.use(function (req, res, next) { ...@@ -68,7 +68,7 @@ app.use(function (req, res, next) {
68 }); 68 });
69 69
70 //routes add 70 //routes add
71 -app.use('/', Search); 71 +app.use('/', Video);
72 app.use('/categori', categori); 72 app.use('/categori', categori);
73 app.use('/accounts', accounts); 73 app.use('/accounts', accounts);
74 app.use('/auth', auth); 74 app.use('/auth', auth);
......
1 -var mongoose = require('mongoose');
2 -var Schema = mongoose.Schema;
3 -
4 -//생성될 필드명을 정한다.
5 -var ProductsSchema = new Schema({
6 - name: {
7 - //제품명
8 - type: String,
9 - required: [true, '제목은 입력해주세요'],
10 - },
11 - thumbnail: String, //이미지 파일명
12 - price: Number, //가격
13 - description: String, //설명
14 - created_at: {
15 - //작성일
16 - type: Date,
17 - default: Date.now(),
18 - },
19 - username: String, //작성자추가
20 -});
21 -
22 -ProductsSchema.virtual('getDate').get(function () {
23 - var date = new Date(this.created_at);
24 - return {
25 - year: date.getFullYear(),
26 - month: date.getMonth() + 1,
27 - day: date.getDate(),
28 - };
29 -});
30 -
31 -// 1씩 증가하는 primary Key를 만든다
32 -// model : 생성할 document 이름
33 -// field : primary key , startAt : 1부터 시작
34 -
35 -module.exports = mongoose.model('products', ProductsSchema);
...\ No newline at end of file ...\ No newline at end of file
1 var mongoose = require('mongoose'); 1 var mongoose = require('mongoose');
2 var Schema = mongoose.Schema; 2 var Schema = mongoose.Schema;
3 var VideoSchema = new Schema({ 3 var VideoSchema = new Schema({
4 - username: { 4 + categori: String,
5 - type: String, 5 + id: Number,
6 - required: [true, '아이디는 필수입니다.'], 6 + title: String,
7 - }, 7 + video_id: String,
8 - password: { 8 + urls: String,
9 - type: String,
10 - required: [true, '패스워드는 필수입니다.'],
11 - },
12 - displayname: String,
13 - created_at: {
14 - type: Date,
15 - default: Date.now(),
16 - },
17 }); 9 });
18 10
19 module.exports = mongoose.model('videos', VideoSchema); 11 module.exports = mongoose.model('videos', VideoSchema);
......
...@@ -9,7 +9,7 @@ var limit = 10; // 출력 갯수 ...@@ -9,7 +9,7 @@ var limit = 10; // 출력 갯수
9 var video = []; 9 var video = [];
10 var test = 'test'; 10 var test = 'test';
11 var count = 0; 11 var count = 0;
12 -youtube.setKey('AIzaSyAsKr_oWGZIBbL5tLdIl98Lf9Pzqj8jX4o'); // API 키 입력 12 +youtube.setKey('AIzaSyCAaeW1qMSInEdN1OzU20FZlToIZYkb1bc'); // API 키 입력
13 youtube.addParam('order', 'rating'); // 평점 순으로 정렬 13 youtube.addParam('order', 'rating'); // 평점 순으로 정렬
14 youtube.addParam('type', 'video'); // 타입 지정 14 youtube.addParam('type', 'video'); // 타입 지정
15 youtube.addParam('videoLicense', 'creativeCommon'); // 크리에이티브 커먼즈 아이템만 불러옴 15 youtube.addParam('videoLicense', 'creativeCommon'); // 크리에이티브 커먼즈 아이템만 불러옴
...@@ -19,9 +19,7 @@ youtube.search(word, limit, function (err, result) { ...@@ -19,9 +19,7 @@ youtube.search(word, limit, function (err, result) {
19 if (err) { 19 if (err) {
20 console.log(err); 20 console.log(err);
21 } // 에러일 경우 에러공지하고 빠져나감 21 } // 에러일 경우 에러공지하고 빠져나감
22 -
23 //console.log(JSON.stringify(result, null, 2)); // 받아온 전체 리스트 출력 22 //console.log(JSON.stringify(result, null, 2)); // 받아온 전체 리스트 출력
24 -
25 var items = result['items']; // 결과 중 items 항목만 가져옴 23 var items = result['items']; // 결과 중 items 항목만 가져옴
26 for (var i in items) { 24 for (var i in items) {
27 var it = items[i]; 25 var it = items[i];
......
1 -var Youtube = require('youtube-node');
2 -var youtube = new Youtube();
3 -
4 var express = require('express'); 1 var express = require('express');
2 +var CategoriModel = require('../models/CategoriModel');
3 +var VideoModel = require('../models/VideoModel');
5 var router = express.Router(); 4 var router = express.Router();
6 5
7 -var word = '백종원'; // 검색어 지정
8 -var limit = 10; // 출력 갯수
9 -var video = [];
10 -var test = 'test';
11 -var count = 0;
12 -youtube.setKey('AIzaSyAsKr_oWGZIBbL5tLdIl98Lf9Pzqj8jX4o'); // API 키 입력
13 -
14 -youtube.addParam('order', 'rating'); // 평점 순으로 정렬
15 -youtube.addParam('type', 'video'); // 타입 지정
16 -youtube.addParam('videoLicense', 'creativeCommon'); // 크리에이티브 커먼즈 아이템만 불러옴
17 -
18 -youtube.search(word, limit, function (err, result) {
19 - // 검색 실행
20 - if (err) {
21 - console.log(err);
22 - } // 에러일 경우 에러공지하고 빠져나감
23 -
24 - //console.log(JSON.stringify(result, null, 2)); // 받아온 전체 리스트 출력
25 -
26 - var items = result['items']; // 결과 중 items 항목만 가져옴
27 - for (var i in items) {
28 - var it = items[i];
29 - for (var j in it) {
30 - if (it[j]['title'] != null) {
31 - var title = it[j]['title'];
32 - }
33 - if (it[j]['videoId'] != null) {
34 - var video_id = it[j]['videoId'];
35 - }
36 - var urls = 'https://www.youtube.com/watch?v=' + video_id;
37 - }
38 - var item = {
39 - id: count,
40 - title: title,
41 - video_id: video_id,
42 - urls: urls,
43 - };
44 - count++;
45 - video.push(item);
46 - }
47 -});
48 -
49 router.get('/', function (req, res) { 6 router.get('/', function (req, res) {
50 - res.render( 7 + CategoriModel.find(function (err, category) {
51 - 'home', 8 + VideoModel.find(function (err, video) {
52 - { videos: video } // DB에서 받은 videos를 videos변수명으로 내보냄 9 + var item = []; // 카테고리별 비디오 목록을 담아두는 배열
53 - ); 10 + for (var i in category) {
11 + var videos = []; // 비디오 목록을 담는 임시 배열
12 + for (var j in video) {
13 + if (category[i].title == video[j].categori) {
14 + videos.push(video[j]);
15 + }
16 + }
17 + if (videos.length != 0) {
18 + // 빈 배열 체크
19 + console.log(videos);
20 + var items = {
21 + category: category[i],
22 + videos: videos,
23 + };
24 + item.push(items);
25 + }
26 + }
27 + //console.log(item[2].category.title);
28 + //console.log(item[2].videos);
29 + res.render(
30 + 'home',
31 + { video: item, categories: category } // DB에서 받은 videos와 category를 videos변수명으로 내보냄
32 + );
33 + });
34 + });
54 }); 35 });
55 36
56 module.exports = router; 37 module.exports = router;
......
1 var express = require('express'); 1 var express = require('express');
2 var router = express.Router(); 2 var router = express.Router();
3 var CategoriModel = require('../models/CategoriModel'); 3 var CategoriModel = require('../models/CategoriModel');
4 -//var csrf = require('csurf'); 4 +var VideoModel = require('../models/VideoModel');
5 -//var csrfProtection = csrf({ cookie: true }); 5 +var Youtube = require('youtube-node');
6 -var loginRequired = require('../libs/loginRequired'); 6 +var youtube = new Youtube();
7 -
8 -var path = require('path');
9 -var uploadDir = path.join(__dirname, '../uploads'); // 루트의 uploads위치에 저장한다.
10 -var fs = require('fs');
11 7
12 -//multer 셋팅 8 +var loginRequired = require('../libs/loginRequired');
13 -var multer = require('multer');
14 -var storage = multer.diskStorage({
15 - destination: function (req, file, callback) {
16 - //이미지가 저장되는 도착지 지정
17 - callback(null, uploadDir);
18 - },
19 - filename: function (req, file, callback) {
20 - // products-날짜.jpg(png) 저장
21 - callback(
22 - null,
23 - 'products-' + Date.now() + '.' + file.mimetype.split('/')[1]
24 - );
25 - },
26 -});
27 9
28 -var upload = multer({ storage: storage }); 10 +var limit = 10; // 출력 갯수
11 +youtube.setKey('AIzaSyCAaeW1qMSInEdN1OzU20FZlToIZYkb1bc'); // API 키 입력
29 12
30 router.get('/', function (req, res) { 13 router.get('/', function (req, res) {
31 res.send('categori main page'); 14 res.send('categori main page');
...@@ -43,7 +26,6 @@ router.get('/products', function (req, res) { ...@@ -43,7 +26,6 @@ router.get('/products', function (req, res) {
43 }); 26 });
44 27
45 router.get('/categories/write', loginRequired, function (req, res) { 28 router.get('/categories/write', loginRequired, function (req, res) {
46 - //edit에서도 같은 form을 사용하므로 빈 변수( product )를 넣어서 에러를 피해준다
47 res.render('category/form', { categories: '' }); 29 res.render('category/form', { categories: '' });
48 }); 30 });
49 31
...@@ -67,17 +49,85 @@ router.post('/categories/write', loginRequired, function (req, res) { ...@@ -67,17 +49,85 @@ router.post('/categories/write', loginRequired, function (req, res) {
67 49
68 router.get('/products/detail/:id', function (req, res) { 50 router.get('/products/detail/:id', function (req, res) {
69 //url 에서 변수 값을 받아올떈 req.params.id 로 받아온다 51 //url 에서 변수 값을 받아올떈 req.params.id 로 받아온다
52 + var word = req.query.keyword;
70 CategoriModel.findOne({ _id: req.params.id }, function (err, product) { 53 CategoriModel.findOne({ _id: req.params.id }, function (err, product) {
54 + var video = [];
71 //제품정보를 받고 그안에서 댓글을 받아온다. 55 //제품정보를 받고 그안에서 댓글을 받아온다.
72 CategoriModel.find({ product_id: req.params.id }, function (err, comments) { 56 CategoriModel.find({ product_id: req.params.id }, function (err, comments) {
73 - res.render('category/productsDetail', { 57 + if (word != null) {
74 - product: product, 58 + var count = 0;
75 - comments: comments, 59 + youtube.addParam('order', 'rating'); // 평점 순으로 정렬
76 - }); 60 + youtube.addParam('type', 'video'); // 타입 지정
61 + youtube.addParam('videoLicense', 'creativeCommon'); // 크리에이티브 커먼즈 아이템만 불러옴
62 + youtube.search(word, limit, function (err, result) {
63 + // 검색 실행
64 + console.log(word);
65 + if (err) {
66 + console.log(err);
67 + } // 에러일 경우 에러공지하고 빠져나감
68 + //console.log(JSON.stringify(result, null, 2)); // 받아온 전체 리스트 출력
69 + var items = result['items']; // 결과 중 items 항목만 가져옴
70 + for (var i in items) {
71 + var it = items[i];
72 + for (var j in it) {
73 + if (it[j]['title'] != null) {
74 + var title = it[j]['title'];
75 + }
76 + if (it[j]['videoId'] != null) {
77 + var video_id = it[j]['videoId'];
78 + }
79 + var urls = 'https://www.youtube.com/watch?v=' + video_id;
80 + }
81 + var item = {
82 + id: count,
83 + title: title,
84 + video_id: video_id,
85 + urls: urls,
86 + categori: product.title,
87 + };
88 + count++;
89 + video.push(item);
90 + }
91 + res.render('category/productsDetail', {
92 + product: product,
93 + comments: comments,
94 + videos: video,
95 + });
96 + });
97 + } else {
98 + res.render('category/productsDetail', {
99 + product: product,
100 + comments: comments,
101 + videos: video,
102 + });
103 + }
77 }); 104 });
78 }); 105 });
79 }); 106 });
80 107
108 +router.post('/products/detail/:id', loginRequired, function (req, res) {
109 + var item = [];
110 + var count = 1;
111 + for (var i in req.body.videoNum) {
112 + item.push(req.body.videoNum[i].split('///'));
113 + var video = new VideoModel({
114 + categori: item[i][2],
115 + id: count,
116 + title: item[i][1],
117 + video_id: item[i][3],
118 + urls: item[i][4],
119 + });
120 + var validationError = video.validateSync();
121 + if (validationError) {
122 + res.send(validationError);
123 + } else {
124 + video.save(function (err) {});
125 + }
126 + count++;
127 + }
128 + res.redirect('/categori/products');
129 +});
130 +
81 router.get('/products/edit/:id', loginRequired, function (req, res) { 131 router.get('/products/edit/:id', loginRequired, function (req, res) {
82 //기존에 폼에 value안에 값을 셋팅하기 위해 만든다. 132 //기존에 폼에 value안에 값을 셋팅하기 위해 만든다.
83 CategoriModel.findOne({ _id: req.params.id }, function (err, product) { 133 CategoriModel.findOne({ _id: req.params.id }, function (err, product) {
...@@ -87,37 +137,24 @@ router.get('/products/edit/:id', loginRequired, function (req, res) { ...@@ -87,37 +137,24 @@ router.get('/products/edit/:id', loginRequired, function (req, res) {
87 }); 137 });
88 }); 138 });
89 139
90 -router.post( 140 +router.post('/products/edit/:id', loginRequired, function (req, res) {
91 - '/products/edit/:id', 141 + //그전에 지정되 있는 파일명을 받아온다
92 - loginRequired, 142 + CategoriModel.findOne({ _id: req.params.id }, function (err, product) {
93 - upload.single('thumbnail'), 143 + var query = {
94 - // csrfProtection, 144 + name: req.body.name,
95 - function (req, res) { 145 + thumbnail: req.file ? req.file.filename : product.thumbnail,
96 - //그전에 지정되 있는 파일명을 받아온다 146 + price: req.body.price,
97 - CategoriModel.findOne({ _id: req.params.id }, function (err, product) { 147 + description: req.body.description,
98 - //아래의 코드만 추가되면 된다. 148 + };
99 - if (req.file && product.thumbnail) { 149 + CategoriModel.update(
100 - //요청중에 파일이 존재 할시 이전이미지 지운다. 150 + { id: req.params.id },
101 - fs.unlinkSync(uploadDir + '/' + product.thumbnail); 151 + { $set: query },
152 + function (err) {
153 + res.redirect('/categori/products/detail/' + req.params.id);
102 } 154 }
103 - //위의 코드만 추가되면 된다. 155 + );
104 - //넣을 변수 값을 셋팅한다 156 + });
105 - var query = { 157 +});
106 - name: req.body.name,
107 - thumbnail: req.file ? req.file.filename : product.thumbnail,
108 - price: req.body.price,
109 - description: req.body.description,
110 - };
111 - CategoriModel.update(
112 - { id: req.params.id },
113 - { $set: query },
114 - function (err) {
115 - res.redirect('/category/products/detail/' + req.params.id);
116 - }
117 - );
118 - });
119 - }
120 -);
121 158
122 router.get('/products/delete/:id', function (req, res) { 159 router.get('/products/delete/:id', function (req, res) {
123 CategoriModel.deleteMany({ _id: req.params.id }, function (err) { 160 CategoriModel.deleteMany({ _id: req.params.id }, function (err) {
......
...@@ -10,6 +10,6 @@ ...@@ -10,6 +10,6 @@
10 <td><input type="text" name="description" class="form-control" value="<%=categories.description%>"/></td> 10 <td><input type="text" name="description" class="form-control" value="<%=categories.description%>"/></td>
11 </tr> 11 </tr>
12 </table> 12 </table>
13 - <input type="submit" name="submit" value="submit" class="btn btn-primary"> 13 + <input type="submit" name="submit" value="완료" class="btn btn-primary">
14 </form> 14 </form>
15 <% include ../includes/footer.ejs %> 15 <% include ../includes/footer.ejs %>
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -3,6 +3,32 @@ ...@@ -3,6 +3,32 @@
3 <div class="panel-heading"> 3 <div class="panel-heading">
4 <%=product.title%> 4 <%=product.title%>
5 </div> 5 </div>
6 + <form method="get" action="">
7 + <div class="input-group">
8 + <input type="text" class="form-control" placeholder="검색 키워드를 입력하세요!" name="keyword" autocomplete='off'>
9 + <span class="input-group-btn">
10 + <button class="btn btn-secondary" type="submit">찾기</button>
11 + </span>
12 + </div>
13 + </form>
14 + <form method="post" action="">
15 + <% for (var i in videos) { %>
16 + <div style="float:left;
17 + padding: 15px;
18 + ">
19 + <input type="checkbox" name="videoNum" style="
20 + position: absolute;
21 + margin-top: 5px;
22 + margin-left: 5px;
23 + z-index: 4;
24 + zoom:3.0;
25 + " value="<%=videos[i].id + '///' + videos[i].title +'///'+ videos[i].categori +'///'+ videos[i].video_id +'///'+ videos[i].urls%>"/>
26 + <div id="<%=videos[i].id%>" vid="<%=videos[i].video_id%>">
27 + </div>
28 + </div>
29 + <%};%>
30 + <button class="btn btn-primary" style="margin-top: 10px; margin-left: 15px;" >영상담기</button>
31 + </form>
6 <div class="panel-body"> 32 <div class="panel-body">
7 <div style="padding-bottom: 10px"> 33 <div style="padding-bottom: 10px">
8 작성일 : 34 작성일 :
...@@ -20,9 +46,9 @@ ...@@ -20,9 +46,9 @@
20 <div> 46 <div>
21 댓글작성하기 47 댓글작성하기
22 <form id="commentForm" action="" method="post"> 48 <form id="commentForm" action="" method="post">
23 - <input type="hidden" name="product_id" value="<%=product._id%>" /> 49 + <input type="hidden" name="product_id" value="<%=product.id%>" />
24 <textarea class="form-control" name="content"></textarea> 50 <textarea class="form-control" name="content"></textarea>
25 - <button class="btn btn-primary" style="margin-top: 10px">댓글작성</button> 51 + <button class="btn btn-primary" style="margin-top: 10px" type="submit">댓글작성</button>
26 </form> 52 </form>
27 </div> 53 </div>
28 <!-- 댓글영역 --> 54 <!-- 댓글영역 -->
...@@ -90,4 +116,45 @@ $(document).on('click' , '.comment_delete' , function(){ ...@@ -90,4 +116,45 @@ $(document).on('click' , '.comment_delete' , function(){
90 }); 116 });
91 } 117 }
92 }); 118 });
119 +</script>
120 +<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
121 +<script type="text/javascript"
122 + src="https://cdnjs.cloudflare.com/ajax/libs/jquery.imagesloaded/4.1.1/imagesloaded.pkgd.min.js"></script>
123 +<script type="text/javascript">
124 + var $masonry_container = $('#masonry_container');
125 + $masonry_container.imagesLoaded(function () {
126 + $masonry_container.masonry({
127 + itemSelector: '.masonry-grid',
128 + columnWidth: 270
129 + });
130 + });
131 +</script>
132 +<script>
133 + var tag = document.createElement('script');
134 +
135 + tag.src = "https://www.youtube.com/iframe_api";
136 + var firstScriptTag = document.getElementsByTagName('script')[0];
137 + firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
138 +
139 + var player;
140 + var players = [];
141 + var videoIds = [];
142 + for (var i = 0; i < 10; i++) {
143 + players.push(String(i));
144 + videoIds.push($('#' + i).attr('vid'));
145 + }
146 +
147 + function onYouTubeIframeAPIReady() {
148 + for (var i = 0; i < videoIds.length; i++) {
149 + player = new YT.Player(players[i], {
150 + height: '300',
151 + width: '500',
152 + videoId: videoIds[i],
153 + events: {
154 + // 'onReady': onPlayerReady,
155 + // 'onStateChange': onPlayerStateChange
156 + }
157 + });
158 + }
159 + }
93 </script> 160 </script>
...\ No newline at end of file ...\ No newline at end of file
......