Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
fca7f3b
feat: add R01.test.js and unit-test-helpers.js
Carrot7712 Jan 13, 2022
96da4be
feat:add R02.test.js
Carrot7712 Jan 13, 2022
37322b4
feat:add R03.test.js
Carrot7712 Jan 13, 2022
ad796af
feat:add R04.test.js
Carrot7712 Jan 13, 2022
7ece79e
add R01.test.js && unit-test-helper.js
AmberYen Mar 2, 2022
b54a2e9
add R02.test.js file
AmberYen Mar 2, 2022
ef44c3e
add R03.test.js file
AmberYen Mar 2, 2022
1ead393
add R04.test.js
AmberYen Mar 2, 2022
4bce0c5
add R05.test.js
AmberYen Mar 2, 2022
79ff158
註解 typo 修正
zjzheng17 Jul 18, 2022
9d566b6
correcting typo in comment
zjzheng17 Jul 18, 2022
4fe60b0
correcting typo in comment
zjzheng17 Jul 18, 2022
03c14c0
correcting typo in comment
zjzheng17 Jul 18, 2022
326bed8
fix R01.test.js comment typo
tuterwell Aug 10, 2023
7f6510a
fix R01.test.js comment typo
tuterwell Aug 10, 2023
d5b1553
chore: init github workflow
eugenechen0514 Sep 9, 2023
6f29ed3
chore: init github workflow
eugenechen0514 Sep 9, 2023
02a746f
chore: init github workflow
eugenechen0514 Sep 9, 2023
16bd368
chore: init github workflow
eugenechen0514 Sep 9, 2023
afe4d45
chore: init github workflow
eugenechen0514 Sep 9, 2023
fe01b7f
Update unit-test-helper.js
tuterwell Sep 12, 2023
13c29eb
Update unit-test-helper.js update()
tuterwell Sep 12, 2023
e2665da
chore: format code
eugenechen0514 Sep 17, 2023
1be932b
test: fix update method
eugenechen0514 Sep 17, 2023
d12a942
Merge commit '1be932b9d1998168679d2cdf5a7a9e2f1d2bca91' into R01-test
eugenechen0514 Sep 17, 2023
20ab723
Merge branch 'R01-test' into R02-test
eugenechen0514 Sep 17, 2023
fa173a7
chore: fix code format
eugenechen0514 Sep 17, 2023
12487dc
Merge branch 'R02-test' into R03-test
eugenechen0514 Sep 17, 2023
2942b99
Merge branch 'R03-test' into R04-test
eugenechen0514 Sep 17, 2023
8e195f8
Merge branch 'R04-test' into R05-test
eugenechen0514 Sep 17, 2023
1b8cd24
Delete .travis.yml
tuterwell Sep 18, 2023
f3b0c32
Delete .travis.yml
tuterwell Sep 18, 2023
a449027
Delete .travis.yml
tuterwell Sep 18, 2023
c26e8ee
Delete .travis.yml
tuterwell Sep 18, 2023
07201da
Delete .travis.yml
tuterwell Sep 18, 2023
d6e54dd
feat: add handlebars
allenliao0119 Aug 16, 2024
b9fb6f8
feat: add index page
allenliao0119 Aug 16, 2024
13cd3ee
feat: add admin index page
allenliao0119 Aug 17, 2024
6d99fec
feat: add user model
allenliao0119 Aug 18, 2024
8aa3822
feat: user signup
allenliao0119 Aug 18, 2024
7c0a0a7
feat: flash msg & signup verification
allenliao0119 Aug 18, 2024
e54130e
feat: passport init & signin
allenliao0119 Aug 19, 2024
2fa78fd
feat: add header & footer
allenliao0119 Aug 20, 2024
26fc420
feat: user model add is_admin
allenliao0119 Aug 20, 2024
559d3b1
feat: add restaurant model
allenliao0119 Aug 20, 2024
e7c600c
feat: modify admin restaurants page
allenliao0119 Aug 20, 2024
6b12f40
feat: create restaurant
allenliao0119 Aug 20, 2024
48032d9
feat: admin restaurant page
allenliao0119 Aug 21, 2024
29d16ee
feat: admin update restaurant
allenliao0119 Aug 21, 2024
fc50350
feat: delete restaurant
allenliao0119 Aug 21, 2024
454ff02
feat: add restaurant image
allenliao0119 Aug 22, 2024
1e6e02c
feat: add seed data
allenliao0119 Aug 23, 2024
70462c5
fix conflict
allenliao0119 Aug 23, 2024
f3e77cc
feat: modify user seed data to fit test requirement
allenliao0119 Aug 23, 2024
875c180
feat: adjust middlewares/auth.js
allenliao0119 Aug 23, 2024
100c0da
feat: add admin users page
allenliao0119 Aug 23, 2024
acb7f4d
fix conflict
allenliao0119 Aug 23, 2024
2b46d83
feat: add category model
allenliao0119 Aug 23, 2024
170333b
feat: update seed files
allenliao0119 Aug 24, 2024
840139d
feat: show category on admin restaurant pages
allenliao0119 Aug 24, 2024
f01342d
feat: add ifEqual hbs helper and update category selector
allenliao0119 Aug 25, 2024
c53dadb
feat: implement admin categories page and create category
allenliao0119 Aug 25, 2024
ace3fba
feat: category delete
allenliao0119 Aug 26, 2024
8d1df04
feat: add restaurants index page
allenliao0119 Aug 26, 2024
4d5439e
feat: add restaurant page
allenliao0119 Aug 26, 2024
8887116
Merge remote-tracking branch 'origin/R02-test' into R02
allenliao0119 Aug 26, 2024
7a3b795
feat: add restaurant dashboard
allenliao0119 Aug 26, 2024
55cab8f
refactor: getRestaurant in restController
allenliao0119 Aug 26, 2024
fe38627
feat: add categories navbar on restaurants page
allenliao0119 Aug 27, 2024
a063bfb
feat: add pagination on restaurants index page
allenliao0119 Aug 27, 2024
9935b4f
feat: add comment model
allenliao0119 Aug 27, 2024
7bddf25
feat: add post comment on restaurant page
allenliao0119 Aug 27, 2024
fe239d4
feat: show comments on restaurant page
allenliao0119 Aug 27, 2024
a3a2e12
feat: add delete comment for admin
allenliao0119 Aug 28, 2024
32b2c57
feat: add comment count on dashboard
allenliao0119 Aug 28, 2024
b341252
Merge remote-tracking branch 'origin/R03-test' into R03
allenliao0119 Aug 28, 2024
c83f286
feat: add user profile page
allenliao0119 Aug 28, 2024
c9d63cf
feat: user profile edit
allenliao0119 Aug 28, 2024
67a293d
feat: add comment record on user profile and create comments seed file
allenliao0119 Aug 29, 2024
dd069f5
feat: add feeds page
allenliao0119 Aug 29, 2024
9a5d6ae
feat: create favorite model
allenliao0119 Aug 30, 2024
52f146d
feat: add favorite/unfavorite button on index page
allenliao0119 Aug 30, 2024
9826179
feat: get user's favorite restaurants & switch button
allenliao0119 Aug 31, 2024
52e9f19
Merge remote-tracking branch 'origin/R04-test' into R04
allenliao0119 Aug 31, 2024
4dec505
feat: create like model
allenliao0119 Aug 31, 2024
3db6df0
feat: implement like/unlike restaurant and switch button
allenliao0119 Aug 31, 2024
dd5a078
feat: create followship model
allenliao0119 Sep 1, 2024
40f368d
feat: add topUser page
allenliao0119 Sep 1, 2024
0a862dd
modify user seedfile
allenliao0119 Sep 1, 2024
91bc6b5
feat: addFollowing & removeFollowing function
allenliao0119 Sep 1, 2024
137c502
Merge remote-tracking branch 'origin/R05-test'
allenliao0119 Sep 1, 2024
e4b2585
feat: add top restaurants page
allenliao0119 Sep 2, 2024
370a31b
reload R05-test
allenliao0119 Sep 2, 2024
fc6fffc
feat: add favorite restaurant, followers and following on profile page
allenliao0119 Sep 2, 2024
f047ec3
feat: implement visiting follower/following user profile page function
allenliao0119 Sep 2, 2024
29f9f16
feat: add pagination to admin restaurant page
allenliao0119 Sep 3, 2024
7214151
feat: filter the duplicate favorited restaurants
allenliao0119 Sep 3, 2024
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
26 changes: 26 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
const express = require('express')
const handlebars = require('express-handlebars')
const handlebarsHelper = require('./helpers/handlebars-helpers')
const flash = require('connect-flash')
const session = require('express-session')
const methodOverride = require('method-override')
const passport = require('passport')
const { getUser } = require('./helpers/auth-helpers')
const routes = require('./routes')
const path = require('path')

const app = express()
const port = process.env.PORT || 3000
const SESSION_SECRET = 'secret'

app.engine('hbs', handlebars({ extname: '.hbs', helpers: handlebarsHelper }))
app.set('view engine', 'hbs')

app.use(methodOverride('_method'))
app.use('/upload', express.static(path.join(__dirname, 'upload')))
app.use(session({ secret: SESSION_SECRET, resave: false, saveUninitialized: false }))
app.use(passport.initialize())
app.use(passport.session())
app.use(flash())

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

app.use(routes)

Expand Down
43 changes: 43 additions & 0 deletions config/passport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const bcrypt = require('bcryptjs')
const passport = require('passport')
const LocalStrategy = require('passport-local')

const { User, Restaurant } = require('../models')

passport.use(new LocalStrategy(
{
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
(req, email, password, cb) => {
User.findOne({ where: { email } })
.then(user => {
if (!user) return cb(null, false, req.flash('error_messages', '帳號或密碼輸入錯誤!'))
bcrypt.compare(password, user.password).then(isMatched => {
if (!isMatched) return cb(null, false, req.flash('error_messages', '帳號或密碼輸入錯誤!'))
return cb(null, user)
})
})
.catch(err => cb(err))
}
))

passport.serializeUser((user, cb) => {
return 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 => cb(null, user.toJSON()))
.catch(err => cb(err))
})

module.exports = passport
144 changes: 144 additions & 0 deletions controllers/admin-controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
const { Restaurant, User, Category } = require('../models')

const { localFileHandler } = require('../helpers/file-helpers')
const { getOffset, getPagination } = require('../helpers/pagination-helper')

const adminController = {
getRestaurants: (req, res, next) => {
const DEFAULT_REST_LIMEIT = 20
const page = Number(req.query.page) || 1
console.log('page:', page)
const offset = getOffset(DEFAULT_REST_LIMEIT, page)
return Restaurant.findAndCountAll({
include: [Category],
raw: true,
nest: true,
offset,
limit: DEFAULT_REST_LIMEIT
})
.then(restaurant => {
const pagination = getPagination(DEFAULT_REST_LIMEIT, page, restaurant.count)
console.log('currentPage:', pagination.currentPage)
return res.render('admin/restaurants', {
restaurants: restaurant.rows,
pagination
})
})
.catch(err => next(err))
},
createRestaurant: (req, res) => {
return Category.findAll({ raw: true })
.then(categories => res.render('admin/create-restaurant', { categories }))
},
postRestaurant: (req, res, next) => {
const { name, tel, address, openingHours, description, categoryId } = req.body
if (!name) throw new Error('Restaurant name is required!')
const { file } = req
localFileHandler(file)
.then(filePath => {
return Restaurant.create({
name,
tel,
address,
openingHours,
description,
image: filePath || null,
categoryId
})
})
.then(() => {
req.flash('success_messages', 'restaurant was successfully created')
res.redirect('/admin/restaurants')
})
.catch(err => next(err))
},
getRestaurant: (req, res, next) => {
return Restaurant.findByPk(req.params.id, {
raw: true,
nest: true,
include: [Category]
})
.then(restaurant => {
if (!restaurant) throw new Error("Restaurant didn't exist!")
res.render('admin/restaurant', { restaurant })
})
.catch(err => next(err))
},
editRestaurant: (req, res, next) => {
return Promise.all([
Restaurant.findByPk(req.params.id, { raw: true }),
Category.findAll({ raw: true })
])
.then(([restaurant, categories]) => {
if (!restaurant) throw new Error("Restaurant didn't exist!")
res.render('admin/edit-restaurant', { restaurant, categories })
})
.catch(err => next(err))
},
putRestaurant: (req, res, next) => {
const { name, tel, address, openingHours, description, categoryId } = req.body
if (!name) throw new Error('Restaurant name is required!')
const { file } = req
return Promise.all([
Restaurant.findByPk(req.params.id),
localFileHandler(file)
])
.then(([restaurant, filePath]) => {
if (!restaurant) throw new Error("Restaurant didn't exist!")
return restaurant.update({
name,
tel,
address,
openingHours,
description,
image: filePath || restaurant.image,
categoryId
})
})
.then(() => {
req.flash('success_messages', 'restaurant was successfully updated')
res.redirect('/admin/restaurants')
})
.catch(err => next(err))
},
deleteRestaurant: (req, res, next) => {
return Restaurant.findByPk(req.params.id)
.then(restaurant => {
if (!restaurant) throw new Error("Restaurant didn't exist!")
return restaurant.destroy()
})
.then(() => {
req.flash('success_messages', 'restaurant was successfully deleted')
res.redirect('/admin/restaurants')
})
.catch(err => next(err))
},
getUsers: (req, res, next) => {
return User.findAll({
attributes: ['id', 'name', 'email', 'isAdmin'],
raw: true
})
.then(users => res.render('admin/users', { users }))
.catch(err => next(err))
},
patchUser: (req, res, next) => {
return User.findOne({
attributes: ['id', 'email', 'isAdmin'],
where: { id: req.params.id }
})
.then(user => {
if (!user) throw new Error("User didn't exist!")
if (user.email === 'root@example.com') {
req.flash('error_messages', '禁止變更 root 權限')
return res.redirect('back')
}
return user.update({ isAdmin: !user.isAdmin }, { where: { id: user.id } })
})
.then(() => {
req.flash('success_messages', '使用者權限變更成功')
res.redirect('/admin/users')
})
.catch(err => next(err))
}
}
module.exports = adminController
49 changes: 49 additions & 0 deletions controllers/category-controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const { Category } = require('../models')

const categoryController = {
getCategories: (req, res, next) => {
Promise.all([
Category.findAll({ raw: true }),
req.params.id ? Category.findByPk(req.params.id, { raw: true }) : null
])
.then(([categories, category]) => { res.render('admin/categories', { categories, category }) })
.catch(err => next(err))
},
postCategory: (req, res, next) => {
const { name } = req.body
if (!name) throw new Error('category name is required')
return Category.create({ name })
.then(() => {
req.flash('success_messages', 'category was successfully created')
res.redirect('/admin/categories')
})
.catch(err => next(err))
},
putCategory: (req, res, next) => {
const { name } = req.body
if (!name) throw new Error('category name is required')
Category.findByPk(req.params.id)
.then(category => {
if (!category) throw new Error("category didn't exist")
return category.update({ name })
})
.then(() => {
req.flash('success_messages', 'category was successfully updated')
res.redirect('/admin/categories')
})
.catch(err => next(err))
},
deleteCategory: (req, res, next) => {
Category.findByPk(req.params.id)
.then(category => {
if (!category) throw new Error("category didn't exist")
return category.destroy()
})
.then(() => {
req.flash('success_messages', 'category and related restaurants were successfully deleted')
res.redirect('/admin/categories')
})
.catch(err => next(err))
}
}
module.exports = categoryController
42 changes: 42 additions & 0 deletions controllers/comment-controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const { Comment, Restaurant, User } = require('../models')
const { getUser } = require('../helpers/auth-helpers')

const commentController = {
postComment: (req, res, next) => {
const { text, restaurantId } = req.body
const userId = getUser(req).id
if (!text) throw new Error('text is required')
if (!restaurantId) throw new Error('some parameters are missing value')
Promise.all([
Restaurant.findByPk(restaurantId),
User.findByPk(userId)
])
.then(([restaurant, user]) => {
if (!restaurant) throw new Error("restaurant didn't exist")
if (!user) throw new Error("User didn't exist")
return Comment.create({
text,
restaurantId,
userId
})
})
.then(() => {
req.flash('success_messages', 'Comment was successfully created')
res.redirect(`/restaurants/${restaurantId}`)
})
.catch(err => next(err))
},
deleteComment: (req, res, next) => {
return Comment.findByPk(req.params.id)
.then(comment => {
if (!comment) throw new Error("comment didn't exist")
return comment.destroy()
})
.then(deleteComment => {
req.flash('success_messages', 'comment was successfully deleted')
res.redirect(`/restaurants/${deleteComment.restaurantId}`)
})
.catch(err => next(err))
}
}
module.exports = commentController
Loading