Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
4111b32
add proxyquire & sequelize-mock npm lib
AmberYen Oct 12, 2021
161a837
add new A17 test
AmberYen Oct 12, 2021
bb8ce89
tests/A17.test.js added comments
AmberYen Oct 18, 2021
c15fe79
add A19 test
AmberYen Oct 18, 2021
da713e0
add A20 test
AmberYen Oct 18, 2021
88812da
add A21 test
AmberYen Oct 18, 2021
a7d56e1
add A22 test
AmberYen Oct 18, 2021
d4a7391
add commnets for A17
AmberYen Oct 19, 2021
e981eb0
add comments for A19
AmberYen Oct 19, 2021
5396cf6
add comments for A22
AmberYen Oct 19, 2021
dab9f1d
add comments for A21
AmberYen Oct 19, 2021
c7a336d
add comments for A22
AmberYen Oct 19, 2021
a175811
adjust coding style
Carrot7712 Oct 27, 2021
39950b9
修改變數名與註解
Carrot7712 Oct 27, 2021
82de6c8
refactor mock db in unit test / integrated into helpers/unitTestHelpers
AmberYen Oct 28, 2021
c9b201e
remove n_comments check due to follow model answer
AmberYen Oct 28, 2021
50476ab
revise comments
Carrot7712 Oct 28, 2021
b3ddfcd
add A21 test userId and restaurantId with addLike function
AmberYen Oct 29, 2021
6c5f774
add viewCounts check in A20
AmberYen Oct 29, 2021
2ad4b59
add new test comment
AmberYen Oct 29, 2021
a2df6a4
remove other test and rename A17 -> R01
AmberYen Oct 31, 2021
2f9c683
changed all test file name
AmberYen Oct 31, 2021
d3a66dd
remove R03/04/05 test
AmberYen Oct 31, 2021
5a83153
remove R05 test
AmberYen Oct 31, 2021
9148715
fixed R01 ../../app issue & not found sequelize lib
AmberYen Nov 1, 2021
154a12e
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
ba68733
fixed controller path wrong issue / check data exist
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
28011ed
fixed controller path wrong issue / check data exist
AmberYen Nov 1, 2021
9b8b4b1
fixed wrong path
AmberYen Nov 1, 2021
e45367f
add mockRequest / mockResponse
AmberYen Nov 1, 2021
d487f4a
use new mockRequest / mockResponse
AmberYen Nov 1, 2021
73fc123
require sinon
AmberYen Nov 1, 2021
5224b9a
remove sinon
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
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
9bf30ca
return [defaulvalue] when findall data empty
AmberYen Nov 1, 2021
05b87a2
remove done param
AmberYen Nov 2, 2021
c014106
remove done param
AmberYen Nov 2, 2021
a04125f
remove done param
AmberYen Nov 2, 2021
a1cf9c3
update readme config.json package.json
Carrot7712 Nov 3, 2021
5e1573a
Update .travis.yml
Carrot7712 Nov 5, 2021
c71da44
Update .travis.yml
Carrot7712 Nov 5, 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
ec34393
R02 use new mockRequest / mockResponse
AmberYen Nov 1, 2021
8b395b2
add helper ref
AmberYen Nov 7, 2021
a9d4082
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
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
29dd825
Update config.json
Carrot7712 Nov 8, 2021
20cab63
Update config.json
Carrot7712 Nov 8, 2021
32a6374
Update config.json
Carrot7712 Nov 8, 2021
caa0aef
change restaurantId,userId to UserId, RestaurantId
AmberYen Nov 15, 2021
13abc4b
return [defaulvalue] when findall data empty
Carrot7712 Nov 17, 2021
e854171
return [defaulvalue] when findall data empty
Carrot7712 Nov 17, 2021
bce1fc9
U97 initialize
leo812leo Nov 21, 2021
2e92d3b
U98 admin view setting
leo812leo Nov 21, 2021
c19c4b1
U99 sequelize initialize
leo812leo Nov 21, 2021
c603f05
U100 create User Model
leo812leo Nov 21, 2021
bd18237
U101
leo812leo Nov 21, 2021
12103f0
U102
leo812leo Nov 21, 2021
c443d58
U103
leo812leo Nov 21, 2021
7e76973
U104
leo812leo Nov 21, 2021
8df0eb0
U105
leo812leo Nov 21, 2021
6446335
U107
leo812leo Nov 21, 2021
3879b72
U108
leo812leo Nov 21, 2021
5c13397
U109
leo812leo Nov 21, 2021
dd9a9f6
U110
leo812leo Nov 21, 2021
8bd36d1
U111
leo812leo Nov 21, 2021
355682c
U112
leo812leo Nov 21, 2021
89b5770
U113
leo812leo Nov 21, 2021
f9b52b3
U114
leo812leo Nov 21, 2021
97911cd
Install pg and update production config
leo812leo Nov 21, 2021
3c9a594
port update
leo812leo Nov 21, 2021
d121325
imgur and env
leo812leo Nov 21, 2021
8c0e6c9
heroku PG switch to ClearDB mysql
leo812leo Nov 21, 2021
5ed30e2
Merge remote-tracking branch 'origin/R01-test' into R01
leo812leo Nov 21, 2021
2835ff0
R01
leo812leo Nov 21, 2021
87d88b2
U130
leo812leo Nov 22, 2021
e2c08c3
U131
leo812leo Nov 22, 2021
ce2c3f4
U132
leo812leo Nov 22, 2021
3a98de3
U133
leo812leo Nov 22, 2021
83394f7
U135
leo812leo Nov 22, 2021
8fb6da0
U136
leo812leo Nov 22, 2021
5c9c844
U137
leo812leo Nov 22, 2021
bce92b7
U138
leo812leo Nov 22, 2021
c7f68c1
U140
leo812leo Nov 22, 2021
a779e03
U141
leo812leo Nov 22, 2021
79f6c67
U142
leo812leo Nov 22, 2021
2325b02
U143
leo812leo Nov 22, 2021
ae95b0a
U146
leo812leo Nov 22, 2021
91e07ee
U147
leo812leo Nov 23, 2021
dd76098
U148
leo812leo Nov 23, 2021
3e07b41
Merge remote-tracking branch 'origin/R02-test' into R02
leo812leo Nov 23, 2021
1027439
R02Q4
leo812leo Nov 23, 2021
a9c8158
R02Q5
leo812leo Nov 23, 2021
4579ec5
U150
leo812leo Nov 24, 2021
1b476bf
R03
leo812leo Nov 24, 2021
f20865a
U152
leo812leo Nov 24, 2021
a7a153b
U153
leo812leo Nov 24, 2021
2164cf9
U154
leo812leo Nov 24, 2021
d9ab232
Merge remote-tracking branch 'origin/R04-test' into R04
leo812leo Nov 24, 2021
a978148
R04
leo812leo Nov 24, 2021
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
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"emmet.optimizeStylesheetParsing": false
}
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
6 changes: 3 additions & 3 deletions _helpers.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
function ensureAuthenticated(req) {
return req.isAuthenticated();
return req.isAuthenticated()
}

function getUser(req) {
return req.user;
return req.user
}

module.exports = {
ensureAuthenticated,
getUser,
};
}
36 changes: 33 additions & 3 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,41 @@
const express = require('express')
const flash = require('connect-flash')
const session = require('express-session')
const passport = require('./config/passport')
const app = express()
const port = 3000
const { engine } = require('express-handlebars')
const db = require('./models') // 引入資料庫
const methodOverride = require('method-override')
const helpers = require('./_helpers')
const port = process.env.PORT || 3000

if (process.env.NODE_ENV !== 'production') {
require('dotenv').config()
}

app.use(express.urlencoded({ extended: true }))
app.use(session({ secret: 'secret', resave: false, saveUninitialized: false }))
app.use(flash())
app.use(methodOverride('_method'))
app.use('/upload', express.static(__dirname + '/upload'))
// setup passport
app.use(passport.initialize())
app.use(passport.session())

app.engine('handlebars', engine({ defaultLayout: 'main', helpers: require('./config/handlebars-helpers') }));
app.set('view engine', 'handlebars')

// 把 req.flash 放到 res.locals 裡面
app.use((req, res, next) => {
res.locals.success_messages = req.flash('success_messages')
res.locals.error_messages = req.flash('error_messages')
res.locals.user = req.user
next()
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})

require('./routes')(app)
require('./routes')(app, passport)

module.exports = app
module.exports = app
14 changes: 12 additions & 2 deletions config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,21 @@
"production": {
"username": "root",
"password": null,
"database": "database_production",
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"travis": {
"production": {
"use_env_variable": "CLEARDB_DATABASE_URL",
"dialect": "postgres",
"protocol": "postgres",
"dialectOptions": {
"ssl": {
"rejectUnauthorized": false
}
}
},
"travis": {
"username": "travis",
"database": "forum",
"host": "127.0.0.1",
Expand Down
12 changes: 12 additions & 0 deletions config/handlebars-helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const moment = require('moment')
module.exports = {
ifCond: function (a, b, options) {
if (a === b) {
return options.fn(this)
}
return options.inverse(this)
},
moment: function (a) {
return moment(a).fromNow()
}
}
43 changes: 43 additions & 0 deletions config/passport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
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
const Like = db.Like

// 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' }
]
}).then(user => {
user = user.toJSON()
return cb(null, user)
})
})

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

const adminController = {
//getRestaurants
getRestaurants: (req, res) => {
return Restaurant.findAll({
raw: true,
nest: true,
include: [Category]
}).then(restaurants => {
return res.render('admin/restaurants', { restaurants })
})
},
//getRestaurant
getRestaurant: (req, res) => {
return Restaurant.findByPk(req.params.id, {
include: [Category]
}).then(restaurant => {
return res.render('admin/restaurant', {
restaurant: restaurant.toJSON()
})
})
},
/* create */
// createPage
createRestaurant: (req, res) => {
Category.findAll({
raw: true,
nest: true
}).then(categories => {
return res.render('admin/create', { categories })
})
},
// POST to create
postRestaurant: (req, res) => {
if (!req.body.name) {
req.flash('error_messages', "name didn't exist")
return res.redirect('back')
}
const { file } = req
if (file) {
imgur.setClientID(IMGUR_CLIENT_ID);
imgur.upload(file.path, (err, img) => {
return Restaurant.create({
name: req.body.name,
tel: req.body.tel,
address: req.body.address,
opening_hours: req.body.opening_hours,
description: req.body.description,
image: file ? img.data.link : null,
CategoryId: req.body.categoryId
})
.then((restaurant) => {
req.flash('success_messages', 'restaurant was successfully created')
res.redirect('/admin/restaurants')
})
})
}
else {
return Restaurant.create({
name: req.body.name,
tel: req.body.tel,
address: req.body.address,
opening_hours: req.body.opening_hours,
description: req.body.description,
image: null,
CategoryId: req.body.categoryId
}).then((restaurant) => {
req.flash('success_messages', 'restaurant was successfully created')
return res.redirect('/admin/restaurants')
})
}
},
editRestaurant: async (req, res) => {
const categories = await Category.findAll({
raw: true,
nest: true
})
const restaurant = await Restaurant.findByPk(req.params.id)
return res.render('admin/create', {
categories: categories,
restaurant: restaurant.toJSON()
})
},
putRestaurant: (req, res) => {
if (!req.body.name) {
req.flash('error_messages', "name didn't exist")
return res.redirect('back')
}
const { file } = req
if (file) {
imgur.setClientID(IMGUR_CLIENT_ID);
imgur.upload(file.path, (err, img) => {
return Restaurant.findByPk(req.params.id)
.then((restaurant) => {
restaurant.update({
name: req.body.name,
tel: req.body.tel,
address: req.body.address,
opening_hours: req.body.opening_hours,
description: req.body.description,
image: file ? img.data.link : restaurant.image,
CategoryId: req.body.categoryId
})
.then((restaurant) => {
req.flash('success_messages', 'restaurant was successfully to update')
res.redirect('/admin/restaurants')
})
})
})
} else {
return Restaurant.findByPk(req.params.id)
.then((restaurant) => {
restaurant.update({
name: req.body.name,
tel: req.body.tel,
address: req.body.address,
opening_hours: req.body.opening_hours,
description: req.body.description,
image: restaurant.image,
CategoryId: req.body.categoryId
}).then((restaurant) => {
req.flash('success_messages', 'restaurant was successfully to update')
res.redirect('/admin/restaurants')
})
})
}
},
deleteRestaurant: (req, res) => {
return Restaurant.findByPk(req.params.id)
.then((restaurant) => {
restaurant.destroy()
.then((restaurant) => {
res.redirect('/admin/restaurants')
})
})
},
getUsers: (req, res) => {
return User.findAll({ raw: true }).then(users => {
return res.render('admin/users', { users })
})
},
toggleAdmin: (req, res) => {
return User.findByPk(req.params.id)
.then(
(user) => {
if (user.email !== 'root@example.com') {
user.update({
isAdmin: !user.isAdmin
})
.then(() => {
req.flash('success_messages', '使用者權限變更成功')
res.redirect('/admin/users')
})
} else {
req.flash('error_messages', '禁止變更管理者權限')
return res.redirect('back')
}
})
}
}

module.exports = adminController
54 changes: 54 additions & 0 deletions controllers/categoryController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const db = require('../models')
const Category = db.Category
let categoryController = {
getCategories: (req, res) => {
return Category.findAll({
raw: true,
nest: true
}).then(categories => {
return res.render('admin/categories', { categories })
})
},
postCategory: (req, res) => {
if (!req.body.name) {
req.flash('error_messages', 'name didn\'t exist')
return res.redirect('back')
} else {
return Category.create({
name: req.body.name
})
.then((category) => {
res.redirect('/admin/categories')
})
}
},
getCategories: async (req, res) => {
const categories = await Category.findAll({
raw: true,
nest: true
})
if (req.params.id) {
const category = await Category.findByPk(req.params.id)
return res.render('admin/categories', { categories, category: category.toJSON() })
} else {
return res.render('admin/categories', { categories })
}
},
putCategory: async (req, res) => {
if (!req.body.name) {
req.flash('error_messages', 'name didn\'t exist')
return res.redirect('back')
} else {
const category = await Category.findByPk(req.params.id)
await category.update(req.body)
res.redirect('/admin/categories')
}
},
deleteCategory: async (req, res) => {

const category = await Category.findByPk(req.params.id)
await category.destroy()
res.redirect('/admin/categories')
}
}
module.exports = categoryController
Loading