Skip to content
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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions homeworks/week17/hw1/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
98 changes: 98 additions & 0 deletions homeworks/week17/hw1/controllers/Articles.js
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的帳號 ,用解構語法拿出來的
Comment on lines +6 to +16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

縮排不一致
我在猜可能是 tab 和 space 的差別,
你可能需要調整一下你的編輯器或者 IDE。

Copy link
Collaborator Author

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格為單位,有時候是四格,沒特別注意就會沒發現到又跳掉了。

Copy link
Contributor

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 可以用。

const {content} = req.body //從輸入框拿的
const {title} = req.body
if (!userId || !content) {
return res.redirect('/')
}

Articles.create({
title,
content,
UserId: userId
}).then(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以改用 async/await

res.redirect('/')
})
},

articlePage: async(req, res) => {
// id 本來就是 URL 的一部分,所以不用特地檢查
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

任何使用者傳進來的資訊都要檢查。

const { id } = req.params

Articles.findOne({
where: {
id: req.params.id,
Copy link
Contributor

Choose a reason for hiding this comment

The 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可以隨意竄改
Copy link
Contributor

Choose a reason for hiding this comment

The 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
Copy link
Contributor

Choose a reason for hiding this comment

The 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
Copy link
Contributor

Choose a reason for hiding this comment

The 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('/')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有錯誤直接回到首頁使用體驗不太好,
使用者會不知道發生什麼情況。

})
}
}

module.exports = articlesController
97 changes: 97 additions & 0 deletions homeworks/week17/hw1/controllers/user.js
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
Empty file removed homeworks/week17/hw1/index.html
Empty file.
61 changes: 61 additions & 0 deletions homeworks/week17/hw1/index.js
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',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

secret 不要用 hard code,
使用環境變數。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cwc329 抱歉助教,這邊的寫法是直接抄網路的方式,所以有點看不懂您提醒的意思,想請問不要用hard code是什麼意思。

Copy link
Contributor

@cwc329 cwc329 Apr 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://lidemy.com/courses/390625/lectures/24510405
環境變數可以參考這個影片。

簡單說你只要看到 secret, key 等關鍵字,所使用的值通常都是敏感資訊,
這種時候如果直接寫在 code 上傳到公開的 repository 是資安大漏洞,
所以這些變數就會用環境變數的方式引入,
使用起來會像這樣。

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}!`)
})
33 changes: 33 additions & 0 deletions homeworks/week17/hw1/migrations/20220401142423-create-user.js
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');
}
};
33 changes: 33 additions & 0 deletions homeworks/week17/hw1/migrations/20220401154601-create-articles.js
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');
}
};
26 changes: 26 additions & 0 deletions homeworks/week17/hw1/models/articles.js
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;
};
Loading