이승윤

Merge branch 'develop'

node_modules
package-lock.json
\ No newline at end of file
var express = require('express');
var app = express();
var port = 3000;
var mongoose = require('mongoose');
mongoose.Promise = global.Promise;
//auto-increment를 위한 패키지
var path = require('path');
var logger = require('morgan');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var flash = require('connect-flash');
//passport 로그인 관련
var passport = require('passport');
var session = require('express-session');
//mongodb 연동
var db = mongoose.connection;
db.on('error', console.error);
db.once('open', function () {
console.log('mongo db Connection');
});
var connect = mongoose.connect('mongodb://127.0.0.1:27017/test', {
useMongoClient: true,
});
//categori module get
var categori = require('./routes/categori');
var accounts = require('./routes/accounts');
var auth = require('./routes/auth');
var connectMongo = require('connect-mongo');
var Video = require('./routes/Videos');
var MongoStore = connectMongo(session);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use('/uploads', express.static('uploads'));
// MiddleWare 지정
var sessionMiddleWare = session({
secret: 'fastcampus',
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 2000 * 60 * 60, //지속시간 2시간
},
store: new MongoStore({
mongooseConnection: mongoose.connection,
ttl: 14 * 24 * 60 * 60,
}),
});
app.use(sessionMiddleWare);
//passport 적용
app.use(passport.initialize());
app.use(passport.session());
//플래시 메시지 관련
app.use(flash());
app.use(function (req, res, next) {
app.locals.isLogin = req.isAuthenticated();
//app.locals.urlparameter = req.url; //현재 url 정보를 보내고 싶으면 이와같이 셋팅
//app.locals.userData = req.user; //사용 정보를 보내고 싶으면 이와같이 셋팅
next();
});
//routes
app.use('/', Video);
app.use('/categori', categori);
app.use('/accounts', accounts);
app.use('/auth', auth);
var server = app.listen(port, function () {
console.log('Express listening on port', port);
});
module.exports = function(req, res, next) {
if (!req.isAuthenticated()){
res.redirect('/accounts/login');
}else{
return next();
}
};
\ No newline at end of file
var crypto = require('crypto');
var mysalt = "fastcampus";
module.exports = function(password){
return crypto.createHash('sha512').update( password + mysalt).digest('base64');
};
\ No newline at end of file
module.exports = function(){
Array.prototype.removeByValue = function (search) {
var index = this.indexOf(search);
if (index !== -1) {
this.splice(index, 1);
}
};
};
\ No newline at end of file
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var CategoriSchema = new Schema({
title: {
type: String,
default: 'default',
required: [true, '카테고리명이 비어있습니다!'],
},
videoNum: String,
description: String, //설명
created_at: {
type: Date,
default: Date.now(),
},
username: String,
});
CategoriSchema.virtual('getDate').get(function () {
var date = new Date(this.created_at);
return {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate(),
};
});
module.exports = mongoose.model('categories', CategoriSchema);
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
username: {
type: String,
required: [true, '아이디는 필수입니다.'],
},
password: {
type: String,
required: [true, '패스워드는 필수입니다.'],
},
displayname: String,
created_at: {
type: Date,
default: Date.now(),
},
});
module.exports = mongoose.model('user', UserSchema);
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var VideoSchema = new Schema({
categori: String,
id: Number,
title: String,
video_id: String,
urls: String,
});
module.exports = mongoose.model('videos', VideoSchema);
{
"name": "node",
"version": "1.0.0",
"description": "my-cookbook-project",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon ./app.js"
},
"dependencies": {
"body-parser": "^1.18.2",
"connect-flash": "^0.1.1",
"connect-mongo": "^2.0.0",
"cookie-parser": "^1.4.3",
"csurf": "^1.9.0",
"ejs": "^2.5.7",
"express": "^4.15.4",
"express-session": "^1.15.5",
"mongodb": "^2.2.36",
"mongoose": "^4.13.21",
"morgan": "^1.8.2",
"multer": "^1.3.0",
"nodemon": "^2.0.7",
"passport": "^0.4.0",
"passport-facebook": "^2.1.1",
"passport-google-oauth20": "^2.0.0",
"passport-local": "^1.0.0",
"path": "^0.12.7",
"socket.io": "^2.0.3",
"youtube-node": "^1.3.3"
}
}
var Youtube = require('youtube-node');
var youtube = new Youtube();
var express = require('express');
var router = express.Router();
var word = '백종원'; // 검색어 지정
var limit = 10; // 출력 갯수
var video = [];
var test = 'test';
var count = 0;
youtube.setKey('AIzaSyCAaeW1qMSInEdN1OzU20FZlToIZYkb1bc'); // API 키 입력
youtube.addParam('order', 'rating'); // 평점 순으로 정렬
youtube.addParam('type', 'video'); // 타입 지정
youtube.addParam('videoLicense', 'creativeCommon'); // 크리에이티브 커먼즈 아이템만 불러옴
youtube.search(word, limit, function (err, result) {
// 검색 실행
if (err) {
console.log(err);
} // 에러일 경우 에러공지하고 빠져나감
//console.log(JSON.stringify(result, null, 2)); // 받아온 전체 리스트 출력
var items = result['items']; // 결과 중 items 항목만 가져옴
for (var i in items) {
var it = items[i];
for (var j in it) {
if (it[j]['title'] != null) {
var title = it[j]['title'];
}
if (it[j]['videoId'] != null) {
var video_id = it[j]['videoId'];
}
var urls = 'https://www.youtube.com/watch?v=' + video_id;
}
var item = {
id: count,
title: title,
video_id: video_id,
urls: urls,
};
count++;
video.push(item);
}
});
router.get('/', function (req, res) {
res.render(
'home',
{ videos: video } // DB에서 받은 videos를 videos변수명으로 내보냄
);
});
module.exports = router;
var express = require('express');
var CategoriModel = require('../models/CategoriModel');
var VideoModel = require('../models/VideoModel');
var router = express.Router();
router.get('/', function (req, res) {
CategoriModel.find(function (err, category) {
VideoModel.find(function (err, video) {
var item = []; // 카테고리별 비디오 목록을 담아두는 배열
for (var i in category) {
var videos = []; // 비디오 목록을 담는 임시 배열
for (var j in video) {
if (category[i].title == video[j].categori) {
videos.push(video[j]);
}
}
if (videos.length != 0) {
// 빈 배열 체크
//console.log(videos);
var items = {
category: category[i],
videos: videos,
};
item.push(items);
}
}
//console.log(item[2].category.title);
//console.log(item[2].videos);
res.render(
'home',
{ video: item, categories: category } // DB에서 받은 videos와 category를 videos변수명으로 내보냄
);
});
});
});
module.exports = router;
var express = require('express');
var router = express.Router();
var UserModel = require('../models/UserModel');
var passwordHash = require('../libs/passwordHash');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
passport.serializeUser(function (user, done) {
console.log('serializeUser');
done(null, user);
});
passport.deserializeUser(function (user, done) {
var result = user;
result.password = "";
console.log('deserializeUser');
done(null, result);
});
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField : 'password',
passReqToCallback : true
},
function (req, username, password, done) {
UserModel.findOne({ username : username , password : passwordHash(password) }, function (err,user) {
if (!user){
return done(null, false, { message: '아이디 또는 비밀번호 오류 입니다.' });
}else{
return done(null, user );
}
});
}
));
router.get('/', function(req, res){
res.send('account app');
});
router.get('/join', function(req, res){
res.render('accounts/join');
});
router.post('/join', function(req, res){
var User = new UserModel({
username : req.body.username,
password : passwordHash(req.body.password),
displayname : req.body.displayname
});
User.save(function(err){
res.send('<script>alert("회원가입 성공");location.href="/accounts/login";</script>');
});
});
router.get('/login', function(req, res){
res.render('accounts/login', { flashMessage : req.flash().error });
});
router.post('/login' ,
passport.authenticate('local', {
failureRedirect: '/accounts/login',
failureFlash: true
}),
function(req, res){
res.send('<script>alert("로그인 성공");location.href="/";</script>');
}
);
router.get('/success', function(req, res){
res.send(req.user);
});
router.get('/logout', function(req, res){
req.logout();
res.redirect('/accounts/login');
});
module.exports = router;
\ No newline at end of file
var express = require('express');
var router = express.Router();
var UserModel = require('../models/UserModel');
var passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (user, done) {
done(null, user);
});
passport.use(
new GoogleStrategy(
{
clientID:
'912554148550-gq86jjjgc022b1eit50mboh5lq48covi.apps.googleusercontent.com',
clientSecret: '_EzuXeN7eNCTbcGQUV4kY1pN',
callbackURL: 'http://localhost:3000/auth/google/callback',
profileFields: ['id', 'displayName', 'photos', 'email'], //받고 싶은 필드 나열
},
function (accessToken, refreshToken, profile, done) {
UserModel.findOne(
{ username: 'goo_' + profile.id },
function (err, user) {
if (!user) {
//없으면 회원가입 후 로그인 성공페이지 이동
var regData = {
//DB에 등록 및 세션에 등록될 데이터
username: 'goo_' + profile.id,
password: 'google_login',
displayname: profile.displayName,
};
var User = new UserModel(regData);
User.save(function (err) {
//DB저장
done(null, regData); //세션 등록
});
} else {
//있으면 DB에서 가져와서 세션등록
done(null, user);
}
}
);
}
)
);
router.get('/google', passport.authenticate('google', { scope: ['profile'] }));
//인증후 구글에서 이 주소로 리턴해줌. 상단에 적은 callbackURL과 일치
router.get(
'/google/callback',
passport.authenticate('google', {
failureRedirect: '/auth',
successRedirect: '/',
})
);
//로그인 성공시 이동할 주소
router.get('/google/success', function (req, res) {
res.send(req.user);
});
router.get('/google/fail', function (req, res) {
res.send('google login fail');
});
module.exports = router;
var express = require('express');
var router = express.Router();
var CategoriModel = require('../models/CategoriModel');
var VideoModel = require('../models/VideoModel');
var Youtube = require('youtube-node');
var youtube = new Youtube();
var loginRequired = require('../libs/loginRequired');
var redirectUrls = '';
var limit = 10; // 출력 갯수
youtube.setKey('AIzaSyCAaeW1qMSInEdN1OzU20FZlToIZYkb1bc'); // API 키 입력
router.get('/', function (req, res) {
res.send('categori main page');
});
router.get('/products', function (req, res) {
CategoriModel.find(function (err, products) {
console.log(products);
res.render(
'category/products',
{ categories: products }
//ProductModel의 products를 받아서
//categori/products로 response를 보낸다.
);
});
});
router.get('/categories/write', loginRequired, function (req, res) {
res.render('category/form', { categories: '' });
});
router.post('/categories/write', loginRequired, function (req, res) {
var category = new CategoriModel({
title: req.body.title,
description: req.body.description,
username: req.user.displayname,
});
//
var validationError = category.validateSync();
if (validationError) {
res.send(validationError);
} else {
category.save(function (err) {
res.redirect('/categori/products');
});
}
//
});
router.get('/products/detail/:id', function (req, res) {
//url 에서 변수 값을 받아올때 req.params.id 로 받아온다
var word = req.query.keyword;
redirectUrls = req.params.id;
CategoriModel.findOne({ _id: req.params.id }, function (err, product) {
var video = [];
//제품정보를 받고 그안에서 댓글을 받아온다.
CategoriModel.find({ product_id: req.params.id }, function (err, comments) {
VideoModel.find(function (err, myVideo) {
var mitem = []; // 카테고리별 비디오 목록을 담아두는 배열
var videos = []; // 비디오 목록을 담는 임시 배열
for (var j in myVideo) {
if (product.title == myVideo[j].categori) {
var k = {
title: myVideo[j].title,
id: myVideo[j]._id,
};
videos.push(k);
}
}
if (videos.length != 0) {
// 빈 배열 체크
//console.log(videos);
var items = videos;
mitem.push(items);
}
//console.log(item[2].category.title);
//console.log(item[2].videos);
if (word != null) {
var count = 0;
youtube.addParam('order', 'rating'); // 평점 순으로 정렬
youtube.addParam('type', 'video'); // 타입 지정
youtube.addParam('videoLicense', 'creativeCommon'); // 크리에이티브 커먼즈 아이템만 불러옴
youtube.search(word, limit, function (err, result) {
// 검색 실행
//console.log(word);
if (err) {
console.log(err);
} // 에러일 경우 에러공지하고 빠져나감
//console.log(JSON.stringify(result, null, 2)); // 받아온 전체 리스트 출력
var items = result['items']; // 결과 중 items 항목만 가져옴
for (var i in items) {
var it = items[i];
for (var j in it) {
if (it[j]['title'] != null) {
var title = it[j]['title'];
}
if (it[j]['videoId'] != null) {
var video_id = it[j]['videoId'];
}
var urls = 'https://www.youtube.com/watch?v=' + video_id;
}
var item = {
id: count,
title: title,
video_id: video_id,
urls: urls,
categori: product.title,
};
count++;
video.push(item);
}
res.render('category/productsDetail', {
product: product,
comments: comments,
videos: video,
items: mitem,
});
});
} else {
//console.log(mitem);
res.render('category/productsDetail', {
product: product,
comments: comments,
videos: video,
items: mitem,
});
}
});
});
});
});
router.post('/products/detail/:id', loginRequired, function (req, res) {
var item = [];
var count = 1;
var temp = '';
console.log(req.body.videoNum.length);
if (req.body.videoNum.length > 30) {
for (var i in req.body.videoNum) {
temp += req.body.videoNum[i];
}
item.push(temp.split('///'));
var video = new VideoModel({
categori: item[0][2],
id: count,
title: item[0][1],
video_id: item[0][3],
urls: item[0][4],
});
var validationError = video.validateSync();
if (validationError) {
res.send(validationError);
} else {
video.save(function (err) {});
}
count++;
} else {
for (var i in req.body.videoNum) {
item.push(req.body.videoNum[i].split('///'));
var video = new VideoModel({
categori: item[i][2],
id: count,
title: item[i][1],
video_id: item[i][3],
urls: item[i][4],
});
var validationError = video.validateSync();
if (validationError) {
res.send(validationError);
} else {
video.save(function (err) {});
}
count++;
}
}
res.redirect('/categori/products/detail/' + req.params.id);
});
router.get('/products/edit/:id', loginRequired, function (req, res) {
//기존에 폼에 value안에 값을 셋팅하기 위해 만든다.
CategoriModel.findOne({ _id: req.params.id }, function (err, product) {
res.render('category/form', {
categories: product,
});
});
});
router.post('/products/edit/:id', loginRequired, function (req, res) {
//그전에 지정되 있는 파일명을 받아온다
CategoriModel.findOne({ _id: req.params.id }, function (err, product) {
var query = {
name: req.body.name,
thumbnail: req.file ? req.file.filename : product.thumbnail,
price: req.body.price,
description: req.body.description,
};
CategoriModel.update(
{ id: req.params.id },
{ $set: query },
function (err) {
res.redirect('/categori/products/detail/' + req.params.id);
}
);
});
});
router.get('/products/delete/:id', function (req, res) {
CategoriModel.findOne({ _id: req.params.id }, function (err, products) {
CategoriModel.deleteMany({ _id: req.params.id }, function (err) {
VideoModel.find(function (err, myVideo) {
for (var i in myVideo) {
if (products.title == myVideo[i].categori) {
var deleteItem = myVideo[i].categori;
}
}
VideoModel.deleteMany({ categori: deleteItem }, function (err) {
res.redirect('/categori/products');
});
});
});
});
});
router.get('/products/detail/delete/:id', function (req, res) {
VideoModel.findOne({ _id: req.params.id }, function (err, products) {
VideoModel.deleteMany({ _id: products }, function (err) {
res.redirect('/categori/products/detail/' + redirectUrls);
});
});
});
router.post('/products/ajax_comment/insert', function (req, res) {
var comment = new CategoriModel({
content: req.body.content,
product_id: parseInt(req.body.product_id),
});
comment.save(function (err, comment) {
res.json({
id: comment.id,
content: comment.content,
message: 'success',
});
});
});
router.post('/products/ajax_comment/delete', function (req, res) {
CategoriModel.remove({ _id: req.body.comment_id }, function (err) {
res.json({ message: 'success' });
});
});
module.exports = router;
<% include ../includes/header.ejs %>
<div class="w-25 border border-info border-3" style="position: absolute; left: 37%; top: 17%;">
<div>
<div>
<div style="padding-top: 5%; padding-left: 5%;">
<h3 class="panel-title">회원가입</h3>
</div>
<div class="panel-body">
<form role="form" action="" id="join_form" method="post">
<fieldset>
<div class="w-100" style="padding-left: 5%; padding-right: 5%;">
<input class="form-control" placeholder="ID" name="username" type="text" autofocus="" required="">
</div>
<div class="w-100" style="padding-left: 5%; padding-right: 5%;padding-top: 3%">
<input class="form-control" placeholder="Password" name="password" type="password" value="" required="">
</div>
<div class="w-100" style="padding-left: 5%; padding-right: 5%;padding-top: 3%">
<input class="form-control" placeholder="Password 확인" name="password2" type="password" value="" required="">
</div>
<div class="w-100" style="padding-left: 5%; padding-right: 5%;padding-top: 3%">
<input class="form-control" placeholder="이름" name="displayname" type="text" value="" required="">
</div>
<!-- Change this to a button or input when using this as a form -->
<div class="d-grid gap-2 col-11 mx-auto p-2">
<input type="submit" class="btn btn-lg btn-success btn-block" value="가입하기">
<a href="/auth/google" class="btn btn-lg btn-danger btn-block">
<i class="fa fa-google" aria-hidden="true"></i> Google 회원가입
</a>
</div>
</fieldset>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript">
(function(){
$(document).ready(function() {
$('#join_form').submit(function(){
var $usernameInput = $('#join_form input[name=username]');
var $passwordInput = $('#join_form input[name=password]');
var $passwordInput2 = $('#join_form input[name=password2]');
var $displayname = $('#join_form input[name=displayname]');
if(!$usernameInput.val()){
alert("아이디를 입력해주세요.");
$usernameInput.focus();
return false;
}
if(!$passwordInput.val()){
alert("패스워드를 입력해주세요.");
$passwordInput.focus();
return false;
}
if(!$passwordInput2.val()){
alert("확인 패스워드를 입력해주세요.");
$passwordInput2.focus();
return false;
}
if(!$displayname.val()){
alert("이름을 입력해주세요.");
$displayname.focus();
return false;
}
if($passwordInput.val() !== $passwordInput2.val()){
alert("패스워드와 확인용패스워드를 똑같이 입력해주세요.");
return false;
}
return true;
});
});
})();
</script>
<% include ../includes/footer.ejs %>
\ No newline at end of file
<% include ../includes/header.ejs %>
<div class="w-25 border border-info border-3" style="position: absolute; left: 37%; top: 17%;">
<div>
<%if(typeof flashMessage !=='undefined') {%>
<div class="alert alert-danger" role="alert"><%=flashMessage%></div>
<%}%>
<div>
<div style="padding-top: 5%; padding-left: 5%;">
<h3 class="panel-title">로그인</h3>
</div>
<div class="panel-body">
<form role="form" action="" id="login_form" method="post">
<fieldset>
<div class="w-100" style="padding-left: 5%; padding-right: 5%;">
<label for="login" class="form-label">ID</label>
<input class="form-control" placeholder="ID" name="username" type="text" autofocus="" required="">
</div>
<div class="w-100 p-3">
<label for="password" class="form-label">Password</label>
<input class="form-control" placeholder="Password" name="password" type="password" value="" required="">
</div>
<!-- Change this to a button or input when using this as a form -->
<div class="d-grid gap-2 col-11 mx-auto p-2">
<input type="submit" class="btn btn-lg btn-success btn-block" value="로그인">
<a href="/auth/google" class="btn btn-lg btn-danger btn-block">
<i class="fa fa-google" aria-hidden="true"></i> Google 로그인
</a>
</div>
</fieldset>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript">
(function(){
$(document).ready(function() {
$('#login_form').submit(function(){
var $usernameInput = $('#login_form input[name=username]');
var $passwordInput = $('#login_form input[name=password]');
if(!$usernameInput.val()){
alert("아이디를 입력해주세요.");
$usernameInput.focus();
return false;
}
if(!$passwordInput.val()){
alert("패스워드를 입력해주세요.");
$passwordInput.focus();
return false;
}
return true;
});
});
})();
</script>
<% include ../includes/footer.ejs %>
\ No newline at end of file
<% include ../includes/header.ejs %>
<form action="" method="post" >
<table class="table table-bordered">
<tr>
<th>카테고리명</th>
<td><input type="text" name="title" class="form-control" value="<%=categories.title%>"/></td>
</tr>
<tr>
<th>설명</th>
<td><input type="text" name="description" class="form-control" value="<%=categories.description%>"/></td>
</tr>
</table>
<input type="submit" name="submit" value="완료" class="btn btn-primary">
</form>
<% include ../includes/footer.ejs %>
\ No newline at end of file
<% include ../includes/header.ejs %>
<table class="table table-bordered table-hover">
<tr class="table-info">
<th width="80px" style="text-align: center;">카테고리명</th>
<th width="50px" style="text-align: center;">개설 날짜</th>
<th width="550px" style="text-align: center;">내용</th>
<th width="50px" style="text-align: center;">사용자명</th>
<th width="30px" style="text-align: center;">삭제</th>
</tr>
<%categories.forEach(function(product){%>
<tr>
<td style="text-align: center;">
<a href="/categori/products/detail/<%=product.id%>"><%=product.title%></a>
</td>
<td style="text-align: center;" >
<%=product.getDate.year%> -
<%=product.getDate.month%> -
<%=product.getDate.day%>
</td>
<td>
<%=product.description%>
</td>
<td style="text-align: center;">
<%=product.username%>
</td>
<td style="text-align: center;">
<a href="/categori/products/delete/<%=product.id%>" class="btn btn-danger" onclick="return confirm('삭제하시겠습니까?')">삭제</a>
</td>
</tr>
<% }); %>
</table>
<a href="/categori/categories/write" class="btn btn-primary">작성하기</a>
<% include ../includes/footer.ejs %>
\ No newline at end of file
<% include ../includes/header.ejs %>
<div class="panel panel-default">
<div class="panel-heading">
 <h2 style="padding-left: 30px;"><%=product.title%></h2>
<div style="padding-bottom: 10px;">  
작성일 :
<%=product.getDate.year%> -
<%=product.getDate.month%> -
<%=product.getDate.day%>
</div>
<div style="padding-left: 30px">
설명 : <%=product.description%>
</div>
<hr/>
</div>
<div>
<% var count=0; %>
<% if (items.length != 0) { %>
<ul class="list-group" style="padding-left: 30px; padding-bottom: 30px;">
<li class="list-group-item list-group-item-info" aria-current="true">보유중인 영상</li>
<% for (var i in items[0]) { %>
<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>
<%count++;};%>
</ul>
<%};%>
</div>
<button style="margin-left: 30px; margin-bottom: 10px;" class="btn btn-outline-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseExample"
aria-expanded="false" aria-controls="collapseExample">
영상 추가하기
</button>
<div class="collapse show" id="collapseExample" style="padding-left: 30px;">
<div class="card card-body">
<form method="get" action="">
<div class="input-group" style="padding-left: 10px;">
<input type="text" class="form-control" placeholder="검색 키워드를 입력하세요!" name="keyword" autocomplete='off'>
<span class="input-group-btn">
<button class="btn btn-secondary" type="submit">찾기</button>
</span>
</div>
</form>
<form method="post" action="">
<% for (var i in videos) { %>
<div style="float:left;
padding: 15px;
">
<input type="checkbox" name="videoNum" style="
position: absolute;
margin-top: 5px;
margin-left: 5px;
z-index: 4;
zoom:3.0;
"
value="<%=videos[i].id + '///' + videos[i].title +'///'+ videos[i].categori +'///'+ videos[i].video_id +'///'+ videos[i].urls%>" />
<div id="<%=videos[i].id%>" vid="<%=videos[i].video_id%>">
</div>
</div>
<%};%>
<button class="btn btn-primary" style="margin-top: 10px; margin-left: 10px;">영상담기</button>
</form>
</div>
</div>
<div class="panel-body">
<div>
<hr />
</div>
</div>
</div>
<div style="padding-bottom: 30px;">
<a href="/categori/products" class="btn btn-dark">목록으로</a>
<a href="/categori/products/edit/<%=product._id%>" class="btn btn-primary">수정</a>
</div>
<% include ../includes/footer.ejs %>
<script>
(function(){
// 영상 메모 구현 파트(아직 미구현)
$(document).ready(function() {
$('#commentForm').submit(function(){
var $contentVal = $(this).children('textarea[name=content]').val();
if($contentVal){
$.ajax({
url: '/admin/products/ajax_comment/insert',
type: 'POST',
data: $(this).serialize(),
})
.done(function(args) {
if(args.message==="success"){
$('#comment_area').append(
'<div>' + args.content +
" ( <a class='comment_delete' comment_id='"+ args._id +"'>삭제</a> ) </div>"
);
$('#commentForm textarea[name=content]').val("");
}
})
.fail(function(args) {
console.log(args);
});
}else{
alert('댓글 내용을 입력해주세요.')
}
return false;
});
});
})();
</script>
<script>
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
var players = [];
var videoIds = [];
for (var i = 0; i < 10; i++) {
players.push(String(i));
videoIds.push($('#' + i).attr('vid'));
}
function onYouTubeIframeAPIReady() {
for (var i = 0; i < videoIds.length; i++) {
player = new YT.Player(players[i], {
height: '360',
width: '640',
videoId: videoIds[i],
events: {
}
});
}
}
</script>
\ No newline at end of file
<% include ./includes/header.ejs %>
<div style="background-color:lavenderblush;">
<h2 style="padding: 30px;">Categories</h2>
<% var count = 0; var collapseCount = 'less';%>
<center>
<div class="accordion w-85" id="accordionExample" style="padding-bottom: 20px;">
<% for (var i in video) { %>
<div class="accordion-item" style="margin: 20px;">
<h2 class="accordion-header" id="<%=video[i].category.title%>">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#<%=collapseCount%>"
aria-expanded="true" aria-controls="<%=collapseCount%>" style ="padding-top: 30px">
<%=video[i].category.title%>
</button>
</h2>
<div id="<%=collapseCount%>" data-bs-parent="#accordionExample" class="accordion-collapse collapse" aria-labelledby="<%=video[i].category.title%>">
<div class="accordion-body">
<% for (var j in video[i].videos) { %>
<div class="card" style="width: 55rem; margin-bottom: 15px; margin-top: 15px;">
<div class="card-top" id="<%=count%>" vid="<%=video[i].videos[j].video_id%>" style="margin: 30px;">
</div>
<div class="card-body">
<h5 class="card-title"><%=video[i].videos[j].title%></h5>
<p class="card-text">해당 영상에 대한 메모를 여기에 출력.
</p>
</div>
</div>
<%count++;}; %>
</div>
</div>
</div>
<%collapseCount = collapseCount+ "le";%>
<%};%>
</div>
</center>
</div>
<style type="text/css">
.masonry-grid img {
max-width: 260px;
}
</style>
<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/jquery.imagesloaded/4.1.1/imagesloaded.pkgd.min.js"></script>
<script type="text/javascript">
var $masonry_container = $('#masonry_container');
$masonry_container.imagesLoaded(function () {
$masonry_container.masonry({
itemSelector: '.masonry-grid',
columnWidth: 270
});
});
</script>
<script>
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
var players = [];
var videoIds = [];
for (var i = 0; i < 30; i++) {
players.push(String(i));
videoIds.push($('#' + players[i]).attr('vid'));
}
function onYouTubeIframeAPIReady() {
for (var i = 0; i < videoIds.length; i++) {
player = new YT.Player(players[i], {
height: '450',
width: '800',
videoId: videoIds[i],
});
}
}
</script>
<% include ./includes/footer.ejs %>
\ No newline at end of file
</div>
</body>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>MYCOOK</title>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!--bootstrap js 추가 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4"
crossorigin="anonymous"></script>
</head>
<body>
<div class="container-fluid" style="margin-top: 15px;">
<nav class="navbar navbar-light" style="background-color: #e3f2fd;">
<div>
<div class="navbar-brand" style="float: left;">
<a href="/" class="nav-link">MyCookBook</a>
</div>
<div class="navbar">
<ul class="nav">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item"><a class="nav-link" href="/categori/products">Category</a></li>
<% if(isLogin){%>
<li class="nav-item"><a class="nav-link" href="/accounts/logout" onclick="return confirm('로그아웃 하시겠습니까?')">LOGOUT</a></li>
<%}else{%>
<li class="nav-item"><a class="nav-link" href="/accounts/join">SignUp</a></li>
<li class="nav-item"><a class="nav-link" href="/accounts/login">LOGIN</a></li>
<%}%>
</ul>
</div>
</div>
</nav>
<hr style=" border: 2px solid #4263eb" />