이승윤

Merge branch 'develop'

1 +node_modules
2 +package-lock.json
...\ No newline at end of file ...\ No newline at end of file
1 +var express = require('express');
2 +var app = express();
3 +var port = 3000;
4 +
5 +var mongoose = require('mongoose');
6 +mongoose.Promise = global.Promise;
7 +
8 +//auto-increment를 위한 패키지
9 +var path = require('path');
10 +var logger = require('morgan');
11 +var bodyParser = require('body-parser');
12 +var cookieParser = require('cookie-parser');
13 +var flash = require('connect-flash');
14 +
15 +//passport 로그인 관련
16 +var passport = require('passport');
17 +var session = require('express-session');
18 +
19 +//mongodb 연동
20 +var db = mongoose.connection;
21 +db.on('error', console.error);
22 +db.once('open', function () {
23 + console.log('mongo db Connection');
24 +});
25 +var connect = mongoose.connect('mongodb://127.0.0.1:27017/test', {
26 + useMongoClient: true,
27 +});
28 +
29 +//categori module get
30 +var categori = require('./routes/categori');
31 +var accounts = require('./routes/accounts');
32 +var auth = require('./routes/auth');
33 +var connectMongo = require('connect-mongo');
34 +var Video = require('./routes/Videos');
35 +var MongoStore = connectMongo(session);
36 +
37 +app.set('views', path.join(__dirname, 'views'));
38 +app.set('view engine', 'ejs');
39 +app.use(logger('dev'));
40 +app.use(bodyParser.json());
41 +app.use(bodyParser.urlencoded({ extended: false }));
42 +app.use(cookieParser());
43 +app.use('/uploads', express.static('uploads'));
44 +
45 +// MiddleWare 지정
46 +var sessionMiddleWare = session({
47 + secret: 'fastcampus',
48 + resave: false,
49 + saveUninitialized: true,
50 + cookie: {
51 + maxAge: 2000 * 60 * 60, //지속시간 2시간
52 + },
53 + store: new MongoStore({
54 + mongooseConnection: mongoose.connection,
55 + ttl: 14 * 24 * 60 * 60,
56 + }),
57 +});
58 +app.use(sessionMiddleWare);
59 +
60 +//passport 적용
61 +app.use(passport.initialize());
62 +app.use(passport.session());
63 +
64 +//플래시 메시지 관련
65 +app.use(flash());
66 +
67 +app.use(function (req, res, next) {
68 + app.locals.isLogin = req.isAuthenticated();
69 + //app.locals.urlparameter = req.url; //현재 url 정보를 보내고 싶으면 이와같이 셋팅
70 + //app.locals.userData = req.user; //사용 정보를 보내고 싶으면 이와같이 셋팅
71 + next();
72 +});
73 +
74 +//routes
75 +app.use('/', Video);
76 +app.use('/categori', categori);
77 +app.use('/accounts', accounts);
78 +app.use('/auth', auth);
79 +
80 +var server = app.listen(port, function () {
81 + console.log('Express listening on port', port);
82 +});
1 +module.exports = function(req, res, next) {
2 + if (!req.isAuthenticated()){
3 + res.redirect('/accounts/login');
4 + }else{
5 + return next();
6 + }
7 +};
...\ No newline at end of file ...\ No newline at end of file
1 +var crypto = require('crypto');
2 +var mysalt = "fastcampus";
3 +module.exports = function(password){
4 + return crypto.createHash('sha512').update( password + mysalt).digest('base64');
5 +};
...\ No newline at end of file ...\ No newline at end of file
1 +module.exports = function(){
2 + Array.prototype.removeByValue = function (search) {
3 + var index = this.indexOf(search);
4 + if (index !== -1) {
5 + this.splice(index, 1);
6 + }
7 + };
8 +};
...\ No newline at end of file ...\ No newline at end of file
1 +var mongoose = require('mongoose');
2 +var Schema = mongoose.Schema;
3 +
4 +var CategoriSchema = new Schema({
5 + title: {
6 + type: String,
7 + default: 'default',
8 + required: [true, '카테고리명이 비어있습니다!'],
9 + },
10 + videoNum: String,
11 + description: String, //설명
12 + created_at: {
13 + type: Date,
14 + default: Date.now(),
15 + },
16 + username: String,
17 +});
18 +
19 +CategoriSchema.virtual('getDate').get(function () {
20 + var date = new Date(this.created_at);
21 + return {
22 + year: date.getFullYear(),
23 + month: date.getMonth() + 1,
24 + day: date.getDate(),
25 + };
26 +});
27 +
28 +module.exports = mongoose.model('categories', CategoriSchema);
1 +var mongoose = require('mongoose');
2 +var Schema = mongoose.Schema;
3 +var UserSchema = new Schema({
4 + username: {
5 + type: String,
6 + required: [true, '아이디는 필수입니다.'],
7 + },
8 + password: {
9 + type: String,
10 + required: [true, '패스워드는 필수입니다.'],
11 + },
12 + displayname: String,
13 + created_at: {
14 + type: Date,
15 + default: Date.now(),
16 + },
17 +});
18 +
19 +module.exports = mongoose.model('user', UserSchema);
1 +var mongoose = require('mongoose');
2 +var Schema = mongoose.Schema;
3 +var VideoSchema = new Schema({
4 + categori: String,
5 + id: Number,
6 + title: String,
7 + video_id: String,
8 + urls: String,
9 +});
10 +
11 +module.exports = mongoose.model('videos', VideoSchema);
1 +{
2 + "name": "node",
3 + "version": "1.0.0",
4 + "description": "my-cookbook-project",
5 + "main": "index.js",
6 + "scripts": {
7 + "test": "echo \"Error: no test specified\" && exit 1",
8 + "start": "nodemon ./app.js"
9 + },
10 + "dependencies": {
11 + "body-parser": "^1.18.2",
12 + "connect-flash": "^0.1.1",
13 + "connect-mongo": "^2.0.0",
14 + "cookie-parser": "^1.4.3",
15 + "csurf": "^1.9.0",
16 + "ejs": "^2.5.7",
17 + "express": "^4.15.4",
18 + "express-session": "^1.15.5",
19 + "mongodb": "^2.2.36",
20 + "mongoose": "^4.13.21",
21 + "morgan": "^1.8.2",
22 + "multer": "^1.3.0",
23 + "nodemon": "^2.0.7",
24 + "passport": "^0.4.0",
25 + "passport-facebook": "^2.1.1",
26 + "passport-google-oauth20": "^2.0.0",
27 + "passport-local": "^1.0.0",
28 + "path": "^0.12.7",
29 + "socket.io": "^2.0.3",
30 + "youtube-node": "^1.3.3"
31 + }
32 +}
1 +var Youtube = require('youtube-node');
2 +var youtube = new Youtube();
3 +
4 +var express = require('express');
5 +var router = express.Router();
6 +
7 +var word = '백종원'; // 검색어 지정
8 +var limit = 10; // 출력 갯수
9 +var video = [];
10 +var test = 'test';
11 +var count = 0;
12 +youtube.setKey('AIzaSyCAaeW1qMSInEdN1OzU20FZlToIZYkb1bc'); // API 키 입력
13 +youtube.addParam('order', 'rating'); // 평점 순으로 정렬
14 +youtube.addParam('type', 'video'); // 타입 지정
15 +youtube.addParam('videoLicense', 'creativeCommon'); // 크리에이티브 커먼즈 아이템만 불러옴
16 +
17 +youtube.search(word, limit, function (err, result) {
18 + // 검색 실행
19 + if (err) {
20 + console.log(err);
21 + } // 에러일 경우 에러공지하고 빠져나감
22 + //console.log(JSON.stringify(result, null, 2)); // 받아온 전체 리스트 출력
23 + var items = result['items']; // 결과 중 items 항목만 가져옴
24 + for (var i in items) {
25 + var it = items[i];
26 + for (var j in it) {
27 + if (it[j]['title'] != null) {
28 + var title = it[j]['title'];
29 + }
30 + if (it[j]['videoId'] != null) {
31 + var video_id = it[j]['videoId'];
32 + }
33 + var urls = 'https://www.youtube.com/watch?v=' + video_id;
34 + }
35 + var item = {
36 + id: count,
37 + title: title,
38 + video_id: video_id,
39 + urls: urls,
40 + };
41 + count++;
42 + video.push(item);
43 + }
44 +});
45 +
46 +router.get('/', function (req, res) {
47 + res.render(
48 + 'home',
49 + { videos: video } // DB에서 받은 videos를 videos변수명으로 내보냄
50 + );
51 +});
52 +
53 +module.exports = router;
1 +var express = require('express');
2 +var CategoriModel = require('../models/CategoriModel');
3 +var VideoModel = require('../models/VideoModel');
4 +var router = express.Router();
5 +
6 +router.get('/', function (req, res) {
7 + CategoriModel.find(function (err, category) {
8 + VideoModel.find(function (err, video) {
9 + var item = []; // 카테고리별 비디오 목록을 담아두는 배열
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 + });
35 +});
36 +
37 +module.exports = router;
1 +var express = require('express');
2 +var router = express.Router();
3 +var UserModel = require('../models/UserModel');
4 +var passwordHash = require('../libs/passwordHash');
5 +var passport = require('passport');
6 +var LocalStrategy = require('passport-local').Strategy;
7 +
8 +passport.serializeUser(function (user, done) {
9 + console.log('serializeUser');
10 + done(null, user);
11 +});
12 +
13 +passport.deserializeUser(function (user, done) {
14 + var result = user;
15 + result.password = "";
16 + console.log('deserializeUser');
17 + done(null, result);
18 +});
19 +
20 +passport.use(new LocalStrategy({
21 + usernameField: 'username',
22 + passwordField : 'password',
23 + passReqToCallback : true
24 + },
25 + function (req, username, password, done) {
26 + UserModel.findOne({ username : username , password : passwordHash(password) }, function (err,user) {
27 + if (!user){
28 + return done(null, false, { message: '아이디 또는 비밀번호 오류 입니다.' });
29 + }else{
30 + return done(null, user );
31 + }
32 + });
33 + }
34 +));
35 +
36 +router.get('/', function(req, res){
37 + res.send('account app');
38 +});
39 +
40 +router.get('/join', function(req, res){
41 + res.render('accounts/join');
42 +});
43 +
44 +router.post('/join', function(req, res){
45 + var User = new UserModel({
46 + username : req.body.username,
47 + password : passwordHash(req.body.password),
48 + displayname : req.body.displayname
49 + });
50 + User.save(function(err){
51 + res.send('<script>alert("회원가입 성공");location.href="/accounts/login";</script>');
52 + });
53 +});
54 +
55 +router.get('/login', function(req, res){
56 + res.render('accounts/login', { flashMessage : req.flash().error });
57 +});
58 +
59 +router.post('/login' ,
60 +passport.authenticate('local', {
61 + failureRedirect: '/accounts/login',
62 + failureFlash: true
63 +}),
64 +function(req, res){
65 + res.send('<script>alert("로그인 성공");location.href="/";</script>');
66 +}
67 +);
68 +
69 +router.get('/success', function(req, res){
70 + res.send(req.user);
71 +});
72 +
73 +
74 +router.get('/logout', function(req, res){
75 + req.logout();
76 + res.redirect('/accounts/login');
77 +});
78 +
79 +module.exports = router;
...\ No newline at end of file ...\ No newline at end of file
1 +var express = require('express');
2 +var router = express.Router();
3 +var UserModel = require('../models/UserModel');
4 +var passport = require('passport');
5 +const GoogleStrategy = require('passport-google-oauth20').Strategy;
6 +
7 +passport.serializeUser(function (user, done) {
8 + done(null, user);
9 +});
10 +
11 +passport.deserializeUser(function (user, done) {
12 + done(null, user);
13 +});
14 +
15 +passport.use(
16 + new GoogleStrategy(
17 + {
18 + clientID:
19 + '912554148550-gq86jjjgc022b1eit50mboh5lq48covi.apps.googleusercontent.com',
20 + clientSecret: '_EzuXeN7eNCTbcGQUV4kY1pN',
21 + callbackURL: 'http://localhost:3000/auth/google/callback',
22 + profileFields: ['id', 'displayName', 'photos', 'email'], //받고 싶은 필드 나열
23 + },
24 + function (accessToken, refreshToken, profile, done) {
25 + UserModel.findOne(
26 + { username: 'goo_' + profile.id },
27 + function (err, user) {
28 + if (!user) {
29 + //없으면 회원가입 후 로그인 성공페이지 이동
30 + var regData = {
31 + //DB에 등록 및 세션에 등록될 데이터
32 + username: 'goo_' + profile.id,
33 + password: 'google_login',
34 + displayname: profile.displayName,
35 + };
36 + var User = new UserModel(regData);
37 + User.save(function (err) {
38 + //DB저장
39 + done(null, regData); //세션 등록
40 + });
41 + } else {
42 + //있으면 DB에서 가져와서 세션등록
43 + done(null, user);
44 + }
45 + }
46 + );
47 + }
48 + )
49 +);
50 +
51 +router.get('/google', passport.authenticate('google', { scope: ['profile'] }));
52 +
53 +//인증후 구글에서 이 주소로 리턴해줌. 상단에 적은 callbackURL과 일치
54 +router.get(
55 + '/google/callback',
56 + passport.authenticate('google', {
57 + failureRedirect: '/auth',
58 + successRedirect: '/',
59 + })
60 +);
61 +//로그인 성공시 이동할 주소
62 +router.get('/google/success', function (req, res) {
63 + res.send(req.user);
64 +});
65 +
66 +router.get('/google/fail', function (req, res) {
67 + res.send('google login fail');
68 +});
69 +
70 +module.exports = router;
1 +var express = require('express');
2 +var router = express.Router();
3 +var CategoriModel = require('../models/CategoriModel');
4 +var VideoModel = require('../models/VideoModel');
5 +var Youtube = require('youtube-node');
6 +var youtube = new Youtube();
7 +
8 +var loginRequired = require('../libs/loginRequired');
9 +var redirectUrls = '';
10 +var limit = 10; // 출력 갯수
11 +youtube.setKey('AIzaSyCAaeW1qMSInEdN1OzU20FZlToIZYkb1bc'); // API 키 입력
12 +
13 +router.get('/', function (req, res) {
14 + res.send('categori main page');
15 +});
16 +
17 +router.get('/products', function (req, res) {
18 + CategoriModel.find(function (err, products) {
19 + console.log(products);
20 + res.render(
21 + 'category/products',
22 + { categories: products }
23 + //ProductModel의 products를 받아서
24 + //categori/products로 response를 보낸다.
25 + );
26 + });
27 +});
28 +
29 +router.get('/categories/write', loginRequired, function (req, res) {
30 + res.render('category/form', { categories: '' });
31 +});
32 +
33 +router.post('/categories/write', loginRequired, function (req, res) {
34 + var category = new CategoriModel({
35 + title: req.body.title,
36 + description: req.body.description,
37 + username: req.user.displayname,
38 + });
39 + //
40 + var validationError = category.validateSync();
41 + if (validationError) {
42 + res.send(validationError);
43 + } else {
44 + category.save(function (err) {
45 + res.redirect('/categori/products');
46 + });
47 + }
48 + //
49 +});
50 +
51 +router.get('/products/detail/:id', function (req, res) {
52 + //url 에서 변수 값을 받아올때 req.params.id 로 받아온다
53 + var word = req.query.keyword;
54 + redirectUrls = req.params.id;
55 + CategoriModel.findOne({ _id: req.params.id }, function (err, product) {
56 + var video = [];
57 + //제품정보를 받고 그안에서 댓글을 받아온다.
58 + CategoriModel.find({ product_id: req.params.id }, function (err, comments) {
59 + VideoModel.find(function (err, myVideo) {
60 + var mitem = []; // 카테고리별 비디오 목록을 담아두는 배열
61 + var videos = []; // 비디오 목록을 담는 임시 배열
62 + for (var j in myVideo) {
63 + if (product.title == myVideo[j].categori) {
64 + var k = {
65 + title: myVideo[j].title,
66 + id: myVideo[j]._id,
67 + };
68 + videos.push(k);
69 + }
70 + }
71 + if (videos.length != 0) {
72 + // 빈 배열 체크
73 + //console.log(videos);
74 + var items = videos;
75 + mitem.push(items);
76 + }
77 + //console.log(item[2].category.title);
78 + //console.log(item[2].videos);
79 + if (word != null) {
80 + var count = 0;
81 + youtube.addParam('order', 'rating'); // 평점 순으로 정렬
82 + youtube.addParam('type', 'video'); // 타입 지정
83 + youtube.addParam('videoLicense', 'creativeCommon'); // 크리에이티브 커먼즈 아이템만 불러옴
84 + youtube.search(word, limit, function (err, result) {
85 + // 검색 실행
86 + //console.log(word);
87 + if (err) {
88 + console.log(err);
89 + } // 에러일 경우 에러공지하고 빠져나감
90 + //console.log(JSON.stringify(result, null, 2)); // 받아온 전체 리스트 출력
91 + var items = result['items']; // 결과 중 items 항목만 가져옴
92 + for (var i in items) {
93 + var it = items[i];
94 + for (var j in it) {
95 + if (it[j]['title'] != null) {
96 + var title = it[j]['title'];
97 + }
98 + if (it[j]['videoId'] != null) {
99 + var video_id = it[j]['videoId'];
100 + }
101 + var urls = 'https://www.youtube.com/watch?v=' + video_id;
102 + }
103 + var item = {
104 + id: count,
105 + title: title,
106 + video_id: video_id,
107 + urls: urls,
108 + categori: product.title,
109 + };
110 + count++;
111 + video.push(item);
112 + }
113 + res.render('category/productsDetail', {
114 + product: product,
115 + comments: comments,
116 + videos: video,
117 + items: mitem,
118 + });
119 + });
120 + } else {
121 + //console.log(mitem);
122 + res.render('category/productsDetail', {
123 + product: product,
124 + comments: comments,
125 + videos: video,
126 + items: mitem,
127 + });
128 + }
129 + });
130 + });
131 + });
132 +});
133 +
134 +router.post('/products/detail/:id', loginRequired, function (req, res) {
135 + var item = [];
136 + var count = 1;
137 + var temp = '';
138 + console.log(req.body.videoNum.length);
139 + if (req.body.videoNum.length > 30) {
140 + for (var i in req.body.videoNum) {
141 + temp += req.body.videoNum[i];
142 + }
143 + item.push(temp.split('///'));
144 + var video = new VideoModel({
145 + categori: item[0][2],
146 + id: count,
147 + title: item[0][1],
148 + video_id: item[0][3],
149 + urls: item[0][4],
150 + });
151 + var validationError = video.validateSync();
152 + if (validationError) {
153 + res.send(validationError);
154 + } else {
155 + video.save(function (err) {});
156 + }
157 + count++;
158 + } else {
159 + for (var i in req.body.videoNum) {
160 + item.push(req.body.videoNum[i].split('///'));
161 + var video = new VideoModel({
162 + categori: item[i][2],
163 + id: count,
164 + title: item[i][1],
165 + video_id: item[i][3],
166 + urls: item[i][4],
167 + });
168 + var validationError = video.validateSync();
169 + if (validationError) {
170 + res.send(validationError);
171 + } else {
172 + video.save(function (err) {});
173 + }
174 + count++;
175 + }
176 + }
177 + res.redirect('/categori/products/detail/' + req.params.id);
178 +});
179 +
180 +router.get('/products/edit/:id', loginRequired, function (req, res) {
181 + //기존에 폼에 value안에 값을 셋팅하기 위해 만든다.
182 + CategoriModel.findOne({ _id: req.params.id }, function (err, product) {
183 + res.render('category/form', {
184 + categories: product,
185 + });
186 + });
187 +});
188 +
189 +router.post('/products/edit/:id', loginRequired, function (req, res) {
190 + //그전에 지정되 있는 파일명을 받아온다
191 + CategoriModel.findOne({ _id: req.params.id }, function (err, product) {
192 + var query = {
193 + name: req.body.name,
194 + thumbnail: req.file ? req.file.filename : product.thumbnail,
195 + price: req.body.price,
196 + description: req.body.description,
197 + };
198 + CategoriModel.update(
199 + { id: req.params.id },
200 + { $set: query },
201 + function (err) {
202 + res.redirect('/categori/products/detail/' + req.params.id);
203 + }
204 + );
205 + });
206 +});
207 +
208 +router.get('/products/delete/:id', function (req, res) {
209 + CategoriModel.findOne({ _id: req.params.id }, function (err, products) {
210 + CategoriModel.deleteMany({ _id: req.params.id }, function (err) {
211 + VideoModel.find(function (err, myVideo) {
212 + for (var i in myVideo) {
213 + if (products.title == myVideo[i].categori) {
214 + var deleteItem = myVideo[i].categori;
215 + }
216 + }
217 + VideoModel.deleteMany({ categori: deleteItem }, function (err) {
218 + res.redirect('/categori/products');
219 + });
220 + });
221 + });
222 + });
223 +});
224 +
225 +router.get('/products/detail/delete/:id', function (req, res) {
226 + VideoModel.findOne({ _id: req.params.id }, function (err, products) {
227 + VideoModel.deleteMany({ _id: products }, function (err) {
228 + res.redirect('/categori/products/detail/' + redirectUrls);
229 + });
230 + });
231 +});
232 +
233 +router.post('/products/ajax_comment/insert', function (req, res) {
234 + var comment = new CategoriModel({
235 + content: req.body.content,
236 + product_id: parseInt(req.body.product_id),
237 + });
238 + comment.save(function (err, comment) {
239 + res.json({
240 + id: comment.id,
241 + content: comment.content,
242 + message: 'success',
243 + });
244 + });
245 +});
246 +
247 +router.post('/products/ajax_comment/delete', function (req, res) {
248 + CategoriModel.remove({ _id: req.body.comment_id }, function (err) {
249 + res.json({ message: 'success' });
250 + });
251 +});
252 +
253 +module.exports = router;
1 +<% include ../includes/header.ejs %>
2 +<div class="w-25 border border-info border-3" style="position: absolute; left: 37%; top: 17%;">
3 + <div>
4 + <div>
5 + <div style="padding-top: 5%; padding-left: 5%;">
6 + <h3 class="panel-title">회원가입</h3>
7 + </div>
8 + <div class="panel-body">
9 + <form role="form" action="" id="join_form" method="post">
10 + <fieldset>
11 + <div class="w-100" style="padding-left: 5%; padding-right: 5%;">
12 + <input class="form-control" placeholder="ID" name="username" type="text" autofocus="" required="">
13 + </div>
14 + <div class="w-100" style="padding-left: 5%; padding-right: 5%;padding-top: 3%">
15 + <input class="form-control" placeholder="Password" name="password" type="password" value="" required="">
16 + </div>
17 + <div class="w-100" style="padding-left: 5%; padding-right: 5%;padding-top: 3%">
18 + <input class="form-control" placeholder="Password 확인" name="password2" type="password" value="" required="">
19 + </div>
20 + <div class="w-100" style="padding-left: 5%; padding-right: 5%;padding-top: 3%">
21 + <input class="form-control" placeholder="이름" name="displayname" type="text" value="" required="">
22 + </div>
23 + <!-- Change this to a button or input when using this as a form -->
24 + <div class="d-grid gap-2 col-11 mx-auto p-2">
25 + <input type="submit" class="btn btn-lg btn-success btn-block" value="가입하기">
26 + <a href="/auth/google" class="btn btn-lg btn-danger btn-block">
27 + <i class="fa fa-google" aria-hidden="true"></i> Google 회원가입
28 + </a>
29 + </div>
30 + </fieldset>
31 + </form>
32 + </div>
33 + </div>
34 + </div>
35 +</div>
36 +<script type="text/javascript">
37 +(function(){
38 + $(document).ready(function() {
39 + $('#join_form').submit(function(){
40 + var $usernameInput = $('#join_form input[name=username]');
41 + var $passwordInput = $('#join_form input[name=password]');
42 + var $passwordInput2 = $('#join_form input[name=password2]');
43 + var $displayname = $('#join_form input[name=displayname]');
44 + if(!$usernameInput.val()){
45 + alert("아이디를 입력해주세요.");
46 + $usernameInput.focus();
47 + return false;
48 + }
49 + if(!$passwordInput.val()){
50 + alert("패스워드를 입력해주세요.");
51 + $passwordInput.focus();
52 + return false;
53 + }
54 + if(!$passwordInput2.val()){
55 + alert("확인 패스워드를 입력해주세요.");
56 + $passwordInput2.focus();
57 + return false;
58 + }
59 + if(!$displayname.val()){
60 + alert("이름을 입력해주세요.");
61 + $displayname.focus();
62 + return false;
63 + }
64 + if($passwordInput.val() !== $passwordInput2.val()){
65 + alert("패스워드와 확인용패스워드를 똑같이 입력해주세요.");
66 + return false;
67 + }
68 + return true;
69 + });
70 + });
71 +})();
72 +</script>
73 +<% include ../includes/footer.ejs %>
...\ No newline at end of file ...\ No newline at end of file
1 +<% include ../includes/header.ejs %>
2 +<div class="w-25 border border-info border-3" style="position: absolute; left: 37%; top: 17%;">
3 + <div>
4 + <%if(typeof flashMessage !=='undefined') {%>
5 + <div class="alert alert-danger" role="alert"><%=flashMessage%></div>
6 + <%}%>
7 + <div>
8 + <div style="padding-top: 5%; padding-left: 5%;">
9 + <h3 class="panel-title">로그인</h3>
10 + </div>
11 + <div class="panel-body">
12 + <form role="form" action="" id="login_form" method="post">
13 + <fieldset>
14 + <div class="w-100" style="padding-left: 5%; padding-right: 5%;">
15 + <label for="login" class="form-label">ID</label>
16 + <input class="form-control" placeholder="ID" name="username" type="text" autofocus="" required="">
17 + </div>
18 + <div class="w-100 p-3">
19 + <label for="password" class="form-label">Password</label>
20 + <input class="form-control" placeholder="Password" name="password" type="password" value="" required="">
21 + </div>
22 + <!-- Change this to a button or input when using this as a form -->
23 + <div class="d-grid gap-2 col-11 mx-auto p-2">
24 + <input type="submit" class="btn btn-lg btn-success btn-block" value="로그인">
25 + <a href="/auth/google" class="btn btn-lg btn-danger btn-block">
26 + <i class="fa fa-google" aria-hidden="true"></i> Google 로그인
27 + </a>
28 + </div>
29 + </fieldset>
30 + </form>
31 + </div>
32 + </div>
33 + </div>
34 +</div>
35 +<script type="text/javascript">
36 +(function(){
37 + $(document).ready(function() {
38 + $('#login_form').submit(function(){
39 + var $usernameInput = $('#login_form input[name=username]');
40 + var $passwordInput = $('#login_form input[name=password]');
41 + if(!$usernameInput.val()){
42 + alert("아이디를 입력해주세요.");
43 + $usernameInput.focus();
44 + return false;
45 + }
46 + if(!$passwordInput.val()){
47 + alert("패스워드를 입력해주세요.");
48 + $passwordInput.focus();
49 + return false;
50 + }
51 + return true;
52 + });
53 + });
54 +})();
55 +</script>
56 +<% include ../includes/footer.ejs %>
...\ No newline at end of file ...\ No newline at end of file
1 +<% include ../includes/header.ejs %>
2 + <form action="" method="post" >
3 + <table class="table table-bordered">
4 + <tr>
5 + <th>카테고리명</th>
6 + <td><input type="text" name="title" class="form-control" value="<%=categories.title%>"/></td>
7 + </tr>
8 + <tr>
9 + <th>설명</th>
10 + <td><input type="text" name="description" class="form-control" value="<%=categories.description%>"/></td>
11 + </tr>
12 + </table>
13 + <input type="submit" name="submit" value="완료" class="btn btn-primary">
14 + </form>
15 +<% include ../includes/footer.ejs %>
...\ No newline at end of file ...\ No newline at end of file
1 +<% include ../includes/header.ejs %>
2 + <table class="table table-bordered table-hover">
3 + <tr class="table-info">
4 + <th width="80px" style="text-align: center;">카테고리명</th>
5 + <th width="50px" style="text-align: center;">개설 날짜</th>
6 + <th width="550px" style="text-align: center;">내용</th>
7 + <th width="50px" style="text-align: center;">사용자명</th>
8 + <th width="30px" style="text-align: center;">삭제</th>
9 + </tr>
10 + <%categories.forEach(function(product){%>
11 + <tr>
12 + <td style="text-align: center;">
13 + <a href="/categori/products/detail/<%=product.id%>"><%=product.title%></a>
14 + </td>
15 + <td style="text-align: center;" >
16 + <%=product.getDate.year%> -
17 + <%=product.getDate.month%> -
18 + <%=product.getDate.day%>
19 + </td>
20 + <td>
21 + <%=product.description%>
22 + </td>
23 + <td style="text-align: center;">
24 + <%=product.username%>
25 + </td>
26 + <td style="text-align: center;">
27 + <a href="/categori/products/delete/<%=product.id%>" class="btn btn-danger" onclick="return confirm('삭제하시겠습니까?')">삭제</a>
28 + </td>
29 + </tr>
30 + <% }); %>
31 + </table>
32 +
33 + <a href="/categori/categories/write" class="btn btn-primary">작성하기</a>
34 +
35 +<% include ../includes/footer.ejs %>
...\ No newline at end of file ...\ No newline at end of file
1 +<% include ../includes/header.ejs %>
2 + <div class="panel panel-default">
3 + <div class="panel-heading">
4 +  <h2 style="padding-left: 30px;"><%=product.title%></h2>
5 + <div style="padding-bottom: 10px;">  
6 + 작성일 :
7 + <%=product.getDate.year%> -
8 + <%=product.getDate.month%> -
9 + <%=product.getDate.day%>
10 + </div>
11 + <div style="padding-left: 30px">
12 + 설명 : <%=product.description%>
13 + </div>
14 + <hr/>
15 + </div>
16 +
17 + <div>
18 + <% var count=0; %>
19 + <% if (items.length != 0) { %>
20 + <ul class="list-group" style="padding-left: 30px; padding-bottom: 30px;">
21 + <li class="list-group-item list-group-item-info" aria-current="true">보유중인 영상</li>
22 + <% for (var i in items[0]) { %>
23 + <li class="list-group-item"><%=items[0][i].title%> <a href="/categori/products/detail/delete/<%=items[0][i].id%>" style="position: absolute; right: 1%;" class="btn btn-danger btn-sm" onclick="return confirm('삭제하시겠습니까?')">삭제</a></li>
24 + <%count++;};%>
25 + </ul>
26 + <%};%>
27 + </div>
28 + <button style="margin-left: 30px; margin-bottom: 10px;" class="btn btn-outline-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseExample"
29 + aria-expanded="false" aria-controls="collapseExample">
30 + 영상 추가하기
31 + </button>
32 + <div class="collapse show" id="collapseExample" style="padding-left: 30px;">
33 + <div class="card card-body">
34 + <form method="get" action="">
35 + <div class="input-group" style="padding-left: 10px;">
36 + <input type="text" class="form-control" placeholder="검색 키워드를 입력하세요!" name="keyword" autocomplete='off'>
37 + <span class="input-group-btn">
38 + <button class="btn btn-secondary" type="submit">찾기</button>
39 + </span>
40 + </div>
41 + </form>
42 + <form method="post" action="">
43 + <% for (var i in videos) { %>
44 + <div style="float:left;
45 + padding: 15px;
46 + ">
47 + <input type="checkbox" name="videoNum" style="
48 + position: absolute;
49 + margin-top: 5px;
50 + margin-left: 5px;
51 + z-index: 4;
52 + zoom:3.0;
53 + "
54 + value="<%=videos[i].id + '///' + videos[i].title +'///'+ videos[i].categori +'///'+ videos[i].video_id +'///'+ videos[i].urls%>" />
55 + <div id="<%=videos[i].id%>" vid="<%=videos[i].video_id%>">
56 + </div>
57 + </div>
58 + <%};%>
59 + <button class="btn btn-primary" style="margin-top: 10px; margin-left: 10px;">영상담기</button>
60 + </form>
61 + </div>
62 + </div>
63 + <div class="panel-body">
64 + <div>
65 + <hr />
66 + </div>
67 + </div>
68 + </div>
69 +
70 + <div style="padding-bottom: 30px;">
71 + <a href="/categori/products" class="btn btn-dark">목록으로</a>
72 + <a href="/categori/products/edit/<%=product._id%>" class="btn btn-primary">수정</a>
73 + </div>
74 +<% include ../includes/footer.ejs %>
75 +
76 +<script>
77 +(function(){
78 + // 영상 메모 구현 파트(아직 미구현)
79 + $(document).ready(function() {
80 + $('#commentForm').submit(function(){
81 + var $contentVal = $(this).children('textarea[name=content]').val();
82 + if($contentVal){
83 + $.ajax({
84 + url: '/admin/products/ajax_comment/insert',
85 + type: 'POST',
86 + data: $(this).serialize(),
87 + })
88 + .done(function(args) {
89 + if(args.message==="success"){
90 + $('#comment_area').append(
91 + '<div>' + args.content +
92 + " ( <a class='comment_delete' comment_id='"+ args._id +"'>삭제</a> ) </div>"
93 + );
94 + $('#commentForm textarea[name=content]').val("");
95 + }
96 + })
97 + .fail(function(args) {
98 + console.log(args);
99 + });
100 + }else{
101 + alert('댓글 내용을 입력해주세요.')
102 + }
103 + return false;
104 + });
105 + });
106 +})();
107 +</script>
108 +
109 +<script>
110 + var tag = document.createElement('script');
111 +
112 + tag.src = "https://www.youtube.com/iframe_api";
113 + var firstScriptTag = document.getElementsByTagName('script')[0];
114 + firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
115 +
116 + var player;
117 + var players = [];
118 + var videoIds = [];
119 + for (var i = 0; i < 10; i++) {
120 + players.push(String(i));
121 + videoIds.push($('#' + i).attr('vid'));
122 + }
123 +
124 + function onYouTubeIframeAPIReady() {
125 + for (var i = 0; i < videoIds.length; i++) {
126 + player = new YT.Player(players[i], {
127 + height: '360',
128 + width: '640',
129 + videoId: videoIds[i],
130 + events: {
131 + }
132 + });
133 + }
134 + }
135 +</script>
...\ No newline at end of file ...\ No newline at end of file
1 +<% include ./includes/header.ejs %>
2 + <div style="background-color:lavenderblush;">
3 + <h2 style="padding: 30px;">Categories</h2>
4 + <% var count = 0; var collapseCount = 'less';%>
5 + <center>
6 + <div class="accordion w-85" id="accordionExample" style="padding-bottom: 20px;">
7 + <% for (var i in video) { %>
8 + <div class="accordion-item" style="margin: 20px;">
9 + <h2 class="accordion-header" id="<%=video[i].category.title%>">
10 + <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#<%=collapseCount%>"
11 + aria-expanded="true" aria-controls="<%=collapseCount%>" style ="padding-top: 30px">
12 + <%=video[i].category.title%>
13 + </button>
14 + </h2>
15 + <div id="<%=collapseCount%>" data-bs-parent="#accordionExample" class="accordion-collapse collapse" aria-labelledby="<%=video[i].category.title%>">
16 + <div class="accordion-body">
17 + <% for (var j in video[i].videos) { %>
18 + <div class="card" style="width: 55rem; margin-bottom: 15px; margin-top: 15px;">
19 + <div class="card-top" id="<%=count%>" vid="<%=video[i].videos[j].video_id%>" style="margin: 30px;">
20 + </div>
21 + <div class="card-body">
22 + <h5 class="card-title"><%=video[i].videos[j].title%></h5>
23 + <p class="card-text">해당 영상에 대한 메모를 여기에 출력.
24 + </p>
25 + </div>
26 + </div>
27 + <%count++;}; %>
28 + </div>
29 + </div>
30 + </div>
31 + <%collapseCount = collapseCount+ "le";%>
32 + <%};%>
33 + </div>
34 + </center>
35 + </div>
36 +
37 + <style type="text/css">
38 + .masonry-grid img {
39 + max-width: 260px;
40 + }
41 + </style>
42 + <script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
43 + <script type="text/javascript"
44 + src="https://cdnjs.cloudflare.com/ajax/libs/jquery.imagesloaded/4.1.1/imagesloaded.pkgd.min.js"></script>
45 + <script type="text/javascript">
46 + var $masonry_container = $('#masonry_container');
47 + $masonry_container.imagesLoaded(function () {
48 + $masonry_container.masonry({
49 + itemSelector: '.masonry-grid',
50 + columnWidth: 270
51 + });
52 + });
53 + </script>
54 + <script>
55 + var tag = document.createElement('script');
56 +
57 + tag.src = "https://www.youtube.com/iframe_api";
58 + var firstScriptTag = document.getElementsByTagName('script')[0];
59 + firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
60 + var player;
61 + var players = [];
62 + var videoIds = [];
63 + for (var i = 0; i < 30; i++) {
64 + players.push(String(i));
65 + videoIds.push($('#' + players[i]).attr('vid'));
66 + }
67 +
68 + function onYouTubeIframeAPIReady() {
69 + for (var i = 0; i < videoIds.length; i++) {
70 + player = new YT.Player(players[i], {
71 + height: '450',
72 + width: '800',
73 + videoId: videoIds[i],
74 + });
75 + }
76 + }
77 + </script>
78 + <% include ./includes/footer.ejs %>
...\ No newline at end of file ...\ No newline at end of file
1 +</div>
2 +</body>
3 +<script
4 + src="https://code.jquery.com/jquery-3.2.1.min.js"
5 + integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
6 + crossorigin="anonymous"></script>
7 +</html>
...\ No newline at end of file ...\ No newline at end of file
1 +<!DOCTYPE html>
2 +<html lang="en">
3 +<head>
4 + <meta charset="UTF-8">
5 + <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 + <meta http-equiv="X-UA-Compatible" content="ie=edge">
7 + <title>MYCOOK</title>
8 + <script
9 + src="https://code.jquery.com/jquery-3.2.1.min.js"
10 + integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
11 + crossorigin="anonymous"></script>
12 + <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
13 + <!--bootstrap js 추가 -->
14 + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet"
15 + integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous">
16 + <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js"
17 + integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4"
18 + crossorigin="anonymous"></script>
19 +</head>
20 +<body>
21 + <div class="container-fluid" style="margin-top: 15px;">
22 + <nav class="navbar navbar-light" style="background-color: #e3f2fd;">
23 + <div>
24 + <div class="navbar-brand" style="float: left;">
25 + <a href="/" class="nav-link">MyCookBook</a>
26 + </div>
27 + <div class="navbar">
28 + <ul class="nav">
29 + <li class="nav-item">
30 + <a class="nav-link" href="/">Home</a>
31 + </li>
32 + <li class="nav-item"><a class="nav-link" href="/categori/products">Category</a></li>
33 + <% if(isLogin){%>
34 + <li class="nav-item"><a class="nav-link" href="/accounts/logout" onclick="return confirm('로그아웃 하시겠습니까?')">LOGOUT</a></li>
35 + <%}else{%>
36 + <li class="nav-item"><a class="nav-link" href="/accounts/join">SignUp</a></li>
37 + <li class="nav-item"><a class="nav-link" href="/accounts/login">LOGIN</a></li>
38 + <%}%>
39 + </ul>
40 + </div>
41 + </div>
42 + </nav>
43 + <hr style=" border: 2px solid #4263eb" />
44 +