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

Ts 33 查看貼文及留言串 #343

Open
wants to merge 52 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
82b4a3d
feat: project init
evaaaaawu Jun 8, 2023
78ce236
Merge pull request #1 from thpss91103/TS-24
thpss91103 Jun 8, 2023
de7dba2
Ts-25 (#2)
gary86442 Jun 8, 2023
22b744d
feat:add tweets page and tweet modal
arubakingpikachu Jun 9, 2023
5cdc621
feat:add reply modal
arubakingpikachu Jun 9, 2023
ca5bf56
feat: add signup process
evaaaaawu Jun 9, 2023
dc21879
feat: use flash messages on signup page
evaaaaawu Jun 9, 2023
e168fc1
feat: add admin login page
thpss91103 Jun 9, 2023
db2a170
feat: add style.css and admin tweets page
thpss91103 Jun 9, 2023
174f3c5
feat: add admin users page
thpss91103 Jun 9, 2023
329736d
Merge pull request #4 from thpss91103/TS-3
thpss91103 Jun 9, 2023
27e50bb
feat:add followship page
arubakingpikachu Jun 9, 2023
75b1fb5
Ts-39 (#3)
gary86442 Jun 9, 2023
1857d8e
Merge branch 'main' into TS-52
gary86442 Jun 9, 2023
328012b
Merge pull request #5 from thpss91103/TS-52
gary86442 Jun 9, 2023
7c09d5a
feat:add follow or unfollow botton
arubakingpikachu Jun 9, 2023
5980747
feat: add user-other page
thpss91103 Jun 10, 2023
40892e2
feat: add user-self page
thpss91103 Jun 10, 2023
3db9be3
style: modify user/self/follower & following pages
evaaaaawu Jun 10, 2023
0fc93e4
fix: git merge origin/main conflict
evaaaaawu Jun 10, 2023
e6c4aab
Merge remote-tracking branch 'origin/TS-8'
evaaaaawu Jun 10, 2023
f594190
feat: modify user-tab route & other user page
thpss91103 Jun 10, 2023
ce5da0e
feat: add admin route
thpss91103 Jun 10, 2023
5b93681
Merge pull request #7 from thpss91103/TS-44
gary86442 Jun 10, 2023
aa967b5
Merge branch 'main' into TS-40
gary86442 Jun 10, 2023
323eea2
Merge pull request #8 from thpss91103/TS-40
gary86442 Jun 10, 2023
486e493
feat: add admin login function
thpss91103 Jun 10, 2023
3bbcc4b
feat:add view all tweets feat
arubakingpikachu Jun 10, 2023
5825cbe
Merge branch 'main' into TS-31
gary86442 Jun 11, 2023
5a83484
Merge pull request #9 from thpss91103/TS-31
gary86442 Jun 11, 2023
16156bc
feat:add _helper
arubakingpikachu Jun 11, 2023
c72e735
feat:add authenticated
arubakingpikachu Jun 11, 2023
873be1f
Merge remote-tracking branch 'origin/TS-21'
evaaaaawu Jun 11, 2023
edf14e6
style: eslint format
evaaaaawu Jun 11, 2023
2aa150b
feat: add signin and logout process
evaaaaawu Jun 11, 2023
cc55251
feat: admin can read all tweets
thpss91103 Jun 11, 2023
6b4284c
feat: use flash messages on sigin page
evaaaaawu Jun 11, 2023
18ee790
feat:add view tweet and replies
arubakingpikachu Jun 11, 2023
c9e4ed2
feat: finished admin page render user
thpss91103 Jun 11, 2023
942f1c3
Ts- 48 (#12)
gary86442 Jun 11, 2023
e584c0e
feat: modify admin controller
thpss91103 Jun 11, 2023
0d98c69
feat: modify message cover view
thpss91103 Jun 11, 2023
1f09dd2
Merge branch 'main' into TS-36
gary86442 Jun 11, 2023
b10d249
Merge pull request #14 from thpss91103/TS-36
gary86442 Jun 11, 2023
3681db5
Merge branch 'main' into TS-28
thpss91103 Jun 11, 2023
b3c48c9
Merge pull request #11 from thpss91103/TS-28
thpss91103 Jun 11, 2023
7bb58ce
feat: debug other-user and self-user page
thpss91103 Jun 11, 2023
4398dfc
Merge pull request #16 from thpss91103/TS-60
gary86442 Jun 12, 2023
074cc5a
fix: user controller 標點符號錯誤 (#17)
gary86442 Jun 12, 2023
f405201
feat:add default user avatar
arubakingpikachu Jun 12, 2023
225cc9f
fix2
arubakingpikachu Jun 12, 2023
c63938f
feat:add reply page likequantity
arubakingpikachu Jun 12, 2023
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 .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
IMGUR_CLIENT_ID=
PORT=
SESSION_SECRET=
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/node_modules/*
/test/*
12 changes: 12 additions & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
env:
browser: true
commonjs: true
es2021: true
extends:
- standard
parserOptions:
ecmaVersion: 12
rules:
arrow-parens:
- warn
- as-needed
53 changes: 53 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
* text=auto

# Source code
*.css text diff=css
*.html text diff=html
*.js text
*.json text

# Documentation
*.markdown text diff=markdown
*.md text diff=markdown
*.txt text

# Templates
*.handlebars text
*.hbs text

# Configs
*.cnf text
*.conf text
*.config text
.editorconfig text
.env text
.env.* text
.gitattributes text
.gitconfig text
*.lock text -diff
package.json text eol=lf
package-lock.json text -diff
yarn.lock text -diff
*.yaml text
*.yml text
browserslist text

# Heroku
Procfile text

# Graphics
*.gif binary
*.ico binary
*.jpg binary
*.jpeg binary
*.pdf binary
*.png binary
# SVG treated as an asset (binary) by default.
*.svg text
# If you want to treat it as binary,
# use the following line instead.
# *.svg binary
*.webp binary

# Ignore files (like .npmignore or .gitignore)
*.*ignore text
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"cSpell.words": [
"signin"
]
}
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
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Simple Twitter

## **Introduction 專案簡介**

使用 Node.js + Express + MySQL 製作的簡易社群網站,使用者可以註冊帳號、登入,並進行發文、瀏覽他人推文、回覆他人留言、對別人的推文按 Like,以及追蹤其他使用者等。

(待補:網站截圖)

## **Features 功能**

- 使用者可以註冊,並登入帳號使用網站服務
- 使用者能在首頁瀏覽所有的推文 (tweet)
- 使用者能新增推文
- 使用者能回覆別人的推文
- 使用者能對別人的推文按 Like/Unlike
- 使用者可以追蹤/取消追蹤其他使用者
- 使用者能編輯自己的名稱、自我介紹、個人頭像與封面

## **Prerequisites 環境設置**

- [VScode](https://code.visualstudio.com/)
- [Git](https://git-scm.com/downloads)
- [Node.js](https://nodejs.org/en/)
- [nodemon](https://www.npmjs.com/package/nodemon)
- [MySQL Workbench](https://dev.mysql.com/downloads/workbench/)

## **Installation 開始使用**

```
# 開啟終端機 並 Clone 此專案至本機
$ git clone https://github.com/thpss91103/twitter-fullstack-2023.git

# 於終端機進入存放本專案的資料夾
$ cd xxxxx

# 安裝 npm 套件
$ npm install

# 新增.env檔案,並請根據.env.example檔案內資訊設置環境變數

# 修改 config.json 中的 development 設定,使用個人 MySQL 的 username、password 和 database
development": {
"username": "<your username>",
"password": "<your password>",
"database": "<your database>",
"host": "127.0.0.1",
"dialect": "mysql"
}

# 新增資料表和種子資料
$ npx sequelize db:migrate
$ npx sequelize db:seed:all

# 啟動伺服器,執行 app.js 檔案
$ npm run dev

# 若在終端機看到下方訊息代表順利運行,於瀏覽器中輸入該網址(http://localhost:3000)即可開始使用本網站
"App is running on http://localhost:3000"
```

## **Contributors 貢獻者**

(待補)
12 changes: 6 additions & 6 deletions _helpers.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
function ensureAuthenticated(req) {
return req.isAuthenticated();
function ensureAuthenticated (req) {
return req.isAuthenticated()
}

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

module.exports = {
ensureAuthenticated,
getUser,
};
getUser
}
40 changes: 36 additions & 4 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,45 @@
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config()
}

const express = require('express')
const helpers = require('./_helpers');
const exphbs = require('express-handlebars')
const routes = require('./routes')
const methodOverride = require('method-override')
const session = require('express-session')
const passport = require('./config/passport')
const flash = require('connect-flash')
const helpers = require('./helpers/auth-helpers')
const handlebarsHelpers = require('./helpers/handlebars-helpers')

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

app.engine('hbs', exphbs({ defaultLayout: 'main', extname: '.hbs', helpers: handlebarsHelpers }))
app.set('view engine', 'hbs')

app.use(express.static('public'))
app.use(express.urlencoded({ extended: true }))
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false
}))
app.use(passport.initialize())
app.use(passport.session())
app.use(flash())
app.use(methodOverride('_method'))
app.use((req, res, next) => {
res.locals.success_messages = req.flash('success_messages')
res.locals.error_messages = req.flash('error_messages')
res.locals.user = helpers.getUser(req)
next()
})
// use helpers.getUser(req) to replace req.user
// use helpers.ensureAuthenticated(req) to replace req.isAuthenticated()

app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
app.use(routes)

app.listen(port, () => console.log(`App is running on http://localhost:${port}`))

module.exports = app
45 changes: 45 additions & 0 deletions config/passport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const passport = require('passport')
const LocalStrategy = require('passport-local')
const bcrypt = require('bcryptjs')
const { User, Tweet } = require('../models')
// set up Passport strategy
passport.use(new LocalStrategy(
// customize user field
{
usernameField: 'account',
passwordField: 'password',
passReqToCallback: true
},
// authenticate user
(req, account, password, cb) => {
User.findOne({ where: { account } })
.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(async (id, cb) => {
try {
const user = await User.findByPk(id, {
include: [
// 關聯資料
{ model: Tweet },
{ model: User, as: 'Followers' },
{ model: User, as: 'Followings' }
]
})
return cb(null, user.toJSON())
} catch (err) {
cb(err)
}
})

module.exports = passport
62 changes: 62 additions & 0 deletions controllers/admin-controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

const { Tweet, User, Like, Followship } = require('../models')

const adminController = {
getSignin: (req, res) => {
res.render('admin/signin')
},
adminSignin: (req, res) => {
req.flash('success_messages', '成功登入!')
res.redirect('/admin/tweets')
},
getTweets: (req, res, next) => {
const tweetRoute = true // admin sidebar判斷目前路由
Tweet.findAll({
raw: true,
nest: true,
include: [User],
order: [['createdAt', 'DESC']]
})
.then(tweets => {
res.render('admin/tweets', { tweets, tweetRoute })
})
.catch(err => next(err))
},
deleteTweets: (req, res, next) => {
return Tweet.findByPk(req.params.id)
.then(tweet => {
if (!tweet) throw new Error("Tweet did'n exist!")
return tweet.destroy()
})
.then(() => res.redirect('/admin/tweets'))
.catch(err => next(err))
},
getUsers: async (req, res, next) => {
const users = await User.findAll({
raw: true
})
const userData = await Promise.all(users.map(async user => {
const userId = user.id
const [tweets, likes, followers, followings] = await Promise.all([ // 用user id進去個表格找
Tweet.findAll({ where: { userId }, raw: true }),
Like.findAll({ where: { userId }, raw: true }),
Followship.findAll({ where: { followerId: userId }, raw: true }),
Followship.findAll({ where: { followingId: userId }, raw: true })
])
user.tweetsCount = tweets?.length // 照到後計算個陣列個數
user.likesCount = likes?.length
user.followersCount = followers?.length
user.followingsCount = followings?.length
return user
}))

res.render('admin/users', { user: userData })
},
getLogout: (req, res) => {
req.flash('success_messages', '登出成功!')
req.logout()
res.redirect('/signin')
}
}

module.exports = adminController
27 changes: 27 additions & 0 deletions controllers/tweet-controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { Tweet, User, Reply, Like } = require('../models')

const tweetController = {
getTweets: async (req, res, next) => {
try {
const tweets = await Tweet.findAll({ raw: true, nest: true, include: [User] })
const sortedTweets = tweets.sort((a, b) => b.createdAt - a.createdAt)
return res.render('tweets', { tweets: sortedTweets })
} catch (err) {
next(err)
}
},
getTweetReplies: async (req, res, next) => {
try {
const tweet = await Tweet.findByPk(req.params.id, { raw: true, nest: true, include: [User] })
const replies = await Reply.findAll({ where: { Tweet_id: req.params.id }, include: [User, { model: Tweet, include: User }], raw: true, nest: true })
const likes = await Like.findAll({ where: { Tweet_id: req.params.id }, raw: true, nest: true })
const replyQuantity = replies.length
const likeQuantity = likes.length
return res.render('reply-list', { tweet, replies, replyQuantity, likeQuantity })
} catch (err) {
next(err)
}
}
}

module.exports = tweetController
Loading