一、個人信息增改查
1、編輯個人資料,隱藏一些信息,在獲取特定用戶資料時顯示信息
在models/user.js中寫userSchema:
const mongoose = require('mongoose');
const { Schema, model} = mongoose;
const userSchema = new Schema({
__v:{type:Number, select:false},
name: { type: String, required: true},
password: {type: String, required: true,select: false},
avatar_url: {type: String},
gender: {type: String, enum: ['male','female'], default: 'male', required: true}, //enum是可枚舉
headline: {type: String},
locations:{type: [{type:String}],select: false},
business: {type: String,select: false},
employments:{type: [{ //工作
company: {type: String},
job:{type: String}
}],select: false},
educations:{
type: [{
school:{type: String},
major: {type: String}, //專業
diploma: {type: Number,enum:[1,2,3,4,5]}, //學歷
entrance_year: {type: Number}, //入學年份
graduation_year: {type: Number}
}],select: false
}
});
module.exports = model('ZhihuUser', userSchema);
在routes/user.js中:
const Router = require('koa-router');
const userRouter = new Router({prefix: '/user'});
const {find, findById, create, update} = require('../controllers/user');
userRouter.get('/',find);
userRouter.get('/:id',findById);
userRouter.post('/', create);
userRouter.post('/update/:id',update); //編輯個人資料
module.exports = userRouter;
在controllers/user.js中:
const User = require('../model/user');
class UserCtl {
async find(ctx) {
ctx.body = await User.find();
}
// 獲取特定用戶資料時顯示信息
async findById(ctx) {
// 獲取請求參數
const {fields} = ctx.query; //返回字符串:locations;educations
const selectFields = fields.split(';').filter(f=>f).map(f=> ' +' + f).join(''); //轉化爲: +location+educations
const user = await User.findById(ctx.params.id).select(selectFields);
if(!user) {
ctx.throw(404, '用戶不存在');
}
ctx.body = user;
}
async create(ctx) {
ctx.verifyParams({
name: {type: 'string',require: true},
password: {type: 'string',require: true}
})
const {name} = ctx.request.body;
const userName = await User.findOne({name});
if(userName) {
ctx.throw(409, '用戶名已存在');
}
const user = await new User(ctx.request.body).save();
ctx.body = user;
}
// 編輯個人資料
async update(ctx) {
console.log(ctx);
ctx.verifyParams({
name: {type: 'string',require: true},
password: {type: 'string',require: false},
avatar_url: {type: 'string',require: false},
gender: {type: 'string',require: false},
headline: {type: 'string',require: false},
locations: {type:'array',itemType:'string',require:false},
business: {type: 'string',require:false},
employments: {type: 'array',itemType:'object', require:false},
eduactions: {type: 'array',itemType:'object', require: false}
})
const user = await User.findByIdAndUpdate(ctx.params.id, ctx.request.body);
console.log(user);
if(!user) {
ctx.throw(404,'用戶不存在');
}
ctx.body = user;
}
}
module.exports = new UserCtl();
二、用戶關注用戶
1.model/user.js:
const mongoose = require('mongoose');
const { Schema, model} = mongoose;
const userSchema = new Schema({
__v:{type:Number, select:false},
name: { type: String, required: true},
password: {type: String, required: true }, //,select: false
avatar_url: {type: String},
gender: {type: String, enum: ['male','female'], default: 'male', required: true}, //enum是可枚舉
headline: {type: String},
locations:{type: [{type:String}],select: false},
business: {type: String,select: false},
employments:{type: [{ //工作
company: {type: String},
job:{type: String}
}],select: false},
educations:{
type: [{
school:{type: String},
major: {type: String}, //專業
diploma: {type: Number,enum:[1,2,3,4,5]}, //學歷
entrance_year: {type: Number}, //入學年份
graduation_year: {type: Number}
}],select: false
},
// 獲取用戶關注人列表
following: {
type: [{type: Schema.Types.ObjectId,ref: 'ZhihuUser'}], // 存儲用戶id,與ZhihuUser集合關聯
select: false
}
});
module.exports = model('ZhihuUser', userSchema);
2.router/user.js
const Router = require('koa-router');
const userRouter = new Router({prefix: '/user'});
const jwt = require('koa-jwt');
const {secret} = require('../config.js');
const auth = jwt({secret: secret});
const {login, find, findById, create, update, listFollowing, checkOwner, following} = require('../controllers/user');
userRouter.post('/login',login);
userRouter.get('/',find);
userRouter.get('/:id',findById);
userRouter.post('/', create); //創建用戶
userRouter.post('/update/:id',auth, checkOwner, update); //更新用戶信息
userRouter.get('/:id/following',auth, checkOwner, listFollowing); //獲取用戶關注人列表
userRouter.put('/following/:id',auth,following); //關注操作
userRouter.delete('/unfollowing/:id',auth,unfollowing); //取消關注操作
module.exports = userRouter;
3.controllers/user.js:
const User = require('../model/user');
const jsonwebtoken = require('jsonwebtoken');
const {secret} = require('../config');
class UserCtl {
// 登陸返回token
async login(ctx) {
ctx.verifyParams({
name: {type: 'string', required: true},
password: {type: 'string', required: true}
})
const user = await User.findOne(ctx.request.body);
if(!user) {
ctx.throw(401, '用戶名或密碼不正確');
}
const {_id, name} = user;
ctx.body = _id
const token = jsonwebtoken.sign({_id,name}, secret, {expiresIn: '10d'});
// const token = jsonwebtoken.sign({_id,name}, secret, {expiresIn: '1d'})
ctx.body = {token};
}
async checkOwner(ctx, next) {
ctx.body = ctx.state.user;
if(ctx.params.id != ctx.state.user._id) {
ctx.throw(403, '沒有權限')
}
await next();
}
// 獲取用戶列表 (有分頁功能)
async find(ctx) {
const {per_page = 10} = ctx.query;
const page = Math.max(ctx.query.page*1,1)-1;
const perPage = Math.max(per_page*1,1);
ctx.body = await User.find().limit(perPage).skip(perPage*page);
}
async findById(ctx) {
// 獲取請求參數
const {fields} = ctx.query; //返回字符串:locations;educations
const selectFields = fields.split(';').filter(f=>f).map(f=> ' +' + f).join('');//返回字符串:+locations+educations
const user = await User.findById(ctx.params.id).select(selectFields);
if(!user) {
ctx.throw(404, '用戶不存在');
}
ctx.body = user;
}
async create(ctx) {
ctx.verifyParams({
name: {type: 'string',required: true},
password: {type: 'string',required: true}
})
const {name} = ctx.request.body;
const userName = await User.findOne({name});
if(userName) {
ctx.throw(409, '用戶名已存在');
}
const user = await new User(ctx.request.body).save();
ctx.body = user;
}
async update(ctx) {
console.log(ctx);
ctx.verifyParams({
name: {type: 'string',required: true},
password: {type: 'string',required: false},
avatar_url: {type: 'string',required: false},
gender: {type: 'string',required: false},
headline: {type: 'string',required: false},
locations: {type:'array',itemType:'string',required:false},
business: {type: 'string',required:false},
employments: {type: 'array',itemType:'object', required:false},
eduactions: {type: 'array',itemType:'object', required: false}
})
const user = await User.findByIdAndUpdate(ctx.params.id, ctx.request.body);
console.log(user);
if(!user) {
ctx.throw(404,'用戶不存在');
}
ctx.body = user;
}
// 獲取用戶關注人列表
async listFollowing(ctx) {
const user = await User.findById(ctx.params.id).select('+following').populate('following'); // select()默認只顯示id,加populate()顯示其他信息
if(!user) {ctx.throw(404, '用戶不存在')};
ctx.body = user.following;
}
// 關注操作
async following(ctx) {
const me = await User.findById(ctx.state.user._id).select('+following');
if(!me.following.map(id=>id.toString()).includes(ctx.params.id)) {
me.following.push(ctx.params.id);
me.save();
}
ctx.status = 204;
}
// 取消關注
async unfollowing(ctx) {
const me= await User.findById(ctx.state.user._id).select('+following');
const index = me.following.map(id=>id.toString()).indexof(ctx.params.id);
if(index > -1) {
me.following.split(index,1);
me.save();
}
}
}
module.exports = new UserCtl();
4.登錄測試:
5.在tests中設置全局變量token:
6.在獲取用戶關注人列表時設置請求頭的Authorization爲全局變量token
三、話題增改查
1.創建/model/topic.js:
const mongoose = require('mongoose');
const { Schema, model } = require('mongoose');
const TopicSchema = new Schema({
__v: {type: Number, select: false},
name: {type: String,required: true},
avatar_url: {type: String},
introduction: {type: String, select: false}
})
module.exports = model('zhihuTopic',TopicSchema);
2.創建/router/topic.js:
const koa= require('koa');
const Router = require('koa-router');
const topicRouter = new Router({prefix: '/topic'});
const {find, create, update} = require('../controllers/topic.js');
topicRouter.get('/',find); //獲取話題
topicRouter.post('/create', create);
topicRouter.post('/update/:id',update);
module.exports = topicRouter;
3.創建/controller/topic.js
const Topic = require('../model/topic');
class TopicCtl {
// 查詢話題(有分頁功能,模糊搜索)
// /topic?page=1&per_page=10&q=模糊搜索字符
async find(ctx) {
const {per_page = 10} = ctx.query;
const page = Math.max(ctx.query.page*1,1)-1;
console.log(Math.max(ctx.query.page*1,1));
const perPage = Math.max(per_page*1,1);
const topic = await Topic.find({name:new RegExp(ctx.query.q)}).limit(perPage).skip(page*perPage);
ctx.body = topic;
}
// 創建話題
async create(ctx) {
ctx.verifyParams({
name: {type: 'string',required: true},
avatar_url: {type: 'string',required:false},
introduction: {type: 'string',required:false}
})
const topic = await new Topic(ctx.request.body).save();
ctx.body = topic;
}
// 更新話題
async update(ctx) {
ctx.verifyParams({
name:{type: 'string',required:false},
avatar_url: {type: 'string', required: false},
introduction:{type:'string', required: false}
})
const topic = await Topic.findByIdAndUpdate(ctx.params.id, ctx.request.body);
ctx.body = topic;
}
}
module.exports = new TopicCtl();
四、將用戶的信息連接話題(用戶的城市、工作、學校、專業等都可以是話題)
做法:用戶的schema參數連接話題的集合id
將model/user.js修改(locations,business,educations,employments):
const mongoose = require('mongoose');
const { Schema, model} = mongoose;
const userSchema = new Schema({
__v:{type:Number, select:false},
name: { type: String, required: true},
password: {type: String, required: true }, //,select: false
avatar_url: {type: String},
gender: {type: String, enum: ['male','female'], default: 'male', required: true}, //enum是可枚舉
headline: {type: String},
locations:{type: [{type:Schema.Types.ObjectId, ref:'zhihuTopic'}],select: false},
business: {type: Schema.Types.ObjectId, ref:'zhihuTopic',select: false},
employments:{type: [{ //工作
company: {type: Schema.Types.ObjectId, ref:'zhihuTopic'},
job:{type: Schema.Types.ObjectId, ref:'zhihuTopic'}
}],select: false},
educations:{
type: [{
school:{type: Schema.Types.ObjectId, ref:'zhihuTopic'},
major: {type: Schema.Types.ObjectId, ref:'zhihuTopic'}, //專業
diploma: {type: Number,enum:[1,2,3,4,5]}, //學歷
entrance_year: {type: Number}, //入學年份
graduation_year: {type: Number}
}],select: false
},
// 獲取用戶關注人列表
following: {
type: [{type: Schema.Types.ObjectId,ref: 'ZhihuUser'}], // 存儲用戶id,與ZhihuUser集合關聯
select: false
}
});
module.exports = model('ZhihuUser', userSchema);
修改controllers/user.js(findById):
async findById(ctx) {
// 獲取請求參數
const {fields} = ctx.query; //返回字符串:locations;educations
const selectFields = fields.split(';').filter(f=>f).map(f=> ' +' + f).join('');//返回字符串:+locations+educations
const populateStr = fields.split(';').filter(f=>f).map(f=> {
console.log(f)
if(f === 'employments') {
return 'employments.company employments.job'
}
if(f === 'educations') {
return 'educations.school educations.major'
}
return f;
}).join(' ');
const user = await User.findById(ctx.params.id).select(selectFields).populate(populateStr); //select()是顯示隱藏的參數,populate()是顯示連接其他集合的數據
if(!user) {
ctx.throw(404, '用戶不存在');
}
ctx.body = user;
}
五、用戶關注取關話題
1.在model/user.js中增加followingTopic字段:
const mongoose = require('mongoose');
const { Schema, model} = mongoose;
const Topic = require('./topic');
const userSchema = new Schema({
__v:{type:Number, select:false},
name: { type: String, required: true},
password: {type: String, required: true }, //,select: false
avatar_url: {type: String},
gender: {type: String, enum: ['male','female'], default: 'male', required: true}, //enum是可枚舉
headline: {type: String},
locations:{type: [{type:Schema.Types.ObjectId, ref:Topic}],select: false},
business: {type: Schema.Types.ObjectId, ref:Topic,select: false},
employments:{type: [{ //工作
company: {type: Schema.Types.ObjectId, ref:Topic},
job:{type: Schema.Types.ObjectId, ref:Topic}
}],select: false},
educations:{
type: [{
school:{type: Schema.Types.ObjectId, ref:Topic},
major: {type: Schema.Types.ObjectId, ref:'Topic'}, //專業
diploma: {type: Number,enum:[1,2,3,4,5]}, //學歷
entrance_year: {type: Number}, //入學年份
graduation_year: {type: Number}
}],select: false
},
// 獲取用戶關注人列表
following: {
type: [{type: Schema.Types.ObjectId,ref: 'ZhihuUser'}], // 存儲用戶id,與ZhihuUser集合關聯
select: false
},
followingTopic:{
type: [{type:Schema.Types.ObjectId, ref: Topic}], // 存儲話題id,與話題model關聯
select: false
}
});
module.exports = model('ZhihuUser', userSchema);
2.router/user.js中增加 獲取用戶關注的話題、關注話題、取消關注話題:
const Router = require('koa-router');
const userRouter = new Router({prefix: '/user'});
const jwt = require('koa-jwt');
const {secret} = require('../config.js');
const auth = jwt({secret: secret});
const {login, find, findById, create, update, listFollowing, checkOwner, following, unfollowing, listFollowingTopic, followingTopic, unfollowingTopic, listQuestions} = require('../controllers/user');
const { checkTopicExist } = require('../controllers/topic');
userRouter.post('/login',login);
userRouter.get('/',find);
userRouter.get('/:id',findById);
userRouter.post('/', create); //創建用戶
userRouter.post('/update/:id',auth, checkOwner, update); //更新用戶信息
userRouter.get('/:id/following',auth, checkOwner, listFollowing); //獲取用戶關注人列表
userRouter.put('/following/:id',auth,following); //關注操作
userRouter.delete('/unfollowing/:id',auth,unfollowing); //取消關注操作
userRouter.get('/:id/listFollowingTopic',auth,listFollowingTopic); //獲取用戶關注的話題
userRouter.put('/followingTopic/:id',auth, checkTopicExist, followingTopic); //關注話題
userRouter.delete('/unfollowingTopic/:id',auth, checkTopicExist, unfollowingTopic); //取消關注話題
module.exports = userRouter;
3.在controllers/user.js中:
const User = require('../model/user');
const Questions = require('../model/questions');
const jsonwebtoken = require('jsonwebtoken');
const {secret} = require('../config');
class UserCtl {
。。。。。。
// 獲取用戶關注的話題
async listFollowingTopic(ctx) {
const user = await User.findById(ctx.params.id).select('+followingTopic').populate('followingTopic');
console.log(user);
if(!user) {
ctx.throw(404, '用戶不存在');
}
ctx.body = user.followingTopic;
}
// 關注話題
async followingTopic(ctx) {
const user = await User.findById(ctx.state.user._id).select('+followingTopic');
console.log(user);
if(!user.followingTopic.includes(ctx.params.id)) {
user.followingTopic.push(ctx.params.id);
user.save();
}
// ctx.status = 204;
ctx.body = user;
}
// 取消關注話題
async unfollowingTopic(ctx) {
const user = await User.findById(ctx.state.user._id).select('+followingTopic');
console.log(user.followingTopic);
// const index = me.following.map(id=>id.toString()).indexof(ctx.params.id);
const index = user.followingTopic.map(id=>id.toString()).indexOf(ctx.params.id);
console.log(index);
if(index > -1) {
user.followingTopic.splice(index,1);
user.save();
}
}
}
module.exports = new UserCtl();
六、問題的增刪改查
1.創建model/questions.js:
const mongoose = require('mongoose');
const {Schema, model} = mongoose;
const User = require('./user.js');
const questionSchema = new Schema({
title: {type: String,required: true},
description:{type:String,required: false},
questioner: {type: Schema.Types.ObjectId, ref:User, required:true}
});
module.exports = model('ZhihuQuestions', questionSchema);
2.創建routers/questions.js:
const Router = require('koa-router');
const questionsRouter = new Router({prefix: '/questions'});
const {find,listQuestions, create, update, delete:del, checkQuestionExist, checkQuestioner }= require('../controllers/questions');
const jwt = require('koa-jwt');
const {secret} = require('../config.js');
const auth = jwt({secret: secret});
questionsRouter.get('/', find);
questionsRouter.get('/:id/listQuestions');
questionsRouter.post('/create',auth, create);
questionsRouter.put('/update/:id',auth,checkQuestionExist, checkQuestioner, update);
questionsRouter.delete('/delete/:id',auth,checkQuestionExist, checkQuestioner, del);
module.exports = questionsRouter;
3.創建controllers/questions.js:
const Questions = require('../model/questions');
class QuestionCtl {
// 檢測創建問題的用戶是否是當前用戶,判定是否有修改刪除問題的權限
async checkQuestioner(ctx, next) {
const {question} = ctx.state;
if(question.questioner!=ctx.state.user._id) {
ctx.throw(403,'沒有權限');
}
await next();
}
// 獲取問題列表(模糊搜索)
async find(ctx) {
// const questions = await Questions.find();
const page = Math.max(ctx.query.page, 1) - 1;
const {per_page = 10} = ctx.query;
const perPage = Math.max(per_page, 1);
const q = new RegExp(ctx.query.q)
const questions = await Questions.find({$or:[{title:q},{description:q}]}).limit(perPage).skip(page*perPage);
ctx.body = questions;
}
// 查詢問題是否存在
async checkQuestionExist(ctx, next) {
const question = await Questions.findById(ctx.params.id).select('questioner');
ctx.state.question = question;
if(!question) {
ctx.throw(404,'該問題不存在');
}
await next();
}
// 創建問題
async create(ctx) {
ctx.verifyParams({
title: {type: 'string', required:true},
description:{type: 'string', required:false}
})
const question = await new Questions({...ctx.request.body,questioner: ctx.state.user._id}).save();
ctx.body = question;
}
async update(ctx) {
ctx.verifyParams({
title: {type: 'string', required:true},
description:{type: 'string', required:false}
})
await ctx.state.question.update(ctx.request.body);
ctx.body = ctx.state.question;
}
async delete(ctx) {
const question = await Questions.findByIdAndRemove(ctx.params.id);
ctx.status = 204;
}
}
module.exports = new QuestionCtl();