-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Week17 #18
base: master
Are you sure you want to change the base?
Week17 #18
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
const db = require('../models') | ||
const User = db.User | ||
const Articles = db.Articles | ||
|
||
const articlesController = { | ||
homePage: async(req, res) => { | ||
const articles = await Articles.findAll({ | ||
order: [['id', 'DESC']], | ||
include: User | ||
}) | ||
res.render('index', { | ||
articles | ||
}) | ||
}, | ||
add: (req, res) => { | ||
const {userId} = req.session //這從登入帳號存在session的帳號 ,用解構語法拿出來的 | ||
const {content} = req.body //從輸入框拿的 | ||
const {title} = req.body | ||
if (!userId || !content) { | ||
return res.redirect('/') | ||
} | ||
|
||
Articles.create({ | ||
title, | ||
content, | ||
UserId: userId | ||
}).then(() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 可以改用 async/await |
||
res.redirect('/') | ||
}) | ||
}, | ||
|
||
articlePage: async(req, res) => { | ||
// id 本來就是 URL 的一部分,所以不用特地檢查 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 任何使用者傳進來的資訊都要檢查。 |
||
const { id } = req.params | ||
|
||
Articles.findOne({ | ||
where: { | ||
id: req.params.id, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 上面已經解構了這邊可以直接用變數。 |
||
}, | ||
include: User | ||
}).then(article => { | ||
res.render('page/article_page', { | ||
article | ||
}) | ||
}) | ||
}, | ||
|
||
|
||
//這邊傳username是為了確認這個id是不是真的有這篇文章,不然id可以隨意竄改 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 身份驗證可以寫成 middleware 讓 add, update 等功能都可以使用。 |
||
delete: (req, res) => { | ||
Articles.findOne({ | ||
where: { | ||
id: req.params.id, | ||
UserId: req.session.userId | ||
} | ||
}).then(articles => { | ||
return articles.destroy() | ||
Comment on lines
+51
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 應該可以直接用 sequelize model 的刪除, |
||
}).then(() => { | ||
res.redirect('/') | ||
}).catch(() => { | ||
res.redirect('/') | ||
}) | ||
}, | ||
|
||
|
||
update: (req, res) => { | ||
Articles.findOne({ | ||
where: { | ||
id: req.params.id, | ||
} | ||
}).then(article => { | ||
res.render('update', { | ||
article | ||
}) | ||
}) | ||
}, | ||
|
||
//req.body.content 這邊是從view的form的 name來的 | ||
handleUpdate: (req, res) => { | ||
Articles.findOne({ | ||
where: { | ||
id: req.params.id, | ||
UserId: req.session.userId | ||
} | ||
}).then(article => { | ||
return article.update({ | ||
Comment on lines
+80
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 不用找到再更新。 |
||
title: req.body.title, | ||
content: req.body.content | ||
}) | ||
}).then(() => { | ||
res.redirect('/') | ||
}).catch(() => { | ||
res.redirect('/') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 有錯誤直接回到首頁使用體驗不太好, |
||
}) | ||
} | ||
} | ||
|
||
module.exports = articlesController |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
const bcrypt = require('bcrypt'); | ||
const saltRounds = 10; | ||
const db = require('../models') | ||
const User = db.User | ||
|
||
const userController = { | ||
|
||
login: (req, res) => { | ||
res.render('user/login') | ||
}, | ||
|
||
handleLogin: (req, res, next) => { | ||
const { username, password } = req.body | ||
if (!username || !password) { | ||
req.flash('errorMessage', '請輸入帳號或密碼') | ||
return next() | ||
} | ||
|
||
User.findOne({ | ||
where: { | ||
username | ||
} | ||
}).then(user => { | ||
if (!user) { | ||
req.flash('errorMessage', '使用者不存在') | ||
return next() | ||
} | ||
//使用者輸入的Password , 資料庫來的Password 看密碼有沒有正確 | ||
bcrypt.compare(password, user.password, function (err, isSuccess) { | ||
// res == true | ||
if (err || !isSuccess) { | ||
req.flash('errorMessage', '密碼錯誤') | ||
return next() | ||
} | ||
req.session.username = user.username | ||
req.session.userId = user.id | ||
|
||
res.redirect('/') | ||
}); | ||
|
||
}).catch(err => { | ||
req.flash('errorMessage', err.toString()) | ||
return next() | ||
}) | ||
|
||
}, | ||
|
||
register: (req, res) => { | ||
res.render('user/register') | ||
}, | ||
|
||
handleRegister: (req, res, next) => { | ||
const { username, password, nickname } = req.body | ||
if (!username || !password || !nickname) { | ||
return req.flash('errorMessage', '缺少必要欄位') | ||
} | ||
|
||
User.findOne({ | ||
where: { | ||
username | ||
} | ||
}).then(user => { | ||
if (user) { | ||
req.flash('errorMessage', '此帳號已被註冊') | ||
return next() | ||
} | ||
}) | ||
|
||
bcrypt.hash(password, saltRounds, function (err, hash) { | ||
if (err) { | ||
req.flash('errorMessage', err.toString()) | ||
return next() | ||
} | ||
|
||
User.create({ | ||
username, | ||
nickname, | ||
password: hash | ||
}).then(user => { | ||
req.session.username = username //新增username 之後直接是登入狀態所以把username存進session | ||
req.session.userId = user.id | ||
|
||
res.redirect('/') | ||
}).catch(err => { | ||
req.flash('errorMessage', err.toString()) | ||
return next() | ||
}) | ||
}); | ||
}, | ||
|
||
logout: (req, res) => { | ||
req.session.username = null | ||
res.redirect('/') | ||
} | ||
} | ||
|
||
module.exports = userController |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
const express = require("express") | ||
const bodyParser = require('body-parser') | ||
const session = require('express-session') | ||
const flash = require('connect-flash'); | ||
|
||
const app = express() | ||
const port = process.env.PORT || 5001 | ||
|
||
|
||
const userController = require('./controllers/user') | ||
const articlesController = require('./controllers/Articles') | ||
|
||
app.set('view engine','ejs') | ||
|
||
// app.use('/static', express.static(__dirname + '/public')); | ||
app.use(express.static(`${__dirname}/public`)) | ||
|
||
|
||
app.use(session({ | ||
secret: 'keyboard cat', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. secret 不要用 hard code, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @cwc329 抱歉助教,這邊的寫法是直接抄網路的方式,所以有點看不懂您提醒的意思,想請問不要用hard code是什麼意思。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://lidemy.com/courses/390625/lectures/24510405 簡單說你只要看到 secret, key 等關鍵字,所使用的值通常都是敏感資訊, app.use(session({
secret: process.env.SECRET
}); |
||
resave: false, | ||
saveUninitialized: true | ||
})) | ||
|
||
|
||
app.use(bodyParser.urlencoded({extended: false})) | ||
app.use(bodyParser.json()) | ||
app.use(flash()) | ||
|
||
|
||
app.use((req, res, next) => { | ||
res.locals.username = req.session.username | ||
res.locals.errorMessage = req.flash('errorMessage') | ||
next() | ||
}) | ||
|
||
app.get('/', articlesController.homePage) | ||
|
||
function redirectBack(req, res) { | ||
res.redirect('back') | ||
} | ||
|
||
app.get('/login', userController.login) | ||
app.post('/login', userController.handleLogin, redirectBack) | ||
app.get('/logout', userController.logout) | ||
|
||
app.get('/register', userController.register) | ||
app.post('/register', userController.handleRegister, redirectBack) | ||
|
||
app.post('/articles',articlesController.add) | ||
|
||
app.get('/article-page/:id', articlesController.articlePage) | ||
|
||
app.get('/delete_articles/:id', articlesController.delete) | ||
app.get('/update_articles/:id', articlesController.update) | ||
app.post('/update_articles/:id', articlesController.handleUpdate) | ||
|
||
|
||
app.listen(port, () => { | ||
console.log(`Example app listening on port ${port}!`) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
'use strict'; | ||
module.exports = { | ||
async up(queryInterface, Sequelize) { | ||
await queryInterface.createTable('Users', { | ||
id: { | ||
allowNull: false, | ||
autoIncrement: true, | ||
primaryKey: true, | ||
type: Sequelize.INTEGER | ||
}, | ||
username: { | ||
type: Sequelize.STRING | ||
}, | ||
password: { | ||
type: Sequelize.STRING | ||
}, | ||
nickname: { | ||
type: Sequelize.STRING | ||
}, | ||
createdAt: { | ||
allowNull: false, | ||
type: Sequelize.DATE | ||
}, | ||
updatedAt: { | ||
allowNull: false, | ||
type: Sequelize.DATE | ||
} | ||
}); | ||
}, | ||
async down(queryInterface, Sequelize) { | ||
await queryInterface.dropTable('Users'); | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
'use strict'; | ||
module.exports = { | ||
async up(queryInterface, Sequelize) { | ||
await queryInterface.createTable('Articles', { | ||
id: { | ||
allowNull: false, | ||
autoIncrement: true, | ||
primaryKey: true, | ||
type: Sequelize.INTEGER | ||
}, | ||
title: { | ||
type: Sequelize.STRING | ||
}, | ||
content: { | ||
type: Sequelize.TEXT | ||
}, | ||
createdAt: { | ||
allowNull: false, | ||
type: Sequelize.DATE | ||
}, | ||
updatedAt: { | ||
allowNull: false, | ||
type: Sequelize.DATE | ||
}, | ||
UserId: { | ||
type: Sequelize.INTEGER | ||
} | ||
}); | ||
}, | ||
async down(queryInterface, Sequelize) { | ||
await queryInterface.dropTable('Articles'); | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
'use strict'; | ||
const { | ||
Model | ||
} = require('sequelize'); | ||
module.exports = (sequelize, DataTypes) => { | ||
class Articles extends Model { | ||
/** | ||
* Helper method for defining associations. | ||
* This method is not a part of Sequelize lifecycle. | ||
* The `models/index` file will call this method automatically. | ||
*/ | ||
static associate(models) { | ||
// define association here | ||
Articles.belongsTo(models.User) | ||
} | ||
} | ||
Articles.init({ | ||
title: DataTypes.STRING, | ||
content: DataTypes.TEXT, | ||
UserId: DataTypes.INTEGER | ||
}, { | ||
sequelize, | ||
modelName: 'Articles', | ||
}); | ||
return Articles; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
縮排不一致
我在猜可能是 tab 和 space 的差別,
你可能需要調整一下你的編輯器或者 IDE。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cwc329 想請教助教,如果這時候用VSCODE自動排版快捷鍵,SHIFT ALT F 讓它自動排是好的縮排嗎?
因為排版問題其實有先調過了,但每次在寫新的一頁的時候又會跑掉,我都是按tab去寫,但有時候我的編輯器會跳2格為單位,有時候是四格,沒特別注意就會沒發現到又跳掉了。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我現在用的 IDE 不是 vscode,所以不太知道要怎麼用。
不過想要一致的話,JS 可以考慮用 eslint。
這樣只要規則一樣然後讓 eslint 自己 format 就可以保證一致了。
而且主流的編輯器以及 IDE 幾乎都有 eslint 的 plugin 可以用。