Skip to content
Open

R04 #258

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 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
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
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
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
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
1b8cd24
Delete .travis.yml
tuterwell Sep 18, 2023
c26e8ee
Delete .travis.yml
tuterwell Sep 18, 2023
10fd943
add index page
sdfghjka Feb 2, 2025
16b2a67
add admin index page
sdfghjka Feb 2, 2025
0fe53cc
add user model
sdfghjka Feb 2, 2025
a0bd58d
user signup
sdfghjka Feb 3, 2025
0a3e70d
flash msg & signup verification
sdfghjka Feb 3, 2025
7089131
passport init & signin
sdfghjka Feb 3, 2025
d86618d
add header & footer
sdfghjka Feb 3, 2025
668b474
user model add is_admin and add restaurants model
sdfghjka Feb 3, 2025
92c80df
modify admin restaurants page
sdfghjka Feb 3, 2025
dff2f5a
create restaurant
sdfghjka Feb 4, 2025
858ab44
admin restaurant page
sdfghjka Feb 4, 2025
35fa199
admin update restaurant
sdfghjka Feb 4, 2025
eb12036
delete restaurant
sdfghjka Feb 4, 2025
cc897d9
add restaurant image
sdfghjka Feb 5, 2025
a78a47d
add seed data
sdfghjka Feb 5, 2025
6f999e6
Merge remote-tracking branch 'upstream/R01-test' into R01
sdfghjka Feb 5, 2025
d67dffa
adjust middleware/auth.js
sdfghjka Feb 5, 2025
47da6db
add user manage page
sdfghjka Feb 6, 2025
db6676f
add category model
sdfghjka Feb 6, 2025
07c783c
update seed files
sdfghjka Feb 6, 2025
8f485df
add categories selector on admin create and edit page
sdfghjka Feb 7, 2025
fde8e0f
add ifCond hbs helper & update category selector
sdfghjka Feb 7, 2025
a8dfae7
merge R01 and add admin categories page
sdfghjka Feb 7, 2025
d72fb1a
category create
sdfghjka Feb 8, 2025
0b80b22
category update
sdfghjka Feb 8, 2025
2387b5b
category delete
sdfghjka Feb 8, 2025
1ededb5
add restaurants index page
sdfghjka Feb 8, 2025
c229d40
add restaurant page
sdfghjka Feb 8, 2025
d770330
R02 test
sdfghjka Feb 8, 2025
2fbcddb
add categories navbar on restaurants index page
sdfghjka Feb 8, 2025
e8d995d
add pagination on restaurants index page
sdfghjka Feb 8, 2025
993a809
add comment model
sdfghjka Feb 8, 2025
8ebd6fa
add post comment on restaurant page
sdfghjka Feb 8, 2025
7ec0461
show comments on restaurant page
sdfghjka Feb 8, 2025
5f39c60
add delete comment for admin
sdfghjka Feb 8, 2025
a84bf68
R03 test
sdfghjka Feb 9, 2025
fc6d203
add feeds page
sdfghjka Feb 9, 2025
c5fa4db
create favorite model
sdfghjka Feb 9, 2025
4718ac2
add favorite/unfavorite button at index page
sdfghjka Feb 9, 2025
c86ca77
get user's favorited restaurants & switch button
sdfghjka Feb 10, 2025
d450e0a
R04 test
sdfghjka Feb 10, 2025
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
18 changes: 5 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
name: Node.js test

on:
pull_request_target:
push:
branches:
- main
# push:
# branches:
# - main
# - 'R*'
# - '*-test'
# pull_request:
# branches:
- '*-test'
pull_request:
branches:
# - main

env:
Expand Down Expand Up @@ -38,11 +34,7 @@ jobs:
# mysql user: 'github' # Required if "mysql root password" is empty, default is empty. The superuser for the specified database. Can use secrets, too
# mysql password: 'password' # Required if "mysql user" exists. The password for the "mysql user"
- run: mysql --version
- run: echo "checkout head ${{ github.event.pull_request.head.sha }}"
- run: echo "base ${{ github.event.pull_request.base.sha }}"
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
Expand Down
46 changes: 38 additions & 8 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,43 @@
const express = require('express')
const routes = require('./routes')
const express = require("express");
const routes = require("./routes");
const handlebars = require("express-handlebars");
const app = express();
const port = process.env.PORT || 3000;
const flash = require("connect-flash");
const session = require("express-session");
const SESSION_SECRET = "secret";
const passport = require("passport");
const { getUser } = require("./helpers/auth-helpers");
const handlebarsHelpers = require("./helpers/handlebars-helpers");
const methodOverride = require("method-override");
const path = require("path");

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

app.use(routes)
app.use(
session({ secret: SESSION_SECRET, resave: false, saveUninitialized: false })
);

app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(methodOverride("_method"));
app.use("/upload", express.static(path.join(__dirname, "upload")));

app.use((req, res, next) => {
res.locals.success_messages = req.flash("success_messages"); // 設定 success_msg 訊息
res.locals.error_messages = req.flash("error_messages"); // 設定 warning_msg 訊息
res.locals.user = getUser(req);
next();
});

app.use(routes);
app.engine("hbs", handlebars({ extname: ".hbs", helpers: handlebarsHelpers }));
app.set("view engine", "hbs");

app.listen(port, () => {
console.info(`Example app listening on port ${port}!`)
})
console.info(`Example app listening on port http://localhost:${port}/`);
});

module.exports = app
module.exports = app;
49 changes: 49 additions & 0 deletions config/passport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const passport = require("passport");
const LocalStrategy = require("passport-local");
const bcrypt = require("bcryptjs");
const { User, Restaurant} = require("../models");
// set up Passport strategy
passport.use(
new LocalStrategy(
// customize user field
{
usernameField: "email",
passwordField: "password",
passReqToCallback: true,
},
// authenticate user
(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((res) => {
if (!res)
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) => {
return User.findByPk(id, {
include: [{ model: Restaurant, as: "FavoritedRestaurants" },{ model: Restaurant, as: "LikeRestaurants" }],
}).then((user) => {
user = user.toJSON();
console.log(user);
return cb(null, user);
});
});
module.exports = passport;
145 changes: 145 additions & 0 deletions controllers/admin-controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
const { Restaurant, User, Category } = require("../models");
const { localFileHandler } = require("../helpers/file-helpers");
const { raw } = require("express");
const { where } = require("sequelize");

const adminController = {
getRestaurants: (req, res, next) => {
Restaurant.findAll({
raw: true,
nest: true,
include: [Category]
})

.then((restaurants) => res.render("admin/restaurants", { restaurants }))

.catch((err) => next(err));
},
createRestaurant: (req, res, next) => {
return Category.findAll({
raw: true,
})
.then((categories) =>
res.render("admin/create-restaurant", { categories })
)
.catch((err) => next(err));
},
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; // 把檔案取出來,也可以寫成 const file = req.file
localFileHandler(file) // 把取出的檔案傳給 file-helper 處理後
.then((filePath) =>
Restaurant.create({
// 再 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) => {
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 doesn'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; // 把檔案取出來
Promise.all([
// 非同步處理
Restaurant.findByPk(req.params.id), // 去資料庫查有沒有這間餐廳
localFileHandler(file), // 把檔案傳到 file-helper 處理
])
.then(([restaurant, filePath]) => {
// 以上兩樣事都做完以後
if (!restaurant) throw new Error("Restaurant didn't exist!");
return restaurant.update({
// 修改這筆資料
name,
tel,
address,
openingHours,
description,
image: filePath || restaurant.image, // 如果 filePath 是 Truthy (使用者有上傳新照片) 就用 filePath,是 Falsy (使用者沒有上傳新照片) 就沿用原本資料庫內的值
categoryId,
});
})
.then(() => {
req.flash("success_messages", "restaurant was successfully to update");
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(() => res.redirect("/admin/restaurants"))
.catch((err) => next(err));
},
getUsers: (req, res, next) => {
return User.findAll({
raw: true,
})
.then((users) => {
console.log(users)
res.render("admin/users", { users });
})
.catch((err) => next(err));
},
patchUser: (req, res, next) => {
const id = req.params.id;
return User.findByPk(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,
});
})
.then(() => {
req.flash("success_messages", "使用者權限變更成功");
return res.redirect("/admin/users");
})
.catch((err) => next(err));
},
};

module.exports = adminController;
57 changes: 57 additions & 0 deletions controllers/category-controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const { Category } = require("../models");
const categoryController = {
getCategories: (req, res, next) => {
return 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!");
Category.create({
name,
})
.then(() => {
req.flash("success_messages", "新增類別成功!");
res.redirect("/admin/categories");
})
.catch((error) => {
next(error);
});
},
putCategory: (req, res, next) => {
const { name } = req.body;
if (!name) throw new Error("Category name is required!");
return Category.findByPk(req.params.id)
.then((category) => {
if (!category) throw new Error("Category doesn't exist!");
return category.update({ name });
})
.then(() => res.redirect("/admin/categories"))
.catch((err) => next(err));
},
deleteCategory: (req, res, next) => {
const { id } = req.params;
Category.findByPk(id)
.then((Category)=>{
if (!Category) throw new Error("Category didn't exist!");
return Category.destroy();
})
.then(()=>{
req.flash("success_messages", "刪除類別成功!")
return res.redirect("/admin/categories");
})
.catch((error)=>{
next(error)
})
},
};
module.exports = categoryController;
38 changes: 38 additions & 0 deletions controllers/comment-controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const { Comment, User, Restaurant } = require("../models");
const commentController = {
postComment: (req, res, next) => {
const { restaurantId, text } = req.body;
const userId = req.user.id;
if (!text) throw new Error("Comment text is required!");
return Promise.all([
User.findByPk(userId),
Restaurant.findByPk(restaurantId),
])
.then(([user, restaurant]) => {
if (!user) throw new Error("User didn't exist!");
if (!restaurant) throw new Error("Restaurant 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((deletedComment) =>
res.redirect(`/restaurants/${deletedComment.restaurantId}`)
)
.catch((err) => next(err));
},
};
module.exports = commentController;
Loading