Skip to content

Node blog #4

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

Merged
merged 3 commits into from
Sep 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 20 additions & 0 deletions myblog/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,26 @@ app.use(session({
// flash 中间件,用来显示通知
app.use(flash())

// 处理表单及文件上传的中间件
app.use(require('express-formidable')({
uploadDir: path.join(__dirname, 'public/img'), // 上传文件目录
keepExtensions: true // 保留后缀
}))

// 设置模板全局常量
app.locals.blog = {
title: pkg.name,
description: pkg.description
}

// 添加模板必需的三个变量
app.use(function (req, res, next) {
res.locals.user = req.session.user
res.locals.success = req.flash('success').toString()
res.locals.error = req.flash('error').toString()
next()
})

// 路由
routes(app)

Expand Down
14 changes: 14 additions & 0 deletions myblog/lib/mongo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const config = require('config-lite')(__dirname)
const Mongolass = require('mongolass')
const mongolass = new Mongolass()
mongolass.connect(config.mongodb)

exports.User = mongolass.model('User', {
name: { type: 'string', required: true },
password: { type: 'string', required: true },
avatar: { type: 'string', required: true },
gender: { type: 'string', enum: ['m', 'f', 'x'], default: 'x' },
bio: { type: 'string', required: true }
})

exports.User.index({ name: 1 }, { unique: true }).exec() // 根据用户名找到用户,用户名全局唯一
8 changes: 8 additions & 0 deletions myblog/models/users.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const User = require('../lib/mongo').User

module.exports = {
// 注册一个用户
create: function create (user) {
return User.create(user).exec()
}
}
78 changes: 78 additions & 0 deletions myblog/public/css/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* ---------- 全局样式 ---------- */

body {
width: 1100px;
height: 100%;
margin: 0 auto;
padding-top: 40px;
}

a:hover {
border-bottom: 3px solid #4fc08d;
}

.button {
background-color: #4fc08d !important;
color: #fff !important;
}

.avatar {
border-radius: 3px;
width: 48px;
height: 48px;
float: right;
}

/* ---------- nav ---------- */

.nav {
margin-bottom: 20px;
color: #999;
text-align: center;
}

.nav h1 {
color: #4fc08d;
display: inline-block;
margin: 10px 0;
}

/* ---------- nav-setting ---------- */

.nav-setting {
position: fixed;
right: 30px;
top: 35px;
z-index: 999;
}

.nav-setting .ui.dropdown.button {
padding: 10px 10px 0 10px;
background-color: #fff !important;
}

.nav-setting .icon.bars {
color: #000;
font-size: 18px;
}

/* ---------- post-content ---------- */

.post-content h3 a {
color: #4fc08d !important;
}

.post-content .tag {
font-size: 13px;
margin-right: 5px;
color: #999;
}

.post-content .tag.right {
float: right;
margin-right: 0;
}

.post-content .tag.right a {
color: #999;
}
2 changes: 1 addition & 1 deletion myblog/routes/posts.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const checkLogin = require('../middlewares/check').checkLogin
// GET /posts 所有用户或者特定用户的文章页
// eg: GET /posts?author=xxx
router.get('/', function (req, res, next) {
res.send('主页')
res.render('posts')
})

// POST /posts/create 发表一篇文章
Expand Down
76 changes: 74 additions & 2 deletions myblog/routes/signup.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,87 @@
const fs = require('fs')
const path = require('path')
const sha1 = require('sha1')
const express = require('express')
const router = express.Router()

const UserModel = require('../models/users')
const checkNotLogin = require('../middlewares/check').checkNotLogin

// GET /signup 注册页
router.get('/', checkNotLogin, function (req, res, next) {
res.send('注册页')
res.render('signup')
})

// POST /signup 用户注册
router.post('/', checkNotLogin, function (req, res, next) {
res.send('注册')
const name = req.fields.name
const gender = req.fields.gender
const bio = req.fields.bio
const avatar = req.files.avatar.path.split(path.sep).pop()
let password = req.fields.password
const repassword = req.fields.repassword

// 校验参数
try {
if (!(name.length >= 1 && name.length <= 10)) {
throw new Error('名字请限制在 1-10 个字符')
}
if (['m', 'f', 'x'].indexOf(gender) === -1) {
throw new Error('性别只能是 m、f 或 x')
}
if (!(bio.length >= 1 && bio.length <= 30)) {
throw new Error('个人简介请限制在 1-30 个字符')
}
if (!req.files.avatar.name) {
throw new Error('缺少头像')
}
if (password.length < 6) {
throw new Error('密码至少 6 个字符')
}
if (password !== repassword) {
throw new Error('两次输入密码不一致')
}
} catch (e) {
// 注册失败,异步删除上传的头像
fs.unlink(req.files.avatar.path)
req.flash('error', e.message)
return res.redirect('/signup')
}

// 明文密码加密
password = sha1(password)

// 待写入数据库的用户信息
let user = {
name: name,
password: password,
gender: gender,
bio: bio,
avatar: avatar
}
// 用户信息写入数据库
UserModel.create(user)
.then(function (result) {
// 此 user 是插入 mongodb 后的值,包含 _id
user = result.ops[0]
// 删除密码这种敏感信息,将用户信息存入 session
delete user.password
req.session.user = user
// 写入 flash
req.flash('success', '注册成功')
// 跳转到首页
res.redirect('/posts')
})
.catch(function (e) {
// 注册失败,异步删除上传的头像
fs.unlink(req.files.avatar.path)
// 用户名被占用则跳回注册页,而不是错误页
if (e.message.match('duplicate key')) {
req.flash('error', '用户名已被占用')
return res.redirect('/signup')
}
next(e)
})
})

module.exports = router
18 changes: 18 additions & 0 deletions myblog/views/components/nav-setting.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<div class="nav-setting">
<div class="ui buttons">
<div class="ui floating dropdown button">
<i class="icon bars"></i>
<div class="menu">
<% if (user) { %>
<a class="item" href="/posts?author=<%= user._id %>">个人主页</a>
<div class="divider"></div>
<a class="item" href="/posts/create">发表文章</a>
<a class="item" href="/signout">登出</a>
<% } else { %>
<a class="item" href="/signin">登录</a>
<a class="item" href="/signup">注册</a>
<% } %>
</div>
</div>
</div>
</div>
10 changes: 10 additions & 0 deletions myblog/views/components/nav.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<div class="nav">
<div class="ui grid">
<div class="four wide column"></div>

<div class="eight wide column">
<a href="/posts"><h1><%= blog.title %></h1></a>
<p><%= blog.description %></p>
</div>
</div>
</div>
18 changes: 18 additions & 0 deletions myblog/views/components/notification.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<div class="ui grid">
<div class="four wide column"></div>
<div class="eight wide column">

<% if (success) { %>
<div class="ui success message">
<p><%= success %></p>
</div>
<% } %>

<% if (error) { %>
<div class="ui error message">
<p><%= error %></p>
</div>
<% } %>

</div>
</div>
15 changes: 15 additions & 0 deletions myblog/views/footer.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script type="text/javascript">
$(document).ready(function () {
// 点击按钮弹出下拉框
$('.ui.dropdown').dropdown();

// 鼠标悬浮在头像上,弹出气泡提示框
$('.post-content .avatar-link').popup({
inline: true,
position: 'bottom right',
lastResort: 'bottom right'
});
})
</script>
</body>
</html>
14 changes: 14 additions & 0 deletions myblog/views/header.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%= blog.title %></title>
<link rel="stylesheet" href="//cdn.bootcss.com/semantic-ui/2.1.8/semantic.min.css">
<link rel="stylesheet" href="/css/style.css">
<script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<script src="//cdn.bootcss.com/semantic-ui/2.1.8/semantic.min.js"></script>
</head>
<body>
<%- include('components/nav') %>
<%- include('components/nav-setting') %>
<%- include('components/notification') %>
3 changes: 3 additions & 0 deletions myblog/views/posts.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<%- include('header') %>
这是主页
<%- include('footer') %>
40 changes: 40 additions & 0 deletions myblog/views/signup.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<%- include('header') %>

<div class="ui grid">
<div class="four wide column"></div>
<div class="eight wide column">
<form class="ui form segment" method="post" enctype="multipart/form-data">
<div class="field required">
<label>用户名</label>
<input placeholder="用户名" type="text" name="name">
</div>
<div class="field required">
<label>密码</label>
<input placeholder="密码" type="password" name="password">
</div>
<div class="field required">
<label>重复密码</label>
<input placeholder="重复密码" type="password" name="repassword">
</div>
<div class="field required">
<label>性别</label>
<select class="ui compact selection dropdown" name="gender">
<option value="m">男</option>
<option value="f">女</option>
<option value="x">保密</option>
</select>
</div>
<div class="field required">
<label>头像</label>
<input type="file" name="avatar">
</div>
<div class="field required">
<label>个人简介</label>
<textarea name="bio" rows="5"></textarea>
</div>
<input type="submit" class="ui button fluid" value="注册">
</form>
</div>
</div>

<%- include('footer') %>