박유빈

login, signup success!

......@@ -84,10 +84,10 @@ app
});
router.get('/about', async ctx =>{
ctx.render('home/about');
await ctx.render('home/about');
});
router.get('/auth', async ctx =>{
ctx.render('users/login');
await ctx.render('users/login');
});
//router.use('/', api.routes());
......
......@@ -8,7 +8,7 @@ const bookSchema = new Schema({
pages:[{type:mongoose.Schema.Types.ObjectId, ref:'page', required:false}],//book contains several pages. pages is the list of page id
title: {type:String, require:true}, // book title
author: [{type:mongoose.Schema.Types.ObjectId, ref:'user', required:true}],//작가복수 가능
contents: {type:String}, // book subtitle or detail
contents: [{type:String}], // book subtitle or detail
createDate: {type:Date, require:true, default:Date.now},
updateDate: {type:Date, default:Date.now},
views: {type: Number, default: 0},//how many people open this book
......
......@@ -3,6 +3,7 @@ var Schema = mongoose.Schema;
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const crypto = require('crypto');
const { exist, allow } = require('@hapi/joi');
//const Pet = require("./pet");
const UserSchema = new Schema({
......
......@@ -237,3 +237,7 @@ input[type="password"] {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.user-form {
width: 400px;
}
\ No newline at end of file
......
......@@ -2,15 +2,18 @@ const Router = require("@koa/router");
const checkLoggedIn = require("../../src/lib/checkLoggedIn");
//const bookCtrl = require("./book.ctrl");
const book = new Router();
const User = require("../models/user")
const User = require("../models/user");
const Book = require("../models/book");
const Joi = require('@hapi/joi');
//북id params로 전달. Render books/show
book.get('/:id', async (ctx) => {
const bookid = ctx.params.id;//bookid by parameter
console.log(bookid);
try {
const book = await Book.findOne({_id:ctx.params.id});
ctx.render('books/show', {book});
const page = await Page.findById(book.pages);
const user = await User.findById(book.author).exec();
await ctx.render('books/show', {book,user,page});
//ctx.body.authorname = user.nickname;
//ctx.body = mybook;
} catch (e) {
......@@ -55,7 +58,7 @@ book.post('/',checkLoggedIn,async (ctx) => {
if (err) throw err;
const user = await User.findById(ctx.state.user._id).exec();
console.log(book._id);
ctx.redirect('/books');
await ctx.redirect('/books');
});
} catch (e) {
ctx.throw(500, e);
......@@ -127,7 +130,7 @@ book.delete('/:id',checkLoggedIn,async (ctx) => {
book.get('/',async (ctx) => {
try {
const books = await Book.find({}).sort({createDate: -1}).exec();
ctx.render('books/index', {books:books});
await ctx.render('books/index', {books:books});
} catch (e) {
return ctx.throw(500, e);
}
......@@ -149,6 +152,21 @@ book.get('/search', async (ctx) => {
});
book.get('/new', async (ctx) => {
ctx.render('books/new');
try{
await ctx.render('books/new');
}catch(e){
ctx.throw(500, e);
}
});
//test용
book.get('/booklist',async (ctx) => {
try {
const books = await Book.find({}).sort({createDate: -1}).exec();
ctx.body = books;
} catch (e) {
return ctx.throw(500, e);
}
}
);
module.exports = book;
\ No newline at end of file
......
const Router = require("@koa/router");
const checkLoggedIn = require("../../src/lib/checkLoggedIn");
// const pageCtrl = require("./page.ctrl");
const Joi = require('@hapi/joi');
const page = new Router();
const Page = require("../models/page");
const User = require("../models/user");
//const index = require('../../../src/index');
//const render = require('koa-ejs');
//Page api
......@@ -23,22 +24,37 @@ page.post('/:id', pageCtrl.detailPage); // detail recipe page
// /recipe/scroll?filter=filter_query&renewal=count (filter_query: 추천순 or 조회순)
page.get('/recipe/scroll', pageCtrl.scrollPage); // video list sorted by 추천순 or 조회순 in main page
*/
//For test
page.get('/pagelist', async (ctx) => {
try{
const page = await Page.find({}).sort({createDate:-1}).exec();
ctx.body = page;
}catch(e){
ctx.throw(500, e);
}
});
page.get('/tset', async (ctx) => {
console.log('testtest');
});
page.get('/', async (ctx) => {
try{
const page = await Page.find({}).sort({createDate:-1}).exec();
console.log(page);
await ctx.render('posts/index', {page});
}catch(e){
ctx.throw(500, e);
}
});
page.get('/new', async (ctx) => {
try{
await ctx.render('posts/new');
}catch(e){
ctx.throw(500, e);
}
});
// create
......@@ -73,7 +89,7 @@ page.get('/tset', async (ctx) => {
if (err) throw err;
const user = await User.findById(ctx.state.user._id).exec();
console.log(book._id);
ctx.redirect('/page');
await ctx.redirect('/page');
});
} catch (e) {
ctx.throw(500, e);
......@@ -81,7 +97,7 @@ page.get('/tset', async (ctx) => {
console.log('저장 성공!');
ctx.status = 200;
ctx.redirect('/page');
await ctx.redirect('/page');
});
......@@ -91,7 +107,8 @@ page.get('/tset', async (ctx) => {
try{
var id = ctx.params.id;
const page = await Page.findById(id).exec();
await ctx.render('posts/show', {page:page});
const user = await User.findById(page.author).exec();
await ctx.render('posts/show', {page:page,user:user});
ctx.status = 200;
}catch(e){
ctx.throw(500,e);
......@@ -113,10 +130,10 @@ page.patch('/:id',checkLoggedIn, async (ctx, next) => {
try {
const mypage = await Page.findOne({ _id: id });//require page's _id
if(ctx.state.user._id == mypage.author){
mypage.updateP(page);
await mypage.updateP(page);
console.log(mypage);
ctx.redirect("/page/"+id);
await ctx.redirect("/page/"+id);
ctx.status = 200;}
} catch (e) {
......@@ -129,8 +146,8 @@ page.patch('/:id',checkLoggedIn, async (ctx, next) => {
// destroy
page.delete('/:id', async (ctx, next) => {
try{
await Page.deleteOne({_id:ctx.params.id})
ctx.redirect('/page');
const page = await Page.deleteOne({_id:ctx.params.id})
//await ctx.redirect('/page');
}catch(e){
ctx.throw(500, e);
}
......
......@@ -6,41 +6,12 @@ const checkLoggedIn = require("../../src/lib/checkLoggedIn");
const User = require("../models/user");
//var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const auth = new Router();
// 회원가입- 로컬 이메일 인증번호 발송 POST auth/signup/email/demand
// 회원가입 이메일 인증번호 확인 POST auth/signup/email/verify
// 로그인 "소셜 로그인
// (페이스북 구글 네이버 카카오)" POST auth/signin/social
// 회원정보갱신 설문이나 설정에서 개인정보 바꾸면 적용 PATCH auth/update/pet
// 회원정보갱신 설문이나 설정에서 개인정보 바꾸면 적용 PATCH auth/update/user
const nodemailer = require('nodemailer');
const config = require('../lib/config');
const Joi = require('@hapi/joi');
/*
auth.get('/userlist', authCtrl.userlist);
auth.get('/test', authCtrl.test);
auth.post('/signup', authCtrl.signupLocal);
auth.post('/signin', authCtrl.signinLocal);
auth.get('/signout',checkLoggedIn, authCtrl.signout);
auth.get('/check', authCtrl.check2);
auth.delete('/user',checkLoggedIn,authCtrl.Withdrawal); // 회원 탈퇴
auth.post('/validate', authCtrl.exists);
auth.post('/checkpassword', authCtrl.checkPassword);
auth.get('/book',checkLoggedIn,authCtrl.getUserBook);
auth.get('/user', checkLoggedIn,authCtrl.userinfo); // show user information
auth.patch('/user', checkLoggedIn, authCtrl.updateUser); // modify user information
auth.patch('/user/password', authCtrl.changePassword); // change password
auth.post('/find/password', authCtrl.findPassword); // 비밀번호 찾기
auth.get('/favorite',checkLoggedIn, authCtrl.showFavorite); // show a list of user's favorites
auth.post('/favorite',checkLoggedIn, authCtrl.addFavorite); // add favorite
auth.delete('/favorite',checkLoggedIn, authCtrl.delFavorite); // delete favorite
auth.post('/find/password', authCtrl.findPassword); // 비밀번호 찾기
*/
auth.get('/new', async (ctx) => {
ctx.render('users/new');
});
auth.get('/test', async (ctx) => {
ctx.render('users/login');
});
*/
// show
......@@ -61,6 +32,13 @@ auth.get('/login', async (ctx) => {
});
auth.get('/new', async (ctx) => {
try{
await ctx.render('users/new');
}catch(e){
console.log(e);
}
});
// edit
auth.get('/:id/edit', async (ctx) => {
......@@ -74,9 +52,9 @@ auth.get('/login', async (ctx) => {
const errors ='';
//handle error
if (!email || !password) {
ctx.status = 401; //Unauthorized
errors= '비밀번호, 이메일 중 하나가 틀렸습니다. '
return;
//Unauthorized
alert( '비밀번호, 이메일 중 하나가 틀렸습니다. ');
await ctx.redirect('/auth/login');
}
try {
//const user = User.findOne({ email: email });
......@@ -100,6 +78,7 @@ auth.get('/login', async (ctx) => {
httpOnly: false,
});
ctx.status = 200;
ctx.state.user = user;
ctx.redirect('/page');
console.log('토큰나옴, 로그인');
} catch (e) {
......@@ -149,42 +128,105 @@ auth.get('/login', async (ctx) => {
} catch (e) {
ctx.throw(500, e);
}
ctx.cookies.set('access_token', token, { maxAge: 1000 * 60 * 60 * 24 * 7 ,httpOnly: true,});
await ctx.cookies.set('access_token', token, { maxAge: 1000 * 60 * 60 * 24 * 7 ,httpOnly: true,});
console.log('set cookie ok');
// 응답할 데이터에서 hashedPassword 필드 제거
ctx.status = 200;
await ctx.render('users/new');
await ctx.render('users/show');
} catch (e) {
ctx.throw(500, e);
}});
// update // 2
auth.post('/:id', async (ctx) => {
await User.findOne({username:ctx.params.username}).select('password').exec();
// update user object
user.originalPassword = user.password;
user.password = ctx.body.newPassword? ctx.body.newPassword : user.password; // 2-3
for(var p in ctx.body) // 2-4
user[p] = ctx.body[p];
auth.patch('/:id', async (ctx) => {
const schema = Joi.object().keys({
// password: Joi.string().min(6).max(20).required(),
username: Joi.string().allow(null, ''),
phone: Joi.string().allow(null, ''),
nickname: Joi.string().allow(null, ''),
fcmToken: Joi.string(),
// birth: Joi.date()
});
try {
const value = await schema.validateAsync(ctx.request.body);
} catch (err) {
console.log(err);
ctx.status = 400;
return;
}
// save updated user
await user.save();
ctx.request.body.email = ctx.state.user.email;
ctx.redirect('/users/'+user.nickname);
try {
await User.updateUser(ctx.request.body);
} catch (e) {
ctx.throw(500, e);
}
ctx.status = 200;
await ctx.redirect('/users/'+user.nickname);
});
// destroy
auth.get('/logout', async (ctx) => {
ctx.cookies.set('access_token');
await ctx.cookies.set('access_token');
ctx.status = 204;
ctx.redirect('/');
await ctx.redirect('/');
});
function getRandomInt(min, max) { //min ~ max 사이의 임의의 정수 반환
return Math.floor(Math.random() * (max - min)) + min;
}
auth.post('/findPassword', async (ctx) => {
var status = 400;
// 전송 옵션 설정
// trainsporter: is going to be an object that is able to send mail
let transporter = nodemailer.createTransport({
service: 'gmail',
host: 'smtp.gmail.com',
// port: 587,
port: 465,
secure: true,
auth: {
user: config.mailer.user, //gmail주소입력
pass: config.mailer.password, //gmail패스워드 입력
},
});
var numsend = getRandomInt(100000,999999);
var mailOptions = {
from: `"Like project"<${config.mailer.user}>`, //enter the send's name and email
to: ctx.request.body.email, // recipient's email
subject: 'Like password', // title of mail
html: `안녕하세요, 글을 나누는 즐거움 Like 입니다.
<br />
인증번호는 다음과 같습니다. (임시)
<br />
${numsend}`,
};
try {
await transporter.sendMail(mailOptions, async function (error, info) {
if (error) {
ctx.status = 401;
return;
} else {
console.log('Email sent: ' + info.response);
ctx.body = { success: true };
status = 200;
}
});
} catch (e) {
ctx.throw(500, e);
}
ctx.status = 200;
});
module.exports = auth;
......
......@@ -24,10 +24,13 @@
</div>
<div class="form-group">
<label for="body">Body</label>
<textarea id="body" name="body" rows="5" class="form-control"></textarea>
<label for="contents">Body</label>
<textarea id="contents" name="contents" rows="5" class="form-control"></textarea>
</div>
<div class="form-group">
<label for="contents">Body</label>
<textarea id="contents" name="contents" rows="5" class="form-control"></textarea>
</div>
<div>
<a class="btn btn-primary" href="/api/book">Back</a>
<button type="submit" class="btn btn-primary">Submit</button>
......
......@@ -11,8 +11,8 @@
<nav aria-label="breadcrumb">
<ol class="breadcrumb p-1 pl-2 pr-2">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/api/page">Page</a></li>
<li class="breadcrumb-item active" aria-current="page"><%= book.title %></li>
<li class="breadcrumb-item"><a href="/page">Page</a></li>
<li class="breadcrumb-item active" aria-current="book"><%= book.title %></li>
</ol>
</nav>
......@@ -37,9 +37,9 @@
</div>
<div class="mt-3">
<a class="btn btn-primary" href="/api/book">Back</a>
<a class="btn btn-primary" href="/api/book/<%= book._id %>/edit">Edit</a>
<form action="/api/book/<%= book._id %>?_method=delete" method="post" class="d-inline">
<a class="btn btn-primary" href="/book">Back</a>
<a class="btn btn-primary" href="/book/<%= book._id %>/edit">Edit</a>
<form action="/book/<%= book._id %>?_method=delete" method="post" class="d-inline">
<a class="btn btn-primary" href="javascript:void(0)" onclick="confirm('Do you want to delete this?')?this.parentElement.submit():null;">Delete</a>
</form>
</div>
......
......@@ -12,6 +12,8 @@
<P>이 사이트는 Like Project 임시 페이지 입니다. </p>
</div>
</body>
</html>
\ No newline at end of file
......
......@@ -17,7 +17,7 @@
<div class="container">
<div class="wrapper">
<form action="/auth/login" method="post" name="Login_Form" class="form-signin">
<h3 class="form-signin-heading">Welcome! Please Sign In</h3>
<h3 class="form-signin-heading">안녕하세요. 로그인 부탁드립니다.</h3>
<input type="text" class="form-control" name="email" placeholder="Email Address" required="" autofocus="" />
<input type="password" class="form-control" name="password" placeholder="Password" required=""/>
......@@ -25,6 +25,15 @@
<button class="btn btn-lg btn-primary btn-block" name="Submit" value="Login" type="Submit">Login</button>
</form>
</div>
<form action="/auth/findPassword" method="post">
<a href="/auth/findPassword">비밀번호를 까먹으셨나요?</a>
<div class="form-group">
<label for="title">이메일을 적으시면 메일이 갑니다. </label>
<input type="text" id="email" name="email" class="form-control">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</body>
</html>
\ No newline at end of file
......
......@@ -10,7 +10,7 @@
<div class="jumbotron">
<h1>My Website</h1>
<P>제 웹사이트를 방문해 주셔서 감사합니다!</p>
<P>Like Proejct 입니다. 방문해 주셔서 감사합니다!</p>
</div>
</div>
......
......@@ -15,6 +15,7 @@
<li class="nav-item"><a href="/auth/new" class="nav-link">Sign Up</a></li>
<li class="nav-item"><a href="/auth/login" class="nav-link">Login</a></li>
<li class="nav-item"><a href="/auth/logout" class="nav-link">Logout</a></li>
</ul>
</div>
......
......@@ -30,11 +30,12 @@
<% page.forEach(function(page) { %>
<tr>
<td>
<a href="/page/<%= page._id %>"><div class="ellipsis"><%= page.title %></div></a>
<a href="/page/<%= page._id %>"><div class="ellipsis"><%= page.title %> author:<%= page.author.email %></div></a>
</td>
<td class="date">
<span data-date="<%= page.createDate %>"></span> <!-- 1 -->
</td>
<a href="/auth/<%= page.author._id %>"><div class="ellipsis"><%= page.author.nickname %></div></a>
</tr>
<% }) %>
</tbody>
......
......@@ -20,6 +20,7 @@
<div class="card">
<h5 class="card-header p-2"><%= page.title %></h5>
<h3 class="card-header p-2"><%= user.nickname %><%= user.email%></h3>
<div class="row"> <!-- 1 -->
<div class="col-md-7 col-lg-8 col-xl-9 order-sm-2 order-md-1"> <!-- 1 -->
......
<!DOCTYPE html>
<html>
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<h3 class="mb-3">Users</h3>
<ul class="list-group">
<% if(users == null || users.length == 0){ %>
<li class="list-group-item"> There is no user yet.</li>
<% } %>
<% users.forEach(function(user) { %>
<li class="list-group-item">
<a href="/users/<%= user.username %>"><%= user.username %></a>
</li>
<% }) %>
</ul>
</div>
</body>
</html>
\ No newline at end of file
......
......@@ -12,10 +12,10 @@
<h3 class="contentBoxTop mb-3">New User</h3>
<form action="/auth/signin" method="post">
<form action="/auth/signup" method="post">
<div class="form-group row">
<label for="nickname" class="col-sm-3 col-form-label">Username*</label>
<label for="nickname" class="col-sm-3 col-form-label">Nickanme*</label>
<div class="col-sm-9">
<input type="text" id="nickname" name="nickname" value="" class="form-control">
</div>
......@@ -32,12 +32,7 @@
<input type="password" id="password" name="password" value="" class="form-control">
</div>
</div>
<div class="form-group row">
<label for="passwordConfirmation" class="col-sm-3 col-form-label">Password Confirmation*</label>
<div class="col-sm-9 col-sm-offset-3">
<input type="password" id="passwordConfirmation" name="passwordConfirmation" value="" class="form-control">
</div>
</div>
<p>
<small>*Required</small>
</p>
......
......@@ -12,13 +12,19 @@
<h3 class="contentBoxTop">usefname</h3>
<form class="user-form" action="/users" method="post">
<fieldset disabled>
<div class="form-group row">
<label for="name" class="col-sm-3 col-form-label">Name</label>
<div class="col-sm-9">
<input class="form-control" type="text" id="name" name="name" value="<%= user.name %>">
</div>
</div>
<div class="form-group row">
<label for="email" class="col-sm-3 col-form-label">Email</label>
<div class="col-sm-9">
<input class="form-control" type="text" id="email" name="email" value="<%= 9 %>">
<input class="form-control" type="text" id="email" name="email" value="<%= user.email %>">
</div>
</div>
</fieldset>
......