Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
146 commits
Select commit Hold shift + click to select a range
2f9c683
changed all test file name
AmberYen Oct 31, 2021
d3a66dd
remove R03/04/05 test
AmberYen Oct 31, 2021
e0dbcb6
remove R04/05 test
AmberYen Oct 31, 2021
5a83153
remove R05 test
AmberYen Oct 31, 2021
3a5beed
update cofig.json
Carrot7712 Nov 1, 2021
154a12e
fixed R01 ../../app issue & not found sequelize lib
AmberYen Nov 1, 2021
c3b664c
fixed R01 ../../app issue & not found sequelize lib
AmberYen Nov 1, 2021
67b9b32
fixed R01 ../../app issue & not found sequelize lib
AmberYen Nov 1, 2021
3e9b544
fixed R01 ../../app issue & not found sequelize lib
AmberYen Nov 1, 2021
3f256dc
fixed controller path wrong issue / check data exist
AmberYen Nov 1, 2021
0ab85cd
fixed wrong path
AmberYen Nov 1, 2021
a342d2d
fixed controller path wrong issue / check data exist
AmberYen Nov 1, 2021
b10ee15
fixed wrong path
AmberYen Nov 1, 2021
28011ed
fixed controller path wrong issue / check data exist
AmberYen Nov 1, 2021
9b8b4b1
fixed wrong path
AmberYen Nov 1, 2021
5a77ed6
fixed controller path wrong issue / check data exist
AmberYen Nov 1, 2021
c044bab
fixed wrong path
AmberYen Nov 1, 2021
e39f3b4
add mockRequest / mockResponse
AmberYen Nov 1, 2021
47a1370
use new mockRequest / mockResponse
AmberYen Nov 1, 2021
371709f
R02 use new mockRequest / mockResponse
AmberYen Nov 1, 2021
5d61a30
add mockRequest / mockResponse
AmberYen Nov 1, 2021
51b22d5
use new mockRequest / mockResponse
AmberYen Nov 1, 2021
eba6e76
require sinon
AmberYen Nov 1, 2021
70db2a5
remove sinon
AmberYen Nov 1, 2021
94b4d56
remove sinon
AmberYen Nov 1, 2021
2d18631
add mockRequest / mockResponse
AmberYen Nov 1, 2021
a79fdd0
use new mockRequest / mockResponse
AmberYen Nov 1, 2021
7fef8c7
require sinon
AmberYen Nov 1, 2021
c8beeb2
add mockRequest / mockResponse
AmberYen Nov 1, 2021
3a85cde
use new mockRequest / mockResponse
AmberYen Nov 1, 2021
61c6de7
require sinon
AmberYen Nov 1, 2021
8927621
remove sinon
AmberYen Nov 1, 2021
44176de
require sinon
AmberYen Nov 1, 2021
8934182
remove sinon
AmberYen Nov 1, 2021
4219d1f
return [defaulvalue] when findall data empty
AmberYen Nov 1, 2021
c014106
remove done param
AmberYen Nov 2, 2021
6eecc8a
remove done param
AmberYen Nov 2, 2021
a04125f
remove done param
AmberYen Nov 2, 2021
96e3daa
remove done param
AmberYen Nov 2, 2021
1da8f64
R02 use new mockRequest / mockResponse
AmberYen Nov 1, 2021
dcc8f0e
add helper ref
AmberYen Nov 7, 2021
6799804
remove mockRequest, mockResponse
AmberYen Nov 7, 2021
97752ae
use new mockRequest, mockResponse
AmberYen Nov 7, 2021
d54a7fd
R02 use new mockRequest / mockResponse
AmberYen Nov 1, 2021
dde5d1d
add helper ref
AmberYen Nov 7, 2021
ec34393
R02 use new mockRequest / mockResponse
AmberYen Nov 1, 2021
8b395b2
add helper ref
AmberYen Nov 7, 2021
59826d4
remove mockRequest, mockResponse
AmberYen Nov 7, 2021
c74a905
add helper ref
AmberYen Nov 7, 2021
049790e
use new mockRequest, mockResponse
AmberYen Nov 7, 2021
a9d4082
use new mockRequest, mockResponse
AmberYen Nov 7, 2021
7f8789b
use new mockRequest, mockResponse
AmberYen Nov 7, 2021
72b9738
update readme config.json package.json
Carrot7712 Nov 3, 2021
8c88719
Update .travis.yml
Carrot7712 Nov 5, 2021
ec2c6df
Update .travis.yml
Carrot7712 Nov 5, 2021
80d4dd1
update readme config.json package.json
Carrot7712 Nov 3, 2021
7dc7a56
Update .travis.yml
Carrot7712 Nov 5, 2021
88575da
Update .travis.yml
Carrot7712 Nov 5, 2021
dd4522b
update readme config.json package.json
Carrot7712 Nov 3, 2021
894675f
Update .travis.yml
Carrot7712 Nov 5, 2021
da3a406
Update .travis.yml
Carrot7712 Nov 5, 2021
29a2fb9
update readme config.json package.json
Carrot7712 Nov 3, 2021
dcd7e2a
Update .travis.yml
Carrot7712 Nov 5, 2021
5306afe
Update .travis.yml
Carrot7712 Nov 5, 2021
b8259be
Initialize project
HUANG-SIH-MAN Nov 18, 2021
52590c9
feat:Add restaurant index page
HUANG-SIH-MAN Nov 18, 2021
8ab66e9
feat:Add admin restaurant index page
HUANG-SIH-MAN Nov 18, 2021
981adec
feat:Create user model
HUANG-SIH-MAN Nov 18, 2021
d26a398
feat:Add userController and signup page
HUANG-SIH-MAN Nov 18, 2021
48296fd
feat:Confirm user password and unique email
HUANG-SIH-MAN Nov 18, 2021
56608af
feat:Add feature: signInPage, signIn and logout
HUANG-SIH-MAN Nov 18, 2021
5b28862
feat:Add navbar to show login status
HUANG-SIH-MAN Nov 18, 2021
36ddfc6
feat:Add isAdmin to users table,and add authentication before renderi…
HUANG-SIH-MAN Nov 19, 2021
7302034
feat:Create restaurant model
HUANG-SIH-MAN Nov 19, 2021
1dde1f0
feat:Add admin restaurant index page
HUANG-SIH-MAN Nov 19, 2021
2ec789f
feat:Add admin restaurant create form and admin restaurant post feature
HUANG-SIH-MAN Nov 19, 2021
5394221
feat:Add admin restaurant page
HUANG-SIH-MAN Nov 19, 2021
955c9a2
feat:Update admin create page for editing usage,and add admin restaur…
HUANG-SIH-MAN Nov 19, 2021
1723190
feat:Add admin restaurant delete feature
HUANG-SIH-MAN Nov 19, 2021
c32572d
feat:Add image to restaurants and add image upload feature
HUANG-SIH-MAN Nov 19, 2021
b92d2bb
feat:Add user seed data and restaurant seed data
HUANG-SIH-MAN Nov 19, 2021
b47df7d
Install pg and update production config
HUANG-SIH-MAN Nov 19, 2021
b4fb009
Listen to process.env.PORT & define Procfile
HUANG-SIH-MAN Nov 19, 2021
da51bf4
feat:Install Imgur api and update admin POST and PUT
HUANG-SIH-MAN Nov 19, 2021
4c1de29
解決合併衝突
HUANG-SIH-MAN Nov 20, 2021
da2fa70
[Assignment Preparation] ensureAuthenticated & getUser
HUANG-SIH-MAN Nov 20, 2021
2c53049
feat:新增瀏覽所有使用者頁面
HUANG-SIH-MAN Nov 20, 2021
360412f
feat:新增更改使用者權限設定
HUANG-SIH-MAN Nov 22, 2021
935347c
feat:調整程式碼,為了能通過測試檔案
HUANG-SIH-MAN Nov 22, 2021
7d6f709
feat:Create category model and add restaurant.CategoryId and association
HUANG-SIH-MAN Nov 23, 2021
a4bc57c
heroku PG switch to ClearDB mysql
HUANG-SIH-MAN Nov 23, 2021
97c7146
feat:Add category seed data
HUANG-SIH-MAN Nov 23, 2021
13384e2
feat:Show category name
HUANG-SIH-MAN Nov 23, 2021
e8c51f8
feat:Add categories selector on admin create and edit page
HUANG-SIH-MAN Nov 23, 2021
829b6ce
feat:Update category select in edit page using ifCond-helper
HUANG-SIH-MAN Nov 23, 2021
cb4cc74
feat:Add admin categories page
HUANG-SIH-MAN Nov 23, 2021
b3d6b4c
feat:Add admin categories post feature
HUANG-SIH-MAN Nov 23, 2021
45fbdd6
feat:Add admin categories edit and put feature
HUANG-SIH-MAN Nov 23, 2021
0b1247b
feat:Add admin categories delete feature
HUANG-SIH-MAN Nov 23, 2021
8e33854
feat:Add restaurants index page
HUANG-SIH-MAN Nov 23, 2021
1e2cc27
feat:Add restaurants show page
HUANG-SIH-MAN Nov 23, 2021
2d65b6e
feat:Add categories navbar on restaurants index page
HUANG-SIH-MAN Nov 23, 2021
a5caf4d
feat:Add pagination on restaurants index
HUANG-SIH-MAN Nov 24, 2021
1a1b3cd
feat:Create comment model & add association among users, comment, res…
HUANG-SIH-MAN Nov 24, 2021
d0695db
feat:Add post comment feature on restaurant page
HUANG-SIH-MAN Nov 24, 2021
008cacb
feat:Show related comments on restaurant page
HUANG-SIH-MAN Nov 24, 2021
f128cdd
feat:Add delete comment feature for admin
HUANG-SIH-MAN Nov 24, 2021
3a86123
解決合併衝突
HUANG-SIH-MAN Nov 24, 2021
c83596f
解決合併衝突2
HUANG-SIH-MAN Nov 24, 2021
a9116e5
feat:建立個人資料頁面
HUANG-SIH-MAN Nov 24, 2021
8abd636
feat:在使用者的model新增照片欄位
HUANG-SIH-MAN Nov 24, 2021
06b420b
feat:新增瀏覽使用者頁面路由,修改無法取得個人圖片資料的錯誤設定(user model內)
HUANG-SIH-MAN Nov 25, 2021
cf37569
feat:建立編輯 Profile 頁面
HUANG-SIH-MAN Nov 25, 2021
59dbeb3
feat:完成編輯 Profile功能
HUANG-SIH-MAN Nov 25, 2021
2c16f40
使用async/await改寫putUser失敗(程式碼已註解)
HUANG-SIH-MAN Nov 25, 2021
5164db4
feat:在個人頁面顯示評論過的餐廳
HUANG-SIH-MAN Nov 26, 2021
020752e
feat:Add feeds page
HUANG-SIH-MAN Nov 26, 2021
f694ed3
解決合併衝突
HUANG-SIH-MAN Nov 26, 2021
0d94585
改寫getUser取得使用者資料,為了通過R02測試檔
HUANG-SIH-MAN Nov 27, 2021
485c7d0
feat:新增dashboard 頁面會彙整餐廳資訊(可顯示評論數)
HUANG-SIH-MAN Nov 27, 2021
22678a3
feat:新增餐廳計算瀏覽次數功能
HUANG-SIH-MAN Nov 27, 2021
c07c01f
feat:Create favorite model and set association between restaurant and…
HUANG-SIH-MAN Nov 27, 2021
a9b8ff2
feat:Add favorite/unfavorite feature
HUANG-SIH-MAN Dec 10, 2021
963c673
feat:Switch add/remove favorite button on restaurants index page and …
HUANG-SIH-MAN Dec 10, 2021
5f91b04
解決合併衝突
HUANG-SIH-MAN Dec 10, 2021
e6fb1f9
feat:新增like/Ulike餐廳功能(無法通過測試檔)
HUANG-SIH-MAN Dec 11, 2021
49e6f7a
fix:modle關聯設定寫錯位置,進行改寫,刪除followship改寫到user內部
HUANG-SIH-MAN Dec 11, 2021
3561cd1
feat:Add topUser page
HUANG-SIH-MAN Dec 12, 2021
27211a8
feat:Add addFollowing and removeFollowing to userController
HUANG-SIH-MAN Dec 12, 2021
a970142
解決合併衝突R05測試檔
HUANG-SIH-MAN Dec 12, 2021
540bf98
fix:修改R04測試檔模擬資料
HUANG-SIH-MAN Dec 13, 2021
656241d
Merge branch 'R04'
HUANG-SIH-MAN Dec 13, 2021
660c91a
feat:新增TOP 10 人氣餐廳頁面
HUANG-SIH-MAN Dec 13, 2021
26ad471
Merge branch 'R05'
HUANG-SIH-MAN Dec 14, 2021
1f62e0d
feat:refactor router and add GET /api/admin/restaurants
HUANG-SIH-MAN Dec 31, 2021
4a7dae0
feat:refactor adminController.getRestaurants
HUANG-SIH-MAN Dec 31, 2021
5bc6701
feat:新增瀏覽餐廳和類別的API
HUANG-SIH-MAN Dec 31, 2021
09dfd69
feat:refactor adminController.deleteRestaurant and 新增刪除餐廳的API
HUANG-SIH-MAN Jan 1, 2022
8ce9db6
feat:POST /api/admin/restaurants
HUANG-SIH-MAN Jan 1, 2022
9bdb805
feat:PUT /api/admin/restaurants/:id
HUANG-SIH-MAN Jan 1, 2022
9e3f019
feat:POST /api/admin/categories - 後台新增類別
HUANG-SIH-MAN Jan 1, 2022
7bd94f8
feat:PUT /api/admin/categories/:id - 後台修改類別
HUANG-SIH-MAN Jan 1, 2022
c1238f7
feat:DELETE /api/admin/categories/:id - 後台刪除類別
HUANG-SIH-MAN Jan 1, 2022
54f62dc
feat:POST /api/signin (return jwt)
HUANG-SIH-MAN Jan 2, 2022
38e498d
feat:add authenticated and authenticatedAdmin
HUANG-SIH-MAN Jan 2, 2022
424f8d3
feat:POST /api/signup
HUANG-SIH-MAN Jan 2, 2022
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 .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
IMGUR_CLIENT_ID =
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: NODE_ENV=production node app.js
32 changes: 31 additions & 1 deletion app.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,37 @@
const express = require('express')
const exphbs = require('express-handlebars')
const flash = require('connect-flash')
const session = require('express-session')
const methodOverride = require('method-override')
const bodyParser = require('body-parser')
const helpers = require('./_helpers')
const handlebarsHelpers = require('./helpers/handlebarsHelpers')
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config()
}
const passport = require('./config/passport')
const app = express()
const port = 3000
const port = process.env.PORT || 3000

app.engine('handlebars', exphbs({ defaultLayout: 'main', helpers: handlebarsHelpers }))
app.set('view engine', 'handlebars')
app.use(express.static('public'))
app.use(methodOverride('_method'))
app.use(express.urlencoded({extended: true}))
app.use(bodyParser.json())
app.use(session({ secret: 'secret', resave: false, saveUninitialized: false }))
app.use(passport.initialize())
app.use(passport.session())
app.use(flash())

app.use((req, res, next) => {
res.locals.user = helpers.getUser(req)
res.locals.success_messages = req.flash('success_messages')
res.locals.error_messages = req.flash('error_messages')
next()
})

app.use('/upload', express.static(__dirname + '/upload'))
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
Expand Down
13 changes: 8 additions & 5 deletions config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
"dialect": "mysql"
},
"production": {
"username": "root",
"password": null,
"database": "database_production",
"host": "127.0.0.1",
"dialect": "mysql"
"use_env_variable": "CLEARDB_DATABASE_URL",
"dialect": "postgres",
"protocol": "postgres",
"dialectOptions": {
"ssl": {
"rejectUnauthorized": false
}
}
},
"travis": {
"username": "travis",
Expand Down
69 changes: 69 additions & 0 deletions config/passport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const passport = require('passport')
const LocalStrategy = require('passport-local')
const bcrypt = require('bcryptjs')
const db = require('../models')
const User = db.User
const Restaurant = db.Restaurant

// setup passport strategy
passport.use(new LocalStrategy(
// customize user field
{
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
// authenticate user
(req, username, password, cb) => {
User.findOne({ where: { email: username } }).then(user => {
if (!user) return cb(null, false, req.flash('error_messages', '帳號或密碼輸入錯誤'))
if (!bcrypt.compareSync(password, user.password)) return cb(null, false, req.flash('error_messages', '帳號或密碼輸入錯誤!'))
return cb(null, user)
})
}
))

// serialize and deserialize user
passport.serializeUser((user, cb) => {
cb(null, user.id)
})
passport.deserializeUser((id, cb) => {
User.findByPk(id,{
include: [
{ model: Restaurant, as: 'FavoritedRestaurants' },
{ model: Restaurant, as: 'LikedRestaurants' },
{ model: User, as: 'Followers' },
{ model: User, as: 'Followings' }
]
}).then(user => {
user = user.toJSON() // 此處與影片示範不同
return cb(null, user)
})
})

// JWT
const jwt = require('jsonwebtoken')
const passportJWT = require('passport-jwt')
const ExtractJwt = passportJWT.ExtractJwt
const JwtStrategy = passportJWT.Strategy

let jwtOptions = {}
jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken()
jwtOptions.secretOrKey = process.env.JWT_SECRET

let strategy = new JwtStrategy(jwtOptions, function (jwt_payload, next) {
User.findByPk(jwt_payload.id, {
include: [
{ model: db.Restaurant, as: 'FavoritedRestaurants' },
{ model: db.Restaurant, as: 'LikedRestaurants' },
{ model: User, as: 'Followers' },
{ model: User, as: 'Followings' }
]
}).then(user => {
if (!user) return next(null, false)
return next(null, user)
})
})
passport.use(strategy)

module.exports = passport
102 changes: 102 additions & 0 deletions controllers/adminController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
const fs = require('fs')
const imgur = require('imgur-node-api')
const IMGUR_CLIENT_ID = process.env.IMGUR_CLIENT_ID
const db = require('../models')
const Restaurant = db.Restaurant
const User = db.User
const Category = db.Category
const adminService = require('../services/adminService.js')

const adminController = {
getRestaurants: (req, res) => {
adminService.getRestaurants(req, res, (data) => {
return res.render('admin/restaurants', data)
})
},

createRestaurant: (req, res) => {
Category.findAll({
raw: true,
nest: true
}).then(categories => {
return res.render('admin/create', { categories })
})
},

postRestaurant: (req, res) => {
adminService.postRestaurant(req, res, (data) => {
if (data['status'] === 'error') {
req.flash('error_messages', data['message'])
return res.redirect('back')
}
req.flash('success_messages', data['message'])
res.redirect('/admin/restaurants')
})
},

getRestaurant: (req, res) => {
adminService.getRestaurant(req, res, data => {
return res.render('admin/restaurant', { restaurant: data.restaurant })
})
},

editRestaurant: (req, res) => {
Category.findAll({
raw: true,
nest: true
}).then(categories => {
return Restaurant.findByPk(req.params.id).then(restaurant => {
return res.render('admin/create', {
categories,
restaurant: restaurant.toJSON()
})
})
})
},

putRestaurant: (req, res) => {
adminService.putRestaurant(req, res, data => {
if(data['status'] === 'error'){
req.flash('error_messages', data['message'])
return res.redirect('back')
}
req.flash('success_messages', data['message'])
return res.redirect('/admin/restaurants')
})
},

deleteRestaurant: (req, res) => {
adminService.deleteRestaurant(req, res, (data) => {
if (data['status'] === 'success') {
return res.redirect('/admin/restaurants')
}
})
},

getUsers: (req, res) => {
return User.findAll({ raw: true, nest: true })
.then(users => res.render('admin/users', { users }))
},

toggleAdmin: async (req, res) => {
//判斷是否能變更管理權限 (自己不能變更自己)
// if (Number(req.params.id) === req.user.id) {
// req.flash('error_messages','禁止變更管理者權限')
// return res.redirect('/admin/users')
// }
//變更管理權限
return User.findByPk(req.params.id)
.then(async (user) => {
if (user.email === 'root@example.com') {
req.flash('error_messages','禁止變更管理者權限')
return res.redirect('back')
}
user.isAdmin ? await user.update({isAdmin: false }) : await user.update({isAdmin: true })
req.flash('success_messages','使用者權限變更成功')
return res.redirect('/admin/users')
})
}
}


module.exports = adminController
53 changes: 53 additions & 0 deletions controllers/api/adminController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const db = require('../../models')
const Restaurant = db.Restaurant
const Category = db.Category
const adminService = require('../../services/adminService')

const adminController = {
getRestaurants: (req, res) => {
adminService.getRestaurants(req, res, (data) => {
return res.json(data)
})
},
getRestaurant: (req, res) => {
adminService.getRestaurant(req, res, (data) => {
return res.json(data)
})
},
getCategories:(req, res) => {
adminService.getCategories(req, res, (data) => {
return res.json(data)
})
},
deleteRestaurant: (req, res) => {
adminService.deleteRestaurant(req, res, (data) => {
return res.json(data)
})
},
postRestaurant: (req, res) => {
adminService.postRestaurant(req, res, (data) => {
return res.json(data)
})
},
putRestaurant: (req, res) => {
adminService.putRestaurant(req, res, (data) => {
return res.json(data)
})
},
postCategory: (req, res) => {
adminService.postCategory(req, res, data => {
return res.json(data)
})
},
putCategory: (req, res) => {
adminService.putCategory(req, res, data => {
return res.json(data)
})
},
deleteCategory: (req, res) => {
adminService.deleteCategory(req, res, data => {
return res.json(data)
})
}
}
module.exports = adminController
60 changes: 60 additions & 0 deletions controllers/api/userController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const bcrypt = require('bcryptjs')
const db = require('../../models')
const User = db.User

// JWT
const jwt = require('jsonwebtoken')
const passportJWT = require('passport-jwt')
const ExtractJwt = passportJWT.ExtractJwt
const JwtStrategy = passportJWT.Strategy

let userController = {
signIn: (req, res) => {
// 檢查必要資料
if (!req.body.email || !req.body.password) {
return res.json({ status: 'error', message: "required fields didn't exist" })
}
// 檢查 user 是否存在與密碼是否正確
let username = req.body.email
let password = req.body.password

User.findOne({ where: { email: username } }).then(user => {
if (!user) return res.status(401).json({ status: 'error', message: 'no such user found' })
if (!bcrypt.compareSync(password, user.password)) {
return res.status(401).json({ status: 'error', message: 'passwords did not match' })
}
// 簽發 token
var payload = { id: user.id }
var token = jwt.sign(payload, process.env.JWT_SECRET)
return res.json({
status: 'success',
message: 'ok',
token: token,
user: {
id: user.id, name: user.name, email: user.email, isAdmin: user.isAdmin
}
})
})
},
signUp: (req, res) => {
if(req.body.passwordCheck !== req.body.password){
return res.json({ status: 'error', message: '兩次密碼輸入不同!'})
} else {
User.findOne({where: {email: req.body.email}}).then(user => {
if(user){
return res.json({ status: 'error', message: '信箱重複!'})
} else {
User.create({
name: req.body.name,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, bcrypt.genSaltSync(10), null)
}).then(user => {
return res.json({ status: 'success', message: '成功註冊帳號!'})
})
}
})
}
}
}

module.exports = userController
Loading