├── README.md ├── app.js ├── bin └── timebank ├── controller ├── post.js └── user.js ├── dao ├── applicationDao.js ├── index.js ├── itemDao.js ├── postDao.js ├── stuInfoDao.js ├── tipDao.js ├── tradeDao.js └── userDao.js ├── db ├── mongo.js └── redis.js ├── library ├── checkToken.js ├── delToken.js ├── genToken.js ├── tools.js └── winstonlogger.js ├── model ├── item.js ├── post.js ├── stuInfo.js ├── tip.js ├── trade.js ├── user.js └── userActionLogs.js ├── package.json ├── pictures ├── 微信图片_20170523161807.jpg ├── 微信图片_20170523161817.jpg ├── 微信图片_20170523161821.jpg ├── 微信图片_20170523161826.jpg ├── 微信图片_20170523161831.jpg ├── 微信图片_20170523161837.jpg ├── 微信图片_20170523161843.jpg ├── 微信图片_20170523161854.jpg ├── 微信图片_20170523161858.jpg ├── 微信图片_20170523161908.jpg └── 微信图片_20170523161912.jpg ├── routes ├── index.html └── index.js └── views ├── error.jade ├── index.jade └── layout.jade /README.md: -------------------------------------------------------------------------------- 1 | # LiBond 2 | email:2317809590@qq.com 3 | 一个基于帖子的校园互助交友平台。人们需要使用这个平台首先需要使用手机号注册一个账户。注册以后会得到30个虚拟币(荔枝)。用户(A)可以使用荔枝在该平台上发布 4 | 一个帖子寻求帮助。其他用户(B)如果对用户A的帖子感兴趣,可以报名该帖子成为任务人。当完成了任务以后,A需要支付给定的荔枝给B。此外用户也可以通过签到获得荔枝。 5 | 用户在这个平台上可以利用空闲的时间帮助别人,也可以从中获取帮助。在这个过程中,可能使互不相识的人成为好朋友。该平台也会发起用荔枝兑换奖品的活动来吸引用户。 6 | ## 应用场景 7 | 我们在高校中经常会遇到一些问题,比如说自己在校外却收到快递公司的收货短信、天气很好想找个伴去游泳、因为有事希望去食堂打包。这些都是很常见的需求。很多时候, 8 | 其他人也刚好想去游泳,或者他刚好就在快递领取点,可以很方便地帮你拿回快递。但是高校却没有一个很好的解决方案。因此我们就想要做这样一个产品,营造更好的校园 9 | 氛围。 10 | 11 | ## 技术架构 12 | 该产品采用前后端分离的方式进行构建。前端可以是APP和网页(包括移动web应用)。后端使用nodejs的Express框架编写接口,数据使用MongoDB进行存储。此外还使用 13 | redis存储一些用户验证的数据。前端通过调用后端的接口进行数据交换。我负责后端接口的开发,这里也只是展示后端的具体实现过程。如果你对具体实现技术或者这个 14 | 项目感兴趣的话,欢迎和我联系。 15 | 16 | ## APP功能展示 17 | 打开APP会进入登录界面,如果用户没有账号,需要注册: 18 | 19 | ![登录界面](https://github.com/Roujack/LiBond/blob/master/pictures/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20170523161817.jpg) 20 | 21 | 登录以后,将会进入APP主界面,可以看到,APP分为五大板块:互助圈、任务、推送、聊天、通知。 22 | 23 | ![主界面](https://github.com/Roujack/LiBond/blob/master/pictures/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20170523161821.jpg) 24 | 25 | ### 个人中心 26 | 点击头像,会进入个人中心: 27 | 28 | ![个人中心,管理用户自己的一些信息](https://github.com/Roujack/LiBond/blob/master/pictures/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20170523161807.jpg) 29 | 30 | ![查看我的钱包](https://github.com/Roujack/LiBond/blob/master/pictures/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20170523161837.jpg) 31 | 32 | 在我的钱包下面,有libond商城,是用来兑换奖品的。用户可以拿荔枝兑换喜欢的物品: 33 | 34 | ![liBond商城](https://github.com/Roujack/LiBond/blob/master/pictures/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20170523161843.jpg) 35 | 36 | ### 互助圈 37 | 在互助圈,可以发布帖子,也可以浏览别人发布的帖子,并领取感兴趣的任务: 38 | 39 | ![发布一个帖子](https://github.com/Roujack/LiBond/blob/master/pictures/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20170523161826.jpg) 40 | 41 | ![浏览帖子](https://github.com/Roujack/LiBond/blob/master/pictures/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20170523161831.jpg) 42 | 43 | ### 任务 44 | 在任务一栏,分我领取的任务以及我发布的帖子两个部分: 45 | 46 | ![我发布的帖子](https://github.com/Roujack/LiBond/blob/master/pictures/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20170523161854.jpg) 47 | 48 | ### 推送 49 | 推送是指平台中心希望发布给所有用户的文章。比如平台使用手册: 50 | 51 | ![推送界面](https://github.com/Roujack/LiBond/blob/master/pictures/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20170523161858.jpg) 52 | 53 | ### 聊天 54 | 聊天栏是用户对帖子感兴趣的时候,可以对发帖人进行询问。 55 | 56 | ![聊天界面](https://github.com/Roujack/LiBond/blob/master/pictures/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20170523161908.jpg) 57 | 58 | ### 通知 59 | 通知栏为系统给用户的信息,比如用户报名你的帖子啊,以及你的帖子被举报啊,还有其他信息等: 60 | ![系统通知](https://github.com/Roujack/LiBond/blob/master/pictures/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20170523161912.jpg) 61 | 62 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var express = require('express'); 4 | var path = require('path'); 5 | var logger = require('./library/winstonlogger.js'); 6 | var cookieParser = require('cookie-parser'); 7 | var bodyParser = require('body-parser'); 8 | var winston = require('winston'); 9 | var morgan = require('morgan'); 10 | var rfs = require('rotating-file-stream'); 11 | //require mongo 12 | var mongo = require('./db/mongo.js'); 13 | 14 | var routes = require('./routes/index.js'); 15 | var checkToken = require('./library/checkToken.js'); 16 | var redisClient = require('./db/redis').redisClient; 17 | var app = express(); 18 | 19 | //2017-3-1 20 | var multer = require('multer'); 21 | const message = require('./config/message.js'); 22 | const getOptions = require('./library/tools.js').getOptions; 23 | var _ = require('underscore'); 24 | var fs = require('fs'); 25 | const uploadMultiPics = require('./library/tools.js').uploadMultiPics; 26 | 27 | 28 | 29 | //cross domain 跨域 http://www.cnblogs.com/dojo-lzz/p/4265637.html 30 | app.use(function (req, res, next) { 31 | res.header("Access-Control-Allow-Origin", "*"); 32 | res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, xkey, xtoken"); 33 | next(); 34 | }); 35 | 36 | 37 | 38 | //limite some interfaces aceess time,每个用户明天最多修改十次密码,以ip地址作为判断标志 39 | /*var limiter = require('express-limiter')(app,redisClient); 40 | limiter({ 41 | path:'/user/getVerCode', 42 | method:'post', 43 | lookup:'connection.remoteAddress', 44 | total:10, 45 | expire:1000 * 60 * 60*24, 46 | onRateLimited:function(req,res,next){ 47 | res.json({statusCode: -100, message: 'access times limited!'}); 48 | } 49 | });*/ 50 | // view engine setup 51 | app.set('views', path.join(__dirname, 'views')); 52 | app.set('view engine', 'jade'); 53 | //设置当前环境为产品环境,与development环境的区别是production不会把错误堆栈信息显示给用户 54 | app.set('env','production'); 55 | 56 | // uncomment after placing your favicon in /public 57 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); 58 | //app.use(logger('dev')); 59 | app.use(bodyParser.json()); 60 | app.use(bodyParser.urlencoded({ extended: false })); 61 | app.use(cookieParser()); 62 | app.use(express.static(path.join(__dirname, 'public'))); 63 | 64 | app.all('*', function (req, res, next) { 65 | let originalUrl = req.originalUrl; 66 | 67 | logger.debug(req.url); 68 | logger.debug("req.body:" + JSON.stringify(req.body)); 69 | 70 | if(/\/user\/signup/.test(originalUrl) 71 | || /\/user\/login/.test(originalUrl) 72 | || /\/user\/updatePass/.test(originalUrl) 73 | || /\/user\/getVerCode/.test(originalUrl) 74 | || /\/user\/rank/.test(originalUrl) 75 | || /\/user\/insertStu/.test(originalUrl) 76 | || /\/user\/verifyStuNum/.test(originalUrl) 77 | || /\/post\/getAll/.test(originalUrl)) { 78 | return next(); 79 | } 80 | //logger.debug('req.headers: xkey: ' + req.headers.xkey + '\txtoken: ' + req.headers.xtoken); 81 | next(); 82 | }); 83 | 84 | 85 | 86 | 87 | 88 | //app.use(morgan('tiny')); 89 | //app.use(morgan(':method :url :response-time')); 90 | var logDirectory = path.join(__dirname, 'logs/access'); 91 | 92 | // ensure log directory exists 93 | fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory) 94 | 95 | // create a rotating write stream 96 | var accessLogStream = rfs('access.log', { 97 | interval: '1d', // rotate daily 98 | path: logDirectory 99 | }) 100 | 101 | // setup the logger 102 | app.use(morgan(':method :url :req[body] :response-time', {stream: accessLogStream})); 103 | 104 | //登录中间件 105 | //为了避免穷举攻击有必要对用户写错密码的次数进行限制: 106 | //每十二个小时内最多填错10次密码 107 | app.use('/user/login',(req,res,next) => { 108 | //为了避免键值重复(用户可能会找回密码) 109 | //我在手机号前加个'0' 110 | redisClient.get('0'+req.body.phone,function(err,response){ 111 | if(response != null && parseInt(response.toString()) >= 10){ 112 | res.json(message.LOGIN_LIMIT); 113 | } 114 | else 115 | next(); 116 | }) 117 | }) 118 | //获取验证码中间件 119 | //为了避免短信的随意发送,对发送短信的次数进行限制; 120 | //每天只能对同一个手机号发送最多十条短信 121 | app.use('/user/getVerCode',(req,res,next)=>{ 122 | //为了避免键值重复(用户可能会找回密码) 123 | //我在手机号前加个'1' 124 | redisClient.get('1'+req.body.phone,function(err,response){ 125 | if(response != null && parseInt(response.toString())>=10){ 126 | res.json(message.GETVERCODE_LIMIT); 127 | } 128 | else 129 | next(); 130 | }) 131 | }) 132 | //single表示只上传一张头像 133 | var upload = multer(getOptions('avatar')).single('avatar'); 134 | //头像中间件 135 | app.use('/user/avatar',(req,res,next) => { 136 | //console.log('/user/avatar'); 137 | upload(req,res,function(err){ 138 | if(err || _.isEmpty(req.file)) 139 | return res.json(message.UPLOAD_FILE_ERROR); 140 | if(req.body.userId != req.headers.xkey){ 141 | fs.unlink(req.file.path,function(err){ 142 | if(err) 143 | logger.error('avatar接口出错:' + err); 144 | }) 145 | return res.json(message.PARAMS_ERROR); 146 | } 147 | next(); 148 | }) 149 | }) 150 | //发布帖子中间件 151 | app.use('/post/publish',(req,res,next) => { 152 | //console.log('/post/publish'); 153 | uploadMultiPics(req,res,function(err,body){ 154 | req.body=body; 155 | if(err ) { 156 | console.log(err); 157 | return res.json(message.UPLOAD_FILE_ERROR); 158 | } 159 | 160 | if(req.body.userId != req.headers.xkey){ 161 | //删除图片 162 | req.files.forEach(function(photo,index){ 163 | fs.unlink(photo.path,function(err){ 164 | if(err) 165 | logger.error('上传多张图片接口出错:' + err); 166 | }) 167 | }) 168 | return res.json(message.PARAMS_ERROR); 169 | } 170 | next(); 171 | }) 172 | }) 173 | 174 | app.use('*', (req, res, next) => { 175 | 176 | let originalUrl = req.originalUrl; 177 | if(/\/user\/signup/.test(originalUrl) 178 | || /\/user\/login/.test(originalUrl) 179 | || /\/user\/updatePass/.test(originalUrl) 180 | || /\/user\/getVerCode/.test(originalUrl) 181 | || /\/user\/rank/.test(originalUrl) 182 | || /\/user\/insertStu/.test(originalUrl) 183 | || /\/getURL/.test(originalUrl) 184 | || /\/getItems/.test(originalUrl) 185 | || /\/insertRegister/.test(originalUrl) 186 | || /\/exportToExcel/.test(originalUrl) 187 | || /\/user\/verifyStuNum/.test(originalUrl) 188 | || /\/post\/assign/.test(originalUrl) 189 | || /\/register\/getAll/.test(originalUrl) 190 | || /\/post\/getAll/.test(originalUrl)) { 191 | return next(); 192 | } 193 | //避免冒充 194 | if( !(/\/user\/getInfo/.test(originalUrl) 195 | || /\/post\/getPost/.test(originalUrl) 196 | || /\/search/.test(originalUrl) )) 197 | { 198 | 199 | req.headers.xkey = req.body.userId; 200 | 201 | if( /\/post\/register/.test(originalUrl)) 202 | req.headers.xkey = req.body.registerId; 203 | 204 | if( /\/post\/comment/.test(originalUrl)) 205 | req.headers.xkey = req.body.fromId; 206 | } 207 | checkToken.validateToken(req, res, next); 208 | }) 209 | 210 | app.use('/', routes); 211 | 212 | 213 | // catch 404 and forward to error handler 214 | app.use(function(req, res, next) { 215 | var err = new Error('Not Found'); 216 | err.status = 404; 217 | next(err); 218 | }); 219 | 220 | // error handlers 221 | 222 | //Connect to MongoDB 223 | mongo.connect(); 224 | 225 | function getDateString(date) { 226 | if (typeof date === 'number') { 227 | date = new Date(date); 228 | } 229 | return String(date.getFullYear()) + (date.getMonth() + 1) + date.getDate(); 230 | } 231 | 232 | //将日志按日期划分开来,方便删除,分析等 233 | setInterval(function(){ 234 | var now = new Date(); 235 | //console.log('yep'); 236 | if(now.getHours() == 10) 237 | { 238 | var filename = '../logs/debug/debug-logs'+getDateString(now)+'.log'; 239 | //console.log(filename); 240 | logger.remove('debug-file'); 241 | logger.add(winston.transports.File,{ 242 | level: 'debug', 243 | name: 'debug-file', 244 | filename: filename, 245 | timestamp:true, 246 | json: false, 247 | colorize: true 248 | }); 249 | } 250 | },60*60*1000); 251 | 252 | // development error handler 253 | // will print stacktrace 254 | if (app.get('env') === 'development') { 255 | app.use(function(err, req, res, next) { 256 | res.status(err.status || 500); 257 | res.render('error', { 258 | message: err.message, 259 | error: err 260 | }); 261 | }); 262 | } 263 | 264 | // production error handler 265 | // no stacktraces leaked to user 266 | app.use(function(err, req, res, next) { 267 | //console.log('why'); 268 | res.status(err.status || 500); 269 | res.render('error', { 270 | message: err.message, 271 | error: {status:err.status} 272 | }); 273 | }); 274 | 275 | 276 | module.exports = app; 277 | -------------------------------------------------------------------------------- /bin/timebank: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('tbApi:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /controller/post.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const uploadMultiPics = require('../library/tools.js').uploadMultiPics; 3 | const sendVerifyCode = require('../library/tools.js').sendVerifyCode; 4 | const sendMsg= require('../library/tools.js').sendMsg; 5 | const checkParams= require('../library/tools.js').checkParams; 6 | const pGetUserByPhone = require('../library/tools.js').pGetUserByPhone; 7 | const pGetUserById = require('../library/tools.js').pGetUserById; 8 | const pGetPostById = require('../library/tools.js').pGetPostById; 9 | 10 | const logger = require('../library/winstonlogger.js'); 11 | const message = require('../config/message.js'); 12 | const UserDao = require('../dao/index').UserDao; 13 | const PostDao = require('../dao/index').PostDao; 14 | const TipDao = require('../dao/index').TipDao; 15 | const _ = require('underscore'); 16 | const config = require('../config/config.js'); 17 | var fs = require('fs'); 18 | //发布帖子 19 | //减去用户金币 20 | var publish = function(req, res){ 21 | let postInfo = req.body; 22 | console.log(postInfo); 23 | checkParams([postInfo.userId,postInfo.postType,postInfo.topicType, 24 | postInfo.content,postInfo.missionCoin,postInfo.expTime]) 25 | .then(function() { 26 | return new Promise(function (resolve,reject) { 27 | if(Number(postInfo.missionCoin)<=0 || !Number.isInteger(Number(postInfo.missionCoin))){ 28 | reject({statusCode:-100,message:'时间币参数不正确'}); 29 | } 30 | else{ 31 | UserDao.getUserById(postInfo.userId,function (err,user) { 32 | //console.log(user.coin); 33 | // console.log("missionCoin="+Number(postInfo.missionCoin)); 34 | if(err){ 35 | reject(message.USERID_ERROR); 36 | }else if(!user){ 37 | reject(message.USER_NOT_EXIST); 38 | } else if(Number(user.coin){ 175 | if(post.status == 0 || post.status == 1|| post.status == 6){ 176 | let d = (new Date(post.expTime)).getTime(); 177 | d = d - Date.now(); 178 | if(d<0){ 179 | post.status = 4; 180 | post.cancelReason = '帖子自动过期'; 181 | post.save(); 182 | } 183 | 184 | } 185 | });*/ 186 | PostDao.getPostsLengthByQuery(query,null,option,function (err,length) { 187 | if(err){ 188 | res.json(message.MONGODB_ERROR); 189 | } 190 | else { 191 | let posts_list = []; 192 | // console.log(length); 193 | let cnt = 0; 194 | //对输出的post进行处理,使得post里面与user有关的数据同步 195 | posts.forEach(function(item){ 196 | if(item.participant.length==0){ 197 | //console.log(item); 198 | item.publisherName = item.publisherInfo.stuName; 199 | item.publisherAvatar = item.publisherInfo.avatar; 200 | item.publisherScore = item.publisherInfo.finalScore.toFixed(1); 201 | item.save(); 202 | posts_list.push(item); 203 | ++cnt; 204 | } 205 | else 206 | --length; 207 | }); 208 | //console.log(length); 209 | // console.log(posts[0].publisherInfo.stuName); 210 | res.json({statusCode: 100, message: 'ok', result:posts_list ,result_count:cnt}); 211 | } 212 | }); 213 | } 214 | }) 215 | }) 216 | .catch(function (err) { 217 | 218 | res.json(err); 219 | logger.info(err); 220 | 221 | 222 | }) 223 | }; 224 | 225 | //收藏帖子与取消收藏帖子,通过flag确定 226 | //已优化 227 | var favoOperation = function(req,res,flag){ 228 | let userId = req.body.userId; 229 | let postId = req.body.postId; 230 | checkParams([userId,postId]).then(function() { 231 | return pGetUserById(userId); 232 | }).then(function(user) { 233 | return new Promise((resolve, reject)=>{ 234 | PostDao.getPostById(postId,function (err,post) { 235 | if(err){ 236 | reject(message.POSTID_ERROR); 237 | }else if(!post){ 238 | reject(message.POST_NOT_EXIST); 239 | } 240 | else if(post){ 241 | resolve({post,user}); 242 | } 243 | }) 244 | }) 245 | }) 246 | .then(function (postAnduser) { 247 | return new Promise((resolve,reject)=>{ 248 | if(flag){ 249 | let isFavo = false; 250 | for(let i = 0;i{ 436 | PostDao.getPostById(postId,function (err,post) { 437 | if (err) { 438 | reject(message.POSTID_ERROR); 439 | }else if(!post){ 440 | reject(message.POST_NOT_EXIST); 441 | }/*else if(post.status==3){ 442 | reject(message.POST_FINISHED); 443 | }else if(post.status==4){ 444 | reject(message.POST_CANCELED); 445 | }*/ 446 | else if(post.status == 0 || post.status == 1 || 447 | post.status == 2 || post.status == 6){ 448 | resolve({post,user}); 449 | } 450 | else 451 | reject(message.STATUS_ERROR); 452 | }); 453 | }) 454 | }) 455 | .then(function(PostUser) { 456 | return new Promise((resolve, reject)=>{ 457 | //发帖人和人任务人都可以取消 458 | if(PostUser.post.status==0 || PostUser.post.status == 1 || PostUser.post.status == 6){ 459 | PostUser.post.status=4; 460 | PostUser.post.cancelReason=reason; 461 | PostUser.user.coin=PostUser.user.coin+Number(PostUser.post.missionCoin); 462 | /*PostUser.post.save(function (err) { 463 | PostUser.user.save(function(err1){ 464 | if(err||err1) reject(message.MONGODB_ERROR); 465 | else res.json(message.OPERATION_SUCCESS); 466 | }) 467 | });*/ 468 | resolve(PostUser); 469 | } 470 | //任务人取消 471 | else if((PostUser.post.status==2) && (userId==PostUser.post.participant[0].userId)){ 472 | //对帖子的处理 473 | PostUser.post.status = 4; 474 | PostUser.post.participant[0].status = 5; 475 | PostUser.post.cancelReason = reason; 476 | PostUser.post.coinBank.status = 2; 477 | //当发帖人取消任务时 478 | /*if(userId==PostUser.post.publisher){ 479 | PostUser.user.message.addToSet({ 480 | date : new Date(), 481 | messageType:17, 482 | content :{ 483 | postId :PostUser.post._id, //帖子id 484 | postTitle :PostUser.post.title //帖子标题 485 | } 486 | }) 487 | PostUser.user.coin=PostUser.user.coin+Number(PostUser.post.missionCoin); 488 | resolve(PostUser); 489 | }*/ 490 | //当任务人取消任务 491 | 492 | PostUser.user.message.addToSet({ 493 | date : new Date(), 494 | messageType:17, 495 | content :{ 496 | postId :PostUser.post._id, //帖子id 497 | postTitle :PostUser.post.title //帖子标题 498 | } 499 | }) 500 | PostUser.user.joinCount--; 501 | //查找帖子发布者 502 | UserDao.getUserById(PostUser.post.publisher,function(err,publisher){ 503 | if(err){ 504 | reject(message.USERID_ERROR); 505 | }else if(!publisher){ 506 | reject(message.USER_NOT_EXIST); 507 | }else{ 508 | publisher.message.addToSet({ 509 | date : new Date(), 510 | messageType:17, 511 | content :{ 512 | postId :PostUser.post._id, //帖子id 513 | postTitle :PostUser.post.title //帖子标题 514 | } 515 | }) 516 | publisher.coin+=Number(PostUser.post.missionCoin); 517 | //为了resolve的数据统一先保存publisher 518 | publisher.save(function(err){ 519 | if(err){ 520 | reject(message.MONGODB_ERROR); 521 | } 522 | else resolve(PostUser); 523 | }) 524 | } 525 | }) 526 | 527 | } 528 | else 529 | reject(message.CANCEL_LIMIT); 530 | }) 531 | }).then(function(PostUser) { 532 | return new Promise((resolve, reject)=>{ 533 | //对数据的保存 534 | PostUser.post.save(function(posterr){ 535 | PostUser.user.save(function(usererr){ 536 | if(posterr||usererr) 537 | reject(message.MONGODB_ERROR); 538 | else{ 539 | res.json(message.OPERATION_SUCCESS); 540 | } 541 | }) 542 | }) 543 | }) 544 | }).catch(function (err) { 545 | res.json(err); 546 | logger.info(err); 547 | }); 548 | }; 549 | 550 | 551 | 552 | //确定任务wancheng接口 553 | var confirm = function(req, res){ 554 | let userId = req.body.userId; 555 | let postId = req.body.postId; 556 | checkParams([userId,postId]).then(function() { 557 | return pGetPostById(postId); 558 | }).then(function(post) { 559 | return new Promise((resolve, reject)=>{ 560 | if(post.status !=2) 561 | reject(message.STATUS_ERROR); 562 | if(post.publisher != userId) 563 | reject(message.CANT_CONFIRM); 564 | resolve(post); 565 | }) 566 | }).then(function(post) { 567 | return new Promise((resolve, reject)=>{ 568 | UserDao.getUserById(post.coinBank.toId,function (err,toUser) { 569 | if(err){ 570 | reject(message.USERID_ERROR); 571 | } else if(!toUser){ 572 | reject(message.USER_NOT_EXIST); 573 | }else{ 574 | resolve({post,toUser}); 575 | } 576 | }) 577 | }) 578 | }).then(function(PostTouser) { 579 | return new Promise((resolve, reject)=>{ 580 | //post.status 一定等于 2 581 | if(PostTouser.post.coinBank.status==1){ 582 | reject(message.CONFIRMED_ALREADY); 583 | }else{ 584 | //转账 585 | PostTouser.toUser.coin=PostTouser.toUser.coin+PostTouser.post.coinBank.coin; 586 | //MongoDB弊端之一,不能保证两个集合的事务性 587 | PostTouser.toUser.message.addToSet({ 588 | date : new Date(), //信息时间 589 | messageType: 4 , 590 | content :{ 591 | userId :userId , //信息触发者id 592 | postId :PostTouser.post._id, //帖子id 593 | userStuName :PostTouser.post.publisherInfo.stuName , //信息触发者姓名 594 | postTitle :PostTouser.post.title //帖子标题 595 | } 596 | }); 597 | PostTouser.toUser.save(function(err){ 598 | if(err){ 599 | reject(message.MONGODB_ERROR); 600 | }else{ 601 | resolve(PostTouser.post); 602 | } 603 | }) 604 | } 605 | }) 606 | }).then(function(post) { 607 | return new Promise((resolve, reject)=>{ 608 | post.participant[0].status= 4; 609 | post.coinBank.status=1; 610 | post.status=5; 611 | post.save(function (err) { 612 | if(err){ 613 | reject(message.MONGODB_ERROR); 614 | }else{ 615 | res.json(message.OPERATION_SUCCESS); 616 | } 617 | }); 618 | }) 619 | }).catch(function (err) { 620 | res.json(err); 621 | logger.info(err); 622 | }); 623 | }; 624 | //举报接口 625 | var tipoff = function (req, res) { 626 | let tipInfo= {}; 627 | tipInfo.postId = req.body.postId; 628 | tipInfo.fromId = req.body.userId; 629 | checkParams([tipInfo.postId,tipInfo.fromId]).then(function() { 630 | return new Promise((resolve, reject)=>{ 631 | TipDao.getTipByUserIdAndPostId(tipInfo.fromId,tipInfo.postId,function (err,tip) { 632 | if (!tip) { 633 | resolve(tipInfo); 634 | }else if (err) { 635 | reject(message.MONGODB_ERROR); 636 | }else if(tip){ 637 | reject(message.TIP_ALREADY); 638 | } 639 | }); 640 | }) 641 | }).then(function(tipInfo) { 642 | return new Promise((resolve, reject)=>{ 643 | PostDao.getPostById(tipInfo.postId,function (err,post) { 644 | if (!post) { 645 | reject(message.POST_NOT_EXIST); 646 | } else if (err) { 647 | reject(message.POSTID_ERROR); 648 | } else{ 649 | UserDao.getUserById(tipInfo.fromId,function (err,user) { 650 | if(err){ 651 | reject(message.USERID_ERROR); 652 | }else if(!user){ 653 | reject(message.USER_NOT_EXIST); 654 | }else{ 655 | tipInfo.fromName=user.stuName; 656 | tipInfo.toName= post.publisherName; 657 | tipInfo.toId=post.publisher; 658 | resolve([post,user]); 659 | } 660 | }); 661 | } 662 | }); 663 | }) 664 | }).then(function(body) { 665 | return new Promise((resolve, reject)=>{ 666 | UserDao.getUserById(body[0].publisher,function (err,user) { 667 | if (!user) { 668 | reject(message.USER_NOT_EXIST); 669 | } else if (err) { 670 | reject(message.USERID_ERROR); 671 | }else if (body[0].publisher==tipInfo.fromId) { 672 | reject(message.TIP_ERROR); 673 | }else{ 674 | user.message.addToSet({ 675 | date : new Date(), //信息时间 676 | messageType: 6 , 677 | content :{ 678 | userId :tipInfo.fromId , //信息触发者id 679 | postId :tipInfo.postId, //帖子id 680 | userStuName :body[0].stuName , //信息触发者姓名 681 | postTitle :body[0].title //帖子标题 682 | } 683 | }); 684 | user.save(function(err){ 685 | if(err){ 686 | reject(message.MONGODB_ERROR); 687 | }else{ 688 | tipInfo.stuName=user.stuName; 689 | tipInfo.tipReason=req.body.reason; 690 | resolve(); 691 | } 692 | }) 693 | } 694 | }); 695 | }) 696 | }).then(function() { 697 | return new Promise((resolve, reject)=> { 698 | TipDao.newTipAndSave(tipInfo, function (err) { 699 | if (err) { 700 | reject(message.MONGODB_ERROR); 701 | } else { 702 | resolve(); 703 | } 704 | }) 705 | }); 706 | }).then(function () { 707 | res.json({statusCode: 100, message: 'ok', result:''}); 708 | }).catch(function (err) { 709 | 710 | res.json(err); 711 | logger.info(err); 712 | }); 713 | }; 714 | //评论接口 715 | var comment = function (req, res) { 716 | let body = req.body; 717 | checkParams([body.fromId,body.content,body.postId]) 718 | .then(() => { 719 | return pGetUserById(body.fromId); 720 | }) 721 | .then(function(user) { 722 | return new Promise((resolve, reject)=>{ 723 | body.user=user; 724 | if(_.isEmpty(body.atId)){ 725 | resolve(body) 726 | }else{ 727 | UserDao.getUserById(body.atId,function(err,user){ 728 | if (err) 729 | reject(message.MONGODB_ERROR); 730 | 731 | PostDao.getPostById(body.postId,function (err,post) { 732 | if(err) { 733 | reject(message.POSTID_ERROR); 734 | }else if(!post){ 735 | reject(message.POST_NOT_EXIST); 736 | }else if (!user) { 737 | reject(message.USER_NOT_EXIST); 738 | }else{ 739 | user.message.addToSet({ 740 | date : new Date(), //信息时间 741 | messageType: 15 , 742 | content :{ 743 | userId :body.fromId , //信息触发者id 744 | postId :body.postId, //帖子id 745 | userStuName :body.user.stuName , //信息触发者姓名 746 | postTitle :post.title //帖子标题 747 | } 748 | }); 749 | user.save(function(err){ 750 | if(err){ 751 | reject(message.MONGODB_ERROR); 752 | }else{ 753 | resolve(body); 754 | } 755 | }) 756 | } 757 | }) 758 | 759 | }) 760 | } 761 | }) 762 | }).then(function(body) { 763 | return new Promise((resolve, reject)=>{ 764 | 765 | UserDao.getUserById(post.publisher,function(err,user){ 766 | if (!post) { 767 | reject(message.POST_NOT_EXIST); 768 | } else if (err) { 769 | reject(message.USERID_ERROR); 770 | } else if (!user) { 771 | reject(message.USER_NOT_EXIST); 772 | }else { 773 | if(!(_.isEmpty(body.atId))){ 774 | resolve([post,user]); 775 | }else{ 776 | user.message.addToSet({ 777 | date : new Date(), //信息时间 778 | messageType: 0 , 779 | content :{ 780 | userId :body.fromId , //信息触发者id 781 | postId :body.postId, //帖子id 782 | userStuName :body.user.stuName , //信息触发者姓名 783 | postTitle :post.title //帖子标题 784 | } 785 | }); 786 | user.save(function(err){ 787 | if(err){ 788 | reject(message.MONGODB_ERROR); 789 | }else{ 790 | resolve([post,user]); 791 | } 792 | }) 793 | } 794 | } 795 | }); 796 | 797 | 798 | }) 799 | }) 800 | .then(function(info) { 801 | return new Promise((resolve, reject)=>{ 802 | UserDao.getUserById(body.fromId,function(err,user){ 803 | if (err) { 804 | reject(message.USERID_ERROR); 805 | } else if (!user) { 806 | reject(message.USER_NOT_EXIST); 807 | }else { 808 | resolve([info[0],user]); 809 | } 810 | }) 811 | }) 812 | }).then(function(info) { 813 | info[0].comment.addToSet({ 814 | fromAvatar :info[1].avatar, //评论者头像 815 | fromId:info[1]._id, 816 | atId: body.atId, 817 | atName :body.atName, 818 | fromName :info[1].stuName, 819 | content: body.content, 820 | time: new Date() 821 | }); 822 | info[0].commentNum++; 823 | info[0].save(function (err) { 824 | if(err){ 825 | res.json(message.MONGODB_ERROR); 826 | } 827 | else{ 828 | res.json({statusCode: 100, message: 'ok', result: ''}); 829 | } 830 | }) 831 | }).catch(function (err) { 832 | 833 | res.json(err); 834 | logger.info(err); 835 | }) 836 | }; 837 | 838 | var getReason = function(req,res){ 839 | let userId = req.body.userId; 840 | let postId = req.body.postId; 841 | checkParams([userId,postId]).then(()=>{ 842 | return pGetPostById(postId); 843 | }).then((post)=>{ 844 | return new Promise((resolve,reject)=>{ 845 | console.log(post.publisher); 846 | if(post.publisher != userId) 847 | reject(message.PARAMS_ERROR); 848 | else{ 849 | console.log('yes'); 850 | resolve({statusCode:100,message:post.cancelReason,result:post.cancelReason}); 851 | } 852 | }) 853 | }) 854 | .then((result)=>{ 855 | res.json(result); 856 | }) 857 | .catch((errMsg)=>{ 858 | res.json(errMsg); 859 | logger.info(errMsg); 860 | }) 861 | } 862 | var assign = function(req,res){ 863 | res.json(message.OPERATION_SUCCESS); 864 | } 865 | exports.favorCancel = favorCancel; 866 | exports.publish = publish; 867 | exports.comment = comment; 868 | exports.tipoff = tipoff; 869 | exports.confirm = confirm; 870 | exports.cancel = cancel; 871 | exports.assign = assign; 872 | exports.register =register; 873 | exports.favo = favo; 874 | exports.getAll = getAll; 875 | exports.getPost = getPost; 876 | exports.getReason = getReason; 877 | 878 | 879 | 880 | 881 | -------------------------------------------------------------------------------- /controller/user.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const crypto = require('crypto'); 4 | const genToken = require('../library/genToken.js').generToken; 5 | var _ = require('underscore'); 6 | const delToken = require('../library/delToken.js').delToken; 7 | const logger = require('../library/winstonlogger.js'); 8 | const message = require('../config/message.js'); 9 | const config = require('../config/config.js'); 10 | 11 | 12 | const UserDao = require('../dao/index').UserDao; 13 | const StuInfoDao = require('../dao/index').StuInfoDao; 14 | const PostDao = require('../dao/index').PostDao; 15 | const ItemDao = require('../dao/index').ItemDao; 16 | const TradeDao = require('../dao/index').TradeDao; 17 | 18 | 19 | const getOptions = require('../library/tools.js').getOptions; 20 | const getFinalScore = require('../library/tools.js').getFinalScore; 21 | const uploadMultiPics = require('../library/tools.js').uploadMultiPics; 22 | const sendVerifyCode = require('../library/tools.js').sendVerifyCode; 23 | const getRandomInt = require('../library/tools.js').getRandomInt; 24 | const pGetUserByPhone = require('../library/tools.js').pGetUserByPhone; 25 | const pGetUserById = require('../library/tools.js').pGetUserById; 26 | const pGetPostById = require('../library/tools.js').pGetPostById; 27 | 28 | 29 | 30 | const path = require('path'); 31 | var User = require('../model/user').user; 32 | var redisClient = require('../db/redis').redisClient; 33 | //上传文件模块 34 | var multer = require('multer'); 35 | var fs = require('fs'); 36 | //图片裁剪模块 37 | var gm = require('gm'); 38 | var mongoose = require('mongoose'); 39 | var User = require('../model/user').user; 40 | 41 | //兑换接口 42 | var buy = function(req,res){ 43 | let body = req.body; 44 | let numberOfItem = body.numberOfItem; 45 | if(!body.userId || !body.itemId || !body.numberOfItem || body.numberOfItem<1) 46 | return res.json(message.UNCOMPLETE_INPUT); 47 | let p1 = new Promise((onFulfill,onReject)=>{ 48 | UserDao.getUserById(body.userId, (err, user)=>{ 49 | if(err) 50 | onReject(message.MONGODB_ERROR); 51 | else if(!user) 52 | onReject(message.USER_NOT_EXIST); 53 | else 54 | onFulfill(user); 55 | }) 56 | }); 57 | 58 | let p2 = new Promise((onFulfill,onReject)=>{ 59 | ItemDao.getItemById(body.itemId, (err, item)=>{ 60 | if(err) 61 | onReject(message.MONGODB_ERROR); 62 | else if(!item) 63 | onReject(message.ITEM_NOT_EXIST); 64 | else 65 | onFulfill(item); 66 | }) 67 | }); 68 | 69 | Promise.all([p1,p2]).then(function(result){ 70 | return new Promise(function(onFulfill,onReject){ 71 | let user = result[0]; 72 | let item = result[1]; 73 | console.log(user.coin); 74 | if(numberOfItem > item.stock){ 75 | 76 | onReject(message.STOCK_OVERFLOW); 77 | } 78 | else if(user.coin < (item.price*numberOfItem)){ 79 | 80 | onReject(message.UN_ENOUGH_COINS); 81 | } 82 | else 83 | onFulfill(result); 84 | }) 85 | }) 86 | .then(function(result){ 87 | return new Promise(function(onFulfill,onReject){ 88 | let user = result[0]; 89 | let item = result[1]; 90 | user.coin = user.coin - (item.price*numberOfItem); 91 | item.stock = item.stock - numberOfItem; 92 | item.save((err)=>{ 93 | if(err) 94 | onReject(message.MONGODB_ERROR); 95 | else{ 96 | user.save((err)=>{ 97 | if(err) 98 | onReject(message.MONGODB_ERROR); 99 | else{ 100 | console.log(user.coin); 101 | onFulfill(result); 102 | } 103 | 104 | }) 105 | } 106 | }) 107 | }) 108 | }) 109 | .then(function(result){ 110 | 111 | let user = result[0]; 112 | let item = result[1]; 113 | let trade = {}; 114 | trade.userId = user._id; 115 | trade.userName = user.stuName; 116 | trade.itemId = item._id; 117 | trade.itemName = item.name; 118 | trade.numberOfItem = body.numberOfItem; 119 | sendVerifyCode(false,user.phone,function(err,result){ 120 | if(err) 121 | res.json(err); 122 | else{ 123 | trade.exchangeCode = result.result; 124 | TradeDao.newTradeAndSave(trade,function(err,trade){ 125 | if(err){ 126 | console.log(err); 127 | res.json(message.MONGODB_ERROR); 128 | } 129 | else{ 130 | console.log("yes"); 131 | res.json(message.OPERATION_SUCCESS); 132 | } 133 | }) 134 | } 135 | }); 136 | }) 137 | .catch((err)=>{ 138 | console.log(err); 139 | res.json(err); 140 | logger.debug(err); 141 | }) 142 | 143 | } 144 | 145 | 146 | //插入学号接口 147 | var insertStu = function(req,res){ 148 | //首先检查姓名和学号是否为空 149 | if(!req.body.stuName || !req.body.stuNum) 150 | return res.json(message.UNCOMPLETE_INPUT); 151 | 152 | new Promise((onFulfill,onReject)=>{ 153 | StuInfoDao.getUserByStuNum(req.body.stuNum,(err,stu) => { 154 | if(err) onReject(message.MONGODB_ERROR); 155 | else if(stu) onReject(message.STUNUM_SIGNUP_ALREADY); 156 | else onFulfill(); 157 | }) 158 | }) 159 | .then(() => { 160 | return new Promise((onFulfill,onReject)=>{ 161 | StuInfoDao.newStuAndSave(req.body.stuName,req.body.stuNum, (err, stu) => { 162 | if(err){ 163 | onReject(message.MONGODB_ERROR); 164 | }else{ 165 | onFulfill(message.OPERATION_SUCCESS); 166 | } 167 | }) 168 | }) 169 | }) 170 | .then((resultMsg) => { 171 | res.json(resultMsg); 172 | }) 173 | .catch((errMsg) =>{ 174 | res.json(errMsg); 175 | }) 176 | 177 | 178 | 179 | } 180 | //验证学号接口 181 | var verifyStuNum = function(req,res){ 182 | let stuName = req.body.stuName; 183 | let stuNum = req.body.stuNum; 184 | if(!stuName || !stuNum){ 185 | return res.json(message.UNCOMPLETE_INPUT); 186 | } 187 | new Promise((onFulfill,onReject)=>{ 188 | //通过学号在学生信息集合里面查找学生 189 | StuInfoDao.getUserByStuNum(stuNum, (err, stu) => { 190 | if(err){ 191 | onReject(message.MONGODB_ERROR); 192 | }else if(stu){ 193 | if(stu.isSignup == 1){ 194 | onReject(message.STUNUM_SIGNUP_ALREADY); 195 | } 196 | else if(stu.stuName == stuName){ 197 | onFulfill(); 198 | }else{ 199 | onReject(message.STUNUM_NAME_UNMATCH); 200 | } 201 | 202 | }else{ 203 | onReject(message.STUNUM_UNEXIST); 204 | } 205 | }) 206 | }) 207 | .then(()=>{ 208 | return new Promise((onFulfill,onReject)=>{ 209 | let isvalid = getRandomInt(6); 210 | //6位随机数用于判断在注册之前是否进过学号验证,设置在一天后过期 211 | redisClient.setex(stuNum,24*60*60,isvalid,function(err,response){ 212 | if(err) 213 | onReject(message.REDIS_ERROR); 214 | else 215 | onFulfill({statusCode:100,message:"验证通过",result:isvalid}); 216 | }) 217 | }) 218 | }) 219 | .then((resultMsg)=>{ 220 | res.json(resultMsg); 221 | }) 222 | .catch((errMsg)=>{ 223 | logger.info(errMsg); 224 | res.json(errMsg); 225 | }) 226 | 227 | } 228 | 229 | 230 | //注册接口 231 | var signup = function(req, res) { 232 | 233 | let stuName = req.body.stuName; 234 | 235 | 236 | let stuNum = req.body.stuNum; 237 | let isValid = req.body.isValid; 238 | 239 | 240 | let phone = req.body.phone; 241 | let password = req.body.password; 242 | let userVerifyCode = req.body.verifyCode; 243 | //存放在服务器的验证码 244 | let verifyCode; 245 | let sex = req.body.sex || 0; 246 | let resultMsg; 247 | let errMsg; 248 | 249 | if(!stuName || !stuNum || !phone || !password || !isValid || (sex != 0 && sex != 1)){ 250 | res.json(message.UNCOMPLETE_INPUT); 251 | } 252 | else { 253 | new Promise((onFulfill,onReject) => { 254 | //一个用户最多只有一个账号 255 | StuInfoDao.getUserByStuNum(stuNum, (err, stu) => { 256 | if(err) 257 | { 258 | onReject(message.MONGODB_ERROR); 259 | } 260 | else if(stu && stu.isSignup == 1) 261 | { 262 | onReject(message.STUNUM_SIGNUP_ALREADY); 263 | } 264 | else 265 | onFulfill(); 266 | }) 267 | }) 268 | .then( () => { 269 | return new Promise((onFulfill,onReject)=>{ 270 | 271 | //此处判断验证码是否正确 272 | redisClient.get(phone,function(err,res){ 273 | 274 | if(err) 275 | onReject(err); 276 | else if(res != null){ 277 | verifyCode = res.toString(); 278 | if(verifyCode != null && userVerifyCode != verifyCode) 279 | onReject(message.VERIFYCODE_ERROR); 280 | else 281 | onFulfill(); 282 | } 283 | else 284 | onReject(message.VERIFYCODE_ERROR); 285 | }) 286 | 287 | //onFulfill(); 288 | 289 | }) 290 | 291 | }).then(()=>{ 292 | return new Promise((onFulfill, onReject) => { 293 | //此处检查6位随机数判断该用户是否经过学号验证 294 | redisClient.get(stuNum,function(err,res){ 295 | 296 | if(err) 297 | onReject(err); 298 | else if(res != null){ 299 | let checkKey = res.toString(); 300 | if(isValid != null && isValid != checkKey) 301 | onReject(message.AUTHENTICATION_FAILED); 302 | else 303 | onFulfill(); 304 | } 305 | else 306 | onReject(message.AUTHENTICATION_FAILED); 307 | }) 308 | }) 309 | }).then(()=>{ 310 | return new Promise((onFulfill, onReject) => { 311 | UserDao.getUserByPhone(phone, (err, user) => { 312 | if(err){ 313 | onReject(message.MONGODB_ERROR); 314 | }else if(user){ 315 | onReject(message.PHONE_ERROR); 316 | }else{ 317 | onFulfill(); 318 | } 319 | }) 320 | }) 321 | }).then(()=>{ 322 | return new Promise((onFulfill, onReject) => { 323 | //漏洞,如果password是一个数组,将返回空对象 324 | //需要将密码进行md5加密算法处理再存入数据库 325 | //MD5可以把密码变成另外一个字符串,而且很难根据这个字符串 326 | //找回密码 327 | let encodePass; 328 | let md5 = crypto.createHash('md5'); 329 | md5.update(password); 330 | encodePass = md5.digest('hex'); 331 | logger.debug(encodePass); 332 | UserDao.newUserAndSave(phone, stuName, stuNum, encodePass, sex, (err, user) => { 333 | if(err){ 334 | logger.debug(message.MONGODB_ERROR); 335 | onReject(message.MONGODB_ERROR) 336 | }else{ 337 | onFulfill(message.REGISTER_SUCCESS); 338 | } 339 | }) 340 | }) 341 | }).then((resultMsg) => { 342 | 343 | res.json(resultMsg); 344 | //logger.debug('用户注册成功', resultMsg); 345 | 346 | //一个用户最多只有一个账号 347 | StuInfoDao.getUserByStuNum(stuNum, (err, stu) => { 348 | if(stu) 349 | { 350 | stu.isSignup = 1; 351 | stu.save(); 352 | } 353 | else 354 | { 355 | console.log("error at signup:can not save stu info"); 356 | } 357 | }) 358 | }).catch((errMsg)=>{ 359 | res.json(errMsg); 360 | logger.info(errMsg); 361 | }) 362 | } 363 | 364 | } 365 | //发送验证码接口 366 | var getVerCode = function(req, res) { 367 | 368 | let phone = req.body.phone; 369 | let type = req.body.type; 370 | let stuNum = req.body.stuNum; 371 | 372 | //console.log(type); 373 | if(!phone || (type != 0 && type != 1) || (!stuNum && type== 0) ) { 374 | res.json(message.UNCOMPLETE_INPUT); 375 | return; 376 | } 377 | if(!(/^1[3|4|5|7|8]\d{9}$/.test(phone)) ){ 378 | return res.json({statusCode:-100,message:"手机号不正确"}); 379 | } 380 | 381 | //type=0表示用户注册时发送验证码 382 | if(type == 0){ 383 | new Promise((onFulfill,onReject) => { 384 | let isValid = req.body.isValid; 385 | if(!isValid) 386 | onReject(message.UNCOMPLETE_INPUT); 387 | //此处判断该用户是否合法 388 | redisClient.get(stuNum,function(err,response){ 389 | if(err) 390 | onReject(message.REDIS_ERROR); 391 | else if(response != null){ 392 | let checkKey = response.toString(); 393 | if(isValid != null && isValid != checkKey) 394 | onReject(message.AUTHENTICATION_FAILED); 395 | else 396 | onFulfill(); 397 | } 398 | else 399 | onReject(message.AUTHENTICATION_FAILED); 400 | }) 401 | }) 402 | .then(() => { 403 | return new Promise((onFulfill,onReject) =>{ 404 | //通过验证才发验证码 405 | UserDao.getUserByPhone(phone, (err, user)=>{ 406 | if(err) 407 | onReject(message.MONGODB_ERROR); 408 | else if(!user) 409 | onFulfill(); 410 | else 411 | onReject(message.PHONE_ERROR); 412 | }) 413 | onFulfill(); 414 | }) 415 | }) 416 | .then(() => { 417 | return new Promise((onFulfill,onReject) =>{ 418 | sendVerifyCode(true,phone,function(err,result){ 419 | if(err) 420 | onReject(err); 421 | else{ 422 | //发送成功将会有所记录 423 | //为了避免恶意用户随便调用发送短信接口 424 | //每24个小时内最多发送10次短信 425 | //为了避免键值重复(用户可能会找回密码) 426 | //我在手机号前加个'1' 427 | redisClient.get('1'+phone,function(err,response){ 428 | 429 | if(err) 430 | console.log(err); 431 | else if(response != null){ 432 | let errTimes = parseInt(response.toString())+1; 433 | 434 | redisClient.setex('1'+phone,24*60*60,errTimes,function(err,response){ 435 | if(err){ 436 | console.log(message.REDIS_ERROR); 437 | logger.err(err.message); 438 | // console.log(message.REDIS_ERROR); 439 | } 440 | }) 441 | } 442 | else 443 | redisClient.setex('1'+phone,24*60*60,1,function(err,response){ 444 | if(err){ 445 | console.log(message.REDIS_ERROR); 446 | logger.err(err.message); 447 | } 448 | 449 | }) 450 | }) 451 | onFulfill(result); 452 | } 453 | }) 454 | }) 455 | }) 456 | .then((resultMsg) =>{ 457 | res.json({statusCode:resultMsg.statusCode,message:resultMsg.message}); 458 | //res.json({statusCode:100,message:"获取成功"}); 459 | }) 460 | .catch((err) => { 461 | logger.info(err); 462 | res.json(err); 463 | }) 464 | } 465 | //type=1表示更改密码时发送验证码 466 | else if(type == 1){ 467 | new Promise((onFulfill,onReject) => { 468 | UserDao.getUserByPhone(phone, (err, user) => { 469 | if(err) onReject(message.MONGODB_ERROR); 470 | else if(user) onFulfill(); 471 | else onReject(message.USER_NOT_EXIST); 472 | }) 473 | }) 474 | .then(() => { 475 | return new Promise((onFulfill,onReject)=>{ 476 | sendVerifyCode(true,phone,function(err,result){ 477 | if(err) 478 | onReject(err); 479 | else{ 480 | //发送成功将会有所记录 481 | //为了避免恶意用户随便调用发送短信接口 482 | //每24个小时内最多发送10次短信 483 | //为了避免键值重复(用户可能会找回密码) 484 | //我在手机号前加个'1' 485 | redisClient.get('1'+phone,function(err,response){ 486 | 487 | if(err) 488 | console.log(err); 489 | else if(response != null){ 490 | let errTimes = parseInt(response.toString())+1; 491 | 492 | redisClient.setex('1'+phone,24*60*60,errTimes,function(err,response){ 493 | if(err){ 494 | console.log(message.REDIS_ERROR); 495 | logger.err(err.message); 496 | // console.log(message.REDIS_ERROR); 497 | } 498 | }) 499 | } 500 | else 501 | redisClient.setex('1'+phone,24*60*60,1,function(err,response){ 502 | if(err){ 503 | console.log(message.REDIS_ERROR); 504 | logger.err(err.message); 505 | } 506 | 507 | }) 508 | }) 509 | onFulfill(result); 510 | } 511 | 512 | }) 513 | }) 514 | 515 | }) 516 | .then((resultMsg) => { 517 | //res.json({statusCode:100,message:"获取成功"}); 518 | res.json({statusCode:resultMsg.statusCode,message:resultMsg.message}); 519 | }) 520 | .catch((err) => { 521 | logger.info(err); 522 | res.json(err); 523 | }) 524 | } 525 | 526 | } 527 | //登录接口 528 | var login = function(req, res) { 529 | let phone = req.body.phone; 530 | let password = req.body.password; 531 | let errMsg; 532 | let resultMsg; 533 | if(!phone || !password){ 534 | res.json(message.LOGIN_INFO_ERROR); 535 | return; 536 | } 537 | new Promise((onFulfill, onReject) => { 538 | UserDao.getUserByPhone(phone, (err, user) => { 539 | err && onReject(message.MONGODB_ERROR); 540 | !user && onReject(message.USER_NOT_EXIST); 541 | user && onFulfill(user); 542 | }) 543 | }) 544 | .then((user)=> { 545 | 546 | return new Promise((onFulfill, onReject) => { 547 | 548 | let encodePass; 549 | let md5 = crypto.createHash('md5'); 550 | md5.update(password); 551 | encodePass = md5.digest('hex'); 552 | //先将请求的密码md5,再跟数据库的密码匹配 553 | if(user.password === encodePass){ 554 | user.lastLoginTime = new Date(); 555 | user.save(); 556 | //如果输入密码正确,将当天错误的次数清0 557 | redisClient.expire('0'+phone,'3'); 558 | onFulfill(user._id) 559 | }else{ 560 | //为了避免穷举攻击有必要对用户写错密码的次数进行限制: 561 | //每十二个小时内最多填错10次密码 562 | //为了避免键值重复(用户可能会找回密码) 563 | //我在手机号前加个'0' 564 | redisClient.get('0'+phone,function(err,response){ 565 | 566 | if(err) 567 | console.log(err); 568 | else if(response != null){ 569 | let errTimes = parseInt(response.toString())+1; 570 | 571 | redisClient.setex('0'+phone,12*60*60,errTimes,function(err,response){ 572 | if(err) 573 | console.log(message.REDIS_ERROR); 574 | }) 575 | } 576 | else 577 | redisClient.setex('0'+phone,12*60*60,1,function(err,response){ 578 | if(err) 579 | console.log(message.REDIS_ERROR); 580 | }) 581 | }) 582 | 583 | onReject(message.PASSWORD_ERROR); 584 | } 585 | }) 586 | }) 587 | .then((userId)=> { 588 | userId = userId.toString(); 589 | genToken(userId, (err, token) => { 590 | err && res.json(message.GEN_TOKEN_ERROR); 591 | resultMsg = {statusCode: 102, 592 | message: message.LOGIN_SUCCESS, 593 | result: { 594 | userId: userId, 595 | token: token 596 | }}; 597 | res.json(resultMsg); 598 | }) 599 | }) 600 | .catch((errMsg) => { 601 | 602 | res.json(errMsg); 603 | logger.info(errMsg); 604 | }) 605 | } 606 | 607 | //注销登录 主要的动作是把token删除掉了 608 | var logout = function(req, res) { 609 | 610 | let userId = req.body.userId || req.headers.xkey; 611 | if(userId){ 612 | delToken(userId, (err, reply) => { 613 | if(err){ 614 | logger.error('Redis 数据库错误:' + err); 615 | res.json({statusCode: -1014, message: message.REDIS_ERROR}); 616 | }else{ 617 | res.json({statusCode: 100, message: message.OPERATION_SUCCESS}); 618 | } 619 | }) 620 | }else{ 621 | res.json({statusCode: 100, message: '用户未登陆'}); 622 | } 623 | } 624 | //查找个人信息通过type字段区分,type=me为查找自己的信息 625 | //type=he为查找他人信息 626 | var getInformation = function(req,res,type){ 627 | let userId = req.body.userId ;//|| req.headers.xkey; 628 | let query; 629 | if(!userId) 630 | return res.json(message.UNCOMPLETE_INPUT); 631 | if(type == 'me') 632 | query = '-frozen -scores -check'; 633 | else if(type == 'he') 634 | query = '-phone -frozen -message -password -check -frozen -scores'; 635 | UserDao.getUserByQuery( 636 | {'_id':userId,'frozen':1}, 637 | query, 638 | //'weChat qq skills', 639 | {}, 640 | (err, user) => { 641 | if(err) 642 | res.json(err.message);//message.MONGODB_ERROR); 643 | else if(!user) 644 | res.json(message.USER_NOT_EXIST); 645 | else { res.json({statusCode: 100, 646 | message: message.OPERATION_SUCCESS, 647 | result: { 648 | userInfo: user 649 | } 650 | }) 651 | } 652 | }); 653 | 654 | 655 | //}) 656 | } 657 | //获取自己的信息 几乎把所有数据都返回了 658 | var getMyInfo = function(req, res) { 659 | getInformation(req,res,'me'); 660 | } 661 | 662 | //查看他人信息 663 | var getInfo = function(req, res) { 664 | getInformation(req,res,'he'); 665 | } 666 | 667 | //查看用户排名表,返回用户所有信息 668 | var rank =function(req,res){ 669 | let rankBy = req.body.rankBy; 670 | if( req.body.start_num<0 || req.body.page_size<0 || _.isEmpty(rankBy) || (rankBy != 'scores' && rankBy != 'coin')) 671 | { 672 | return res.json(message.PARAMS_ERROR); 673 | } 674 | let start_num = req.body.start_num || 0; 675 | let page_size = req.body.page_size || 10; 676 | let query = {frozen:1}; 677 | let field = {stuName:1,stuNum:1,coin:1,avatar:1,finalScore:1}; 678 | let option; 679 | if(rankBy == 'scores') 680 | option = {limit:Number(req.body.page_size),sort:{'finalScore':-1},skip:Number(req.body.start_num)}; 681 | else if(rankBy == 'coin') 682 | option = {limit:Number(req.body.page_size),sort:{'coin':-1},skip:Number(req.body.start_num)}; 683 | UserDao.getUsersByQuery(query,field,option,function (err,users) { 684 | err && res.json(message.MONGODB_ERROR); 685 | users && res.json({statusCode:100,message:'success',result:users}); 686 | }); 687 | 688 | } 689 | 690 | 691 | //用户签到,每日签到时间币+1,连续7天签到时间币额外+3 692 | var checkin = function(req,res){ 693 | var userId = req.body.userId; 694 | var coins = 1; 695 | var now = new Date(); 696 | //规格化时间为月/日/年,用于计算最后签到日期和当前日期的天数差 697 | var now=now.toLocaleDateString(); 698 | //根据userId在数据库里面查找 699 | UserDao.getUserById(userId,function(err,user){ 700 | if(err) logger.error('checkin接口出错:' + err) && res.json(message.USERID_ERROR); 701 | 702 | else if(!user) res.json(message.USER_NOT_EXIST); 703 | 704 | else{ 705 | //如果用户没有签到记录 706 | if(user.check.checkDate.length == 0){ 707 | user.check.checkLog = 1; 708 | user.check.checkDate.push(now); 709 | user.check.lastDate = now; 710 | user.coin += coins; 711 | user.save(function(err,result){ 712 | if(err){ 713 | logger.error('checkin接口出错:' + err); 714 | res.json(message.MONGODB_ERROR); 715 | } 716 | else{ 717 | res.json({statusCode:100,message:message.OPERATION_SUCCESS,result:coins}); 718 | } 719 | }); 720 | 721 | } 722 | //如果这个用户之前签过到 723 | else{ 724 | var dif = (Date.parse(now) - Date.parse(user.check.lastDate)); 725 | var difDays = dif/86400000; 726 | if(difDays<0){ 727 | res.json(message.CHECKDATE_ERROR1); 728 | } 729 | //当天已签到 730 | else if(difDays==0){ 731 | res.json(message.CHECKDATE_ERROR2); 732 | } 733 | else{ 734 | //昨天和今天都签到了 735 | if(difDays==1){ 736 | user.check.checkLog++; 737 | if(user.check.checkLog==7){ 738 | coins = 4; 739 | user.check.checkLog=0; 740 | } 741 | } 742 | else{ 743 | user.check.checkLog = 1; 744 | } 745 | 746 | user.check.checkDate.push(now); 747 | user.check.lastDate = now; 748 | user.coin += coins; 749 | user.save(function(err,result){ 750 | if(err){ 751 | logger.error('checkin接口出错:' + err); 752 | res.json(message.MONGODB_ERROR); 753 | } 754 | else{ 755 | res.json({statusCode:100,message:message.OPERATION_SUCCESS,result:coins}); 756 | } 757 | }); 758 | } 759 | 760 | } 761 | } 762 | }) 763 | } 764 | 765 | //与我相关的帖子,包括我收藏的帖子、参与的帖子和我发布的帖子,由type字段确定 766 | var myPosts = function(req,res,type){ 767 | let info = req.body; 768 | info.start_num = info.start_num||0; 769 | info.page_size = info.page_size||10; 770 | let query; 771 | new Promise(function(resolve, reject) { 772 | 773 | if(_.isEmpty(info.userId)|| 774 | _.isEmpty(info.type)|| 775 | _.isEmpty(info.status)|| 776 | _.isEmpty(info.start_num)|| 777 | _.isEmpty(info.page_size)) 778 | { 779 | 780 | reject(message.UNCOMPLETE_INPUT); 781 | } 782 | else if( 783 | 784 | (!((info.type==1||info.type==0||info.type==2)&& 785 | (info.status==1||info.status==0||info.status==2 786 | ||info.status==3 || info.status == 4 || info.status == 5 787 | ||info.status==6))) 788 | ){ 789 | reject(message.POST_TYPE_ERROR); 790 | }else{ 791 | 792 | resolve(info); 793 | } 794 | 795 | }) 796 | .then(function(info) { 797 | //console.log(1); 798 | return new Promise((onFulfill,onReject) => { 799 | 800 | if(type == 'favo') 801 | { 802 | query ={lock:0,"favorUser.userId" : info.userId}; 803 | if(info.status==0){ 804 | query.status = {"$in":["0","1","2","5"]}; 805 | }else if(info.status==1 || info.status==2){ 806 | query.status = parseInt(info.status) + 2; 807 | } 808 | else //if (info.status==3) 809 | query.status = {"$in":["0","1","2","5","3","4"]}; 810 | 811 | 812 | if(info.type!=2){ 813 | query.postType = info.type; 814 | } 815 | } 816 | if(type == 'pub') 817 | { 818 | 819 | query ={lock:0,publisher : info.userId}; 820 | 821 | if(info.status==0){ 822 | //query.status = {"$in":["1","2"]};//,"5"]}; 823 | query.status = 2; 824 | }else if(info.status==3){ 825 | query.status = 7; 826 | }else if(info.status == 4){ 827 | query.status = 0; 828 | } 829 | else if(info.status == 5){ 830 | query.status = {"$in":["0","1","2","3","4","5","7"]}; 831 | } 832 | else if(info.status == 1){ 833 | // query.status = parseInt(info.status)+2; 834 | query.$or = [{status:3},{"$and":[{status:5},{scoreStatus:1}]},{"$and":[{status:5},{scoreStatus:3}]}]; 835 | } 836 | else if(info.status == 6){ 837 | query.$or = [{"$and":[{status:5},{scoreStatus:0}]},{"$and":[{status:5},{scoreStatus:2}]}]; 838 | } 839 | else if(info.status == 2){ 840 | //query.status = {"$or":[{}]}; 841 | 842 | query.status = parseInt(info.status)+2; 843 | //} 844 | } 845 | else { 846 | onReject(message.POST_TYPE_ERROR); 847 | } 848 | if(info.type!=2){ 849 | query.postType = info.type; 850 | } 851 | } 852 | if(type == 'join') 853 | { 854 | 855 | //query = {lock:0,"participant.userId" : info.userId}; 856 | if(info.status==0){ 857 | query = {lock:0,"participant.userId" : info.userId,"participant.status":{"$in":["0","1"]} }; 858 | }else if(info.status==2){ 859 | query = {lock:0,"participant.userId" : info.userId,"participant.status":parseInt(info.status)+3 }; 860 | 861 | }else if(info.status == 1 || info.status == 3){ 862 | query = {lock:0,"participant.userId" : info.userId,"participant.status": parseInt(info.status)+1 }; 863 | } 864 | else if(info.status == 4){ 865 | query = {lock:0,"participant.userId" : info.userId,"participant.status": {"$in":["0","1","2","4","5"]} }; 866 | } 867 | else { 868 | onReject(message.POST_TYPE_ERROR); 869 | } 870 | if(info.type != 2){ 871 | query.postType = info.type; 872 | } 873 | console.log(query); 874 | } 875 | 876 | //console.log(query); 877 | let option = {limit:Number(info.page_size),sort:{'pubTime':-1},skip:Number(info.start_num)}; 878 | PostDao.getPostsByQuery(query,null,option,function (err,posts) { 879 | //console.log(posts); 880 | //console.log(posts.length); 881 | if(err){ 882 | onReject(message.MONGODB_ERROR); 883 | }else if(!posts||posts.length==0){ 884 | onReject(message.OPERATION_SUCCESS); 885 | }else { 886 | onFulfill(posts); 887 | } 888 | }) 889 | }) 890 | 891 | 892 | }) 893 | .then((posts) => { 894 | //console.log(2); 895 | PostDao.getPostsLengthByQuery(query,null,null,function (err,length) { 896 | if(err){ 897 | 898 | onReject(message.MONGODB_ERROR); 899 | } 900 | else { 901 | 902 | posts.forEach(function(item){ 903 | if(item.publisherInfo != null){ 904 | item.publisherName = item.publisherInfo.stuName; 905 | item.publisherAvatar = item.publisherInfo.avatar; 906 | item.publisherScore = item.publisherInfo.finalScore.toFixed(1); 907 | item.save(); 908 | } 909 | }) 910 | 911 | res.json({statusCode: 100, message: message.OPERATION_SUCCESS, result:posts ,result_count:length}); 912 | } 913 | }) 914 | 915 | }).catch(function (err) { 916 | //console.log('err'); 917 | logger.info(err); 918 | res.json(err); 919 | }) 920 | } 921 | 922 | //我收藏的帖子 923 | var myFavoPosts = function(req,res){ 924 | myPosts(req,res,'favo'); 925 | } 926 | //我发布的帖子 927 | var myPubPosts = function(req,res){ 928 | myPosts(req,res,'pub'); 929 | } 930 | //我参与的帖子 931 | var myJoinPosts = function(req,res){ 932 | myPosts(req,res,'join'); 933 | } 934 | 935 | //修改密码,检查密码是否一致,然后检查手机验证码,如果相符修改数据库 936 | var updatePass = function(req,res){ 937 | //获取手机验证码以及修改的密码 938 | var phone = req.body.phone; 939 | var verifyCode = req.body.verifyCode; 940 | var password = req.body.password; 941 | 942 | if(_.isEmpty(password) || _.isEmpty(phone)|| _.isEmpty(verifyCode)) 943 | { 944 | return res.json(message.UNCOMPLETE_INPUT); 945 | } 946 | 947 | //检查用户验证码 948 | new Promise(function(resolve,reject){ 949 | 950 | //检查验证码 951 | redisClient.get(phone,function(err,res){ 952 | if(err) 953 | reject(err); 954 | 955 | else if(res != null){ 956 | let trueCode = res.toString(); 957 | if(verifyCode==trueCode){ 958 | resolve(); 959 | } 960 | else{ 961 | reject(message.VERIFYCODE_ERROR); 962 | } 963 | } 964 | else{ 965 | reject(message.VERIFYCODE_ERROR); 966 | } 967 | }); 968 | }) 969 | .then(function(){ 970 | return pGetUserByPhone(phone); 971 | }) 972 | .then(function(user){ 973 | return new Promise( function(resolve,reject){ 974 | let encodePass; 975 | let md5 = crypto.createHash('md5'); 976 | md5.update(password); 977 | encodePass = md5.digest('hex'); 978 | user.password = encodePass; 979 | user.save(function(err){ 980 | if(err){ 981 | logger.error('updatePass接口出错:' + err); 982 | reject(message.MONGODB_ERROR); 983 | } 984 | else 985 | resolve(); 986 | }) 987 | }) 988 | }) 989 | .then(function(){ 990 | res.json(message.OPERATION_SUCCESS); 991 | }) 992 | .catch(function(errMsg){ 993 | logger.info(err); 994 | res.json(errMsg); 995 | 996 | }) 997 | 998 | } 999 | 1000 | //修改个人资料 1001 | var update = function(req,res){ 1002 | var body = req.body; 1003 | if(_.isEmpty(body.userId)){ 1004 | res.json(message.UNCOMPLETE_INPUT); 1005 | } 1006 | else{ 1007 | //手机验证码检查 1008 | UserDao.getUserById(body.userId,function(err,user){ 1009 | if(err){ 1010 | logger.error('update接口出错:' + err); 1011 | res.json(message.MONGODB_ERROR); 1012 | } 1013 | else{ 1014 | //昵称,长号,短号,qq,wechat,skills(个人简介),sex 1015 | if(!_.isEmpty(body.stuName)){ 1016 | user.stuName = body.stuName; 1017 | } 1018 | //目前不允许修改密码 1019 | // if(!_.isEmpty(body.phone)){ 1020 | // user.phone = body.phone; 1021 | // } 1022 | if(!_.isEmpty(body.phone_short)){ 1023 | user.phone_short = body.phone_short; 1024 | } 1025 | if(!_.isEmpty(body.qq)){ 1026 | user.qq = body.qq; 1027 | } 1028 | if(!_.isEmpty(body.wechat)){ 1029 | user.wechat = body.wechat; 1030 | } 1031 | if(!_.isEmpty(body.skills)){ 1032 | user.skills = body.skills; 1033 | } 1034 | if(!_.isEmpty(body.sex) && (body.sex == 0 || body.sex == 1)){ 1035 | user.sex = body.sex; 1036 | } 1037 | user.save(function(err){ 1038 | if(err){ 1039 | logger.error('update接口出错:' + err); 1040 | res.json(message.MONGODB_ERROR); 1041 | } 1042 | 1043 | else { 1044 | 1045 | res.json(message.OPERATION_SUCCESS); 1046 | } 1047 | }) 1048 | } 1049 | 1050 | }) 1051 | } 1052 | } 1053 | 1054 | //获取三张默认头像 1055 | var getDefaultAvatar = function(req,res){ 1056 | res.json({statusCode:100,message:message.OPERATION_SUCCESS,result:config.defaultAvatar}); 1057 | } 1058 | 1059 | //single表示只上传一张头像 1060 | //var upload = multer(getOptions('avatar')).single('avatar'); 1061 | var avatar= function(req,res){ 1062 | /*upload(req,res,function(err){ 1063 | if(err || _.isEmpty(req.file)) { 1064 | 1065 | return res.json(message.UPLOAD_FILE_ERROR); 1066 | } 1067 | console.log(req.body.userId);*/ 1068 | 1069 | 1070 | //获取裁剪参数,flag 是是否成功截图的标记 1071 | let x = req.body.x || 0, 1072 | y = req.body.y || 0, 1073 | height = req.body.height || 50, 1074 | flag =0; 1075 | let userId = req.body.userId || req.headers.xkey; 1076 | 1077 | new Promise(function(resolve,reject){ 1078 | 1079 | if(x >= 0 && y >= 0 && height > 0 ) 1080 | { 1081 | resolve(); 1082 | } 1083 | else{ 1084 | 1085 | reject(message.PARAMS_ERROR); 1086 | } 1087 | }) 1088 | .then(function(){ 1089 | return new Promise(function(resolve,reject){ 1090 | gm(req.file.path).size(function(err,value){ 1091 | if(err||_.isEmpty(value)) 1092 | { 1093 | logger.error('avatar接口出错:' + err); 1094 | reject(message.GM_ERROR); 1095 | } 1096 | else{ 1097 | 1098 | resolve(value); 1099 | } 1100 | }) 1101 | }) 1102 | }) 1103 | .then(function(value){ 1104 | return new Promise(function(resolve,reject){ 1105 | gm(req.file.path).resize(value.width,value.height).crop(height,height,x,y).write(req.file.path,function(err) { 1106 | if(err){ 1107 | logger.error('avatar接口出错:' + err); 1108 | reject(message.GM_ERROR); 1109 | } 1110 | else 1111 | resolve(); 1112 | 1113 | }) 1114 | }) 1115 | }) 1116 | .then(function(){ 1117 | return pGetUserById(userId); 1118 | }) 1119 | .then(function(user){ 1120 | 1121 | //删除用户以前的头像,但是不能删除系统默认的三张头像 1122 | let index1 = config.defaultAvatar.indexOf(user.avatar); 1123 | if(!_.isEmpty(user.avatar) && index1 == -1){ 1124 | 1125 | fs.unlink('C:/Users/301/Desktop/tbApi/public/'+user.avatar,function(err){ 1126 | if(err) 1127 | 1128 | logger.error('avatar接口出错:' + err); 1129 | 1130 | }) 1131 | } 1132 | 1133 | user.avatar = '/avatar/'+ req.file.filename; 1134 | user.save(function(err){ 1135 | if(err){ 1136 | logger.error('avatar接口出错:' + err); 1137 | reject(message.MONGODB_ERROR); 1138 | } 1139 | else{ 1140 | res.json({statusCode: 100, message: message.OPERATION_SUCCESS, result: user.avatar}); 1141 | } 1142 | 1143 | }) 1144 | }) 1145 | .catch(function(err){ 1146 | 1147 | fs.unlink(req.file.path,function(err){ 1148 | if(err) 1149 | logger.error('avatar接口出错:' + err); 1150 | }); 1151 | logger.info(err); 1152 | res.json(err); 1153 | }) 1154 | 1155 | 1156 | 1157 | // }) 1158 | } 1159 | 1160 | var multi = function(req,res){ 1161 | uploadMultiPics(req,res,function(err,result,body){ 1162 | if(err) 1163 | res.json(err); 1164 | else{ 1165 | console.log(body); 1166 | res.json(result); 1167 | } 1168 | }) 1169 | } 1170 | exports.multi = multi; 1171 | 1172 | //获取评分状态 1173 | var getScoreStatus = function(userId,postId,cb){ 1174 | PostDao.getPostById(postId,function(err,post){ 1175 | var status = {}; 1176 | if(err){ 1177 | //cb({statusCode: -1036, message: message.POSTID_ERROR, result:''}); 1178 | status.code = -1036; 1179 | status.message = message.POSTID_ERROR; 1180 | 1181 | //cb(status); 1182 | } 1183 | else if(_.isEmpty(post)){ 1184 | //cb({statusCode: -1037, message: message.POST_NOT_EXIST, result:''}) 1185 | status.code = -1037; 1186 | status.message = message.POST_NOT_EXIST; 1187 | } 1188 | else if(post.status != 5){ 1189 | //cb({statusCode: -1038, message: message.TASK_NOT_FINISHED, result:''}); 1190 | status.code = -1038; 1191 | status.message = message.TASK_NOT_FINISHED; 1192 | } 1193 | else{ 1194 | var scoreStatus = post.scoreStatus; 1195 | var flag = 0; 1196 | post.participant.forEach(function(item){ 1197 | if(item.userId == userId) 1198 | flag = 1; 1199 | }); 1200 | if(scoreStatus ==3){ 1201 | //cb({statusCode: -1039, message: message.SCORE_FINISHED, result:''}); 1202 | status.code = -1039; 1203 | status.message = message.SCORE_FINISHED; 1204 | } 1205 | else if(scoreStatus == 0){ 1206 | //cb({statusCode: -1040, message: '双方尚未评分', result:''}); 1207 | status.code = 0; 1208 | status.message = '双方尚未评分'; 1209 | } 1210 | else if((scoreStatus == 1 && userId == post.publisher) || (scoreStatus == 2 && flag == 1)) 1211 | { 1212 | //cb({statusCode: 100, message: '你已经评分', result:''}); 1213 | status.code = -1; 1214 | status.message = '你已经评分'; 1215 | } 1216 | else if((scoreStatus == 1 && flag == 1) || (scoreStatus == 2 && userId == post.publisher)){ 1217 | //cb({statusCode: 100, message: '对方等待你评分', result:''}); 1218 | status.code = 1; 1219 | status.message = '对方等待你评分'; 1220 | } 1221 | else{ 1222 | //cb({statusCode: -100, message: '评分逻辑出错', result:''}); 1223 | status.code = -2; 1224 | status.message = '评分人不是发布人也不是任务人'; 1225 | } 1226 | 1227 | } 1228 | cb(status); 1229 | }) 1230 | } 1231 | var getEvaluateStatus = function(req,res){ 1232 | getScoreStatus(req.body.userId,req.body.postId,function(status){ 1233 | res.json({statusCode: status.code, message: status.message, result:''}); 1234 | }) 1235 | } 1236 | exports.getEvaluateStatus = getEvaluateStatus; 1237 | //用户评分 1238 | var grade = function(req,res){ 1239 | let body = req.body; 1240 | if(_.isEmpty(body.userId)|| 1241 | _.isEmpty(body.target)|| 1242 | _.isEmpty(body.postId)|| 1243 | _.isEmpty(body.score)){ 1244 | return res.json(message.UNCOMPLETE_INPUT); 1245 | } 1246 | if(parseInt(body.score)<0) 1247 | req.body.score = 0; 1248 | if(parseInt(body.score)>5) 1249 | req.body.score = 5; 1250 | 1251 | let p1 = pGetUserById(req.body.userId); 1252 | 1253 | let p2 = pGetUserById(req.body.target); 1254 | 1255 | var p3 =pGetPostById(req.body.postId); 1256 | //当userId,targetId,postId都存在的时候 1257 | Promise.all([p1,p2,p3]).then(function(result){ 1258 | return new Promise(function(resolve,reject){ 1259 | let post = result[2]; 1260 | if(post.status != 5) 1261 | { 1262 | reject(message.TASK_NOT_FINISHED); 1263 | } 1264 | else{ 1265 | //如果评分人是参与人,flag = 1 1266 | let flag = 0; 1267 | post.participant.forEach(function(item){ 1268 | if(item.userId == result[0]._id) 1269 | flag = 1; 1270 | if(item.userId == result[1]._id) 1271 | flag = 2; 1272 | }); 1273 | if(post.scoreStatus == 3){ 1274 | reject(message.SCORE_FINISHED); 1275 | } 1276 | else if(result[0]._id != result[2].publisher && flag == 0){ 1277 | reject(message.GRADE_ERROR); 1278 | } 1279 | else if((result[0]._id == result[2].publisher && result[2].scoreStatus == 1) 1280 | || (flag == 1 && result[2].scoreStatus == 2)){ 1281 | reject(message.GRADE_ERROR); 1282 | } 1283 | else if( (result[0]._id == result[2].publisher && flag == 2 ) || (result[1]._id == result[2].publisher && flag == 1) ) 1284 | { 1285 | resolve(result); 1286 | } 1287 | else 1288 | { 1289 | reject(message.GRADE_ERROR); 1290 | } 1291 | 1292 | } 1293 | }) 1294 | }) 1295 | .then(function(result){ 1296 | return new Promise(function(resolve,reject){ 1297 | let user = result[0], 1298 | target = result[1], 1299 | post = result[2]; 1300 | //深拷贝与浅拷贝 1301 | let temp = post; 1302 | //如果评分人是参与人,flag = 1 1303 | let flag = 0; 1304 | post.participant.forEach(function(item){ 1305 | //只有参与人的状态为4才可以评分 1306 | if(item.userId == user._id && item.status == 4) 1307 | flag = 1; 1308 | }); 1309 | if(user._id == post.publisher && post.scoreStatus == 0){ 1310 | post.scoreStatus = 1; 1311 | } 1312 | else if(flag == 1 && post.scoreStatus == 0){ 1313 | post.scoreStatus = 2; 1314 | } 1315 | else if((user._id == post.publisher && post.scoreStatus == 2) || (flag == 1 && post.scoreStatus == 1)){ 1316 | post.scoreStatus = 3; 1317 | post.status = 3; 1318 | post.participant.forEach(function(item){ 1319 | if(item.status == 4) 1320 | item.status = 2; 1321 | }) 1322 | } 1323 | else{ 1324 | logger.error('grade接口出错:评分逻辑错误'); 1325 | reject(message.GRADE_ERROR); 1326 | } 1327 | let item = { 1328 | isValidate : 1 , //0无效|1默认有效 1329 | postId : post._id, //来自哪个帖子的评分 1330 | fromUser : user._id, //(_id) 1331 | score : req.body.score, //(0-5 0.5间隔) 1332 | time : new Date() 1333 | } 1334 | target.scores.push(item); 1335 | //刷新finalScore 1336 | target.finalScore = getFinalScore(result[1].scores); 1337 | post.save(function(err){ 1338 | if(err) { 1339 | logger.error('grade接口出错:' + err); 1340 | reject({statusCode:-1015,message:message.MONGODB_ERROR,result:''}); 1341 | } 1342 | resolve([target,post,temp]); 1343 | }) 1344 | }) 1345 | }) 1346 | .then(function(result){ 1347 | let target = result[0]; 1348 | let post = result[1]; 1349 | let temp = result[2]; 1350 | target.save(function(err){ 1351 | if(err){ 1352 | logger.error('grade接口出错:' + err); 1353 | //事务回滚 1354 | post = temp; 1355 | post.save(function(err){ 1356 | if(err){ 1357 | logger.error('grade接口出错:事务回滚出错'); 1358 | reject(message.ROLLBACK_ERROR); 1359 | } 1360 | else{ 1361 | logger.error('grade接口出错:mongoDB出错'); 1362 | reject({statusCode:-1015,message:message.MONGODB_ERROR,result:''}); 1363 | } 1364 | }) 1365 | } 1366 | else{ 1367 | res.json(message.OPERATION_SUCCESS); 1368 | } 1369 | 1370 | }) 1371 | 1372 | }) 1373 | .catch(function(err){ 1374 | 1375 | res.json(err); 1376 | logger.info(err); 1377 | }) 1378 | } 1379 | //标记已读消息 1380 | var markRead = function(req,res){ 1381 | var userId = req.body.userId; 1382 | var msgId = req.body.msgId; 1383 | if(_.isEmpty(userId) || _.isEmpty(msgId)){ 1384 | return res.json(message.UNCOMPLETE_INPUT); 1385 | } 1386 | pGetUserById(userId) 1387 | .then((user)=> { 1388 | return new Promise((resolve,reject)=>{ 1389 | _.isEmpty(user.message) && reject(message.USER_NOT_MSG); 1390 | //flag标记是否找到匹配消息 1391 | let flag = 0, 1392 | l =user.message.length; 1393 | let item; 1394 | for(let i = 0 ; i < l; ++i){ 1395 | item = user.message[i]; 1396 | if(item._id == msgId){ 1397 | flag = 1; 1398 | if(item.read == 1){ 1399 | resolve(message.OPERATION_SUCCESS); 1400 | 1401 | } 1402 | else if(item.read == 0){ 1403 | item.read = 1; 1404 | user.save(function(err){ 1405 | if(err){ 1406 | logger.error('markRead接口出错:' + err); 1407 | res.json(message.MONGODB_ERROR); 1408 | } 1409 | else 1410 | resolve(message.OPERATION_SUCCESS); 1411 | }) 1412 | 1413 | } 1414 | break; 1415 | } 1416 | } 1417 | if(flag == 0){ 1418 | reject(message.MSG_NOT_EXIST); 1419 | } 1420 | }) 1421 | }) 1422 | .then((result)=>{ 1423 | res.json(result); 1424 | }) 1425 | .catch((errMsg)=>{ 1426 | res.json(errMsg); 1427 | logger.info(errMsg); 1428 | }) 1429 | 1430 | 1431 | } 1432 | //用于消息的排序 1433 | // General comparison function for convenience 1434 | function compare(x, y) { 1435 | if (x === y) { 1436 | return 0; 1437 | } 1438 | return x > y ? 1 : -1; 1439 | } 1440 | 1441 | 1442 | //获取消息 1443 | var getMsg = function(req,res){ 1444 | var userId = req.body.userId || req.headers.xkey; 1445 | 1446 | 1447 | UserDao.getUserById(userId,(err, user) => { 1448 | if(err){ 1449 | logger.error('getMsg接口出错:' + err); 1450 | return res.json(message.MONGODB_ERROR); 1451 | } 1452 | if(!user) return res.json(message.USER_NOT_EXIST); 1453 | 1454 | 1455 | //先按read排,再按date排序 1456 | user.message.sort(function(x,y){ 1457 | if(x.read != y.read) 1458 | return compare(x.read,y.read); 1459 | return compare(Date.parse(y.date),Date.parse(x.date)); 1460 | }) 1461 | //只筛选前面20条信息 1462 | let end = 20>user.message.length?user.message.length:20; 1463 | //console.log(end); 1464 | 1465 | let message1 = user.message.slice(0,end); 1466 | //console.log(message1.length); 1467 | let readStatus = _.countBy(message1,function(item){ 1468 | return item.read == 0 ? 'unread': 'read'; 1469 | }) 1470 | 1471 | /*if(message1.length == readStatus.read){ 1472 | readStatus.unread = 0; 1473 | }*/ 1474 | //console.log(readStatus); 1475 | //console.log(readStatus.unread); 1476 | /*console.log({statusCode: 100, 1477 | message: message.OPERATION_SUCCESS, 1478 | result:{ 1479 | unReadNum:readStatus.unread, 1480 | msgList: message1 1481 | } 1482 | });*/ 1483 | res.json({statusCode: 100, 1484 | message: message.OPERATION_SUCCESS, 1485 | result:{ 1486 | unReadNum:readStatus.unread, 1487 | msgList: message1 1488 | } 1489 | }); 1490 | 1491 | 1492 | }) 1493 | 1494 | } 1495 | 1496 | 1497 | //查找跟关键字相关的用户和帖子 1498 | var search = function(req, res) { 1499 | let type = req.body.type; 1500 | let keyword = req.body.keyword; 1501 | let start_num = req.body.start_num || 0; 1502 | let page_size = req.body.page_size || 10; 1503 | let query; 1504 | let errMsg; 1505 | let result; 1506 | //搜索用户姓名学号,帖子标题内容 1507 | var userField = {stuName:1,stuNum:1,coin:1,avatar:1,skills:1,finalScore:1,sex:1}; 1508 | var postField = {title:1,content:1,publisherName:1,status:1,pubTimeL:1,favorCount:1,coinBank:1,commentNum:1,publisherInfo:1,publisherAvatar:1}; 1509 | var userQuery = {frozen:1,"$or":[{"stuName": new RegExp(keyword, 'i')},{"stuNum": new RegExp(keyword, 'i')}]}; 1510 | var postQuery = {lock:0,"$or":[{"title": new RegExp(keyword, 'i')},{"content":new RegExp(keyword, 'i')}]}; 1511 | var p1 = new Promise(function(resolve,reject){ 1512 | UserDao.getUsersByQuery(userQuery,userField,{skip: Number(start_num), limit: Number(page_size)},(err, users_list)=>{ 1513 | if(err){ 1514 | logger.error('search接口出错:' + err); 1515 | reject(message.MONGODB_ERROR); 1516 | } 1517 | else{ 1518 | resolve(users_list); 1519 | } 1520 | }) 1521 | }) 1522 | var p2 = new Promise(function(resolve,reject){ 1523 | PostDao.getPostsByQuery(postQuery,postField,{skip: Number(start_num), limit: Number(page_size)},(err, posts_list)=>{ 1524 | if(err){ 1525 | logger.error('search接口出错:' + err); 1526 | reject(message.MONGODB_ERROR); 1527 | } 1528 | else{ 1529 | //对输出的post进行处理,使得post里面与user有关的数据同步 1530 | posts_list.forEach(function(item){ 1531 | item.publisherName = item.publisherInfo.stuName; 1532 | item.publisherAvatar = item.publisherInfo.avatar; 1533 | item.save(); 1534 | }); 1535 | resolve(posts_list); 1536 | } 1537 | }) 1538 | }) 1539 | 1540 | Promise.all([p1,p2]).then(function(list){ 1541 | res.json({statusCode:100,message:message.OPERATION_SUCCESS,result:list}); 1542 | }) 1543 | .catch(function(err){ 1544 | logger.info('search接口出错:' + err); 1545 | res.json(err); 1546 | }) 1547 | } 1548 | //获取网上商城的URL 1549 | var getURL = function(req, res) { 1550 | res.json({url:'http://210.39.12.70:3000/mall/mall.html',showBtn:true}); 1551 | } 1552 | //获取网上商城的商品 1553 | var getItems = function(req,res){ 1554 | console.log(req.body.start_num); 1555 | let start_num = req.body.start_num || 0; 1556 | let page_size = req.body.page_size || 10; 1557 | let sortBy = req.body.sortBy || 'time_to_market'; 1558 | //console.log(sortBy); 1559 | let query = {isDelete:false}; 1560 | let field = {isDelete:0}; 1561 | let option; 1562 | 1563 | if(sortBy == 'price') 1564 | option = {skip: Number(start_num), limit: Number(page_size),sort:{price:-1}}; 1565 | else{ 1566 | option = {skip: Number(start_num), limit: Number(page_size),sort:{time_to_market:-1}}; 1567 | } 1568 | 1569 | ItemDao.getItemsByQuery(query,field,option,(err,items)=>{ 1570 | if(err) 1571 | res.json(message.MONGODB_ERROR); 1572 | else 1573 | res.json({statusCode:100,message:'获取成功',result:items}); 1574 | }); 1575 | } 1576 | exports.getItems = getItems; 1577 | exports.buy = buy; 1578 | exports.getURL = getURL; 1579 | exports.myFavoPosts = myFavoPosts; 1580 | exports.myJoinPosts = myJoinPosts; 1581 | exports.myPubPosts = myPubPosts; 1582 | 1583 | exports.insertStu = insertStu; 1584 | exports.verifyStuNum = verifyStuNum; 1585 | exports.signup = signup; 1586 | exports.login = login; 1587 | exports.logout = logout; 1588 | exports.getMyInfo = getMyInfo; 1589 | exports.rank = rank; 1590 | exports.getVerCode = getVerCode; 1591 | exports.getInfo = getInfo; 1592 | exports.checkin = checkin; 1593 | exports.updatePass = updatePass; 1594 | exports.update = update; 1595 | exports.avatar = avatar; 1596 | exports.grade = grade; 1597 | exports.markRead = markRead; 1598 | exports.getMsg = getMsg; 1599 | exports.getDefaultAvatar = getDefaultAvatar; 1600 | exports.search = search; 1601 | 1602 | 1603 | -------------------------------------------------------------------------------- /dao/applicationDao.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ajay on 2017/4/5. 3 | */ 4 | var Application = require('../model/application'); 5 | var mongoose = require('mongoose'); 6 | /** 7 | * 初始化报名信息 8 | * @param callback 9 | * @param postInfo 10 | */ 11 | exports.insertRegister = function (Info, callback) { 12 | var application = new Application(); 13 | application.college = Info.college; 14 | application.name = Info.name; 15 | application.grade = Info.grade; 16 | application.stuNum = Info.stuNum; 17 | application.sex = Info.sex; 18 | application.phone = Info.phone; 19 | application.wechat = Info.wechat; 20 | application.applyDate = Date.now(); 21 | application.save(callback); 22 | }; 23 | 24 | /** 25 | * 根据学号,获取申请 26 | * Callback: 27 | * - err, 数据库异常 28 | * - register, 用户 29 | * @param stuNum 学号 30 | * @param {Function} callback 回调函数 31 | */ 32 | 33 | exports.getRegisterByStuNum = function (stuNum, callback) { 34 | Application.findOne({stuNum: stuNum}, callback); 35 | }; 36 | 37 | 38 | exports.getApplicationsByQuery = function ( callback) {//query,fields ,option , 39 | Application.find(callback);//query,fields,option, 40 | }; -------------------------------------------------------------------------------- /dao/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by MARDAN on 2016/7/12. 3 | */ 4 | 5 | 6 | exports.UserDao = require('./userDao'); 7 | exports.StuInfoDao = require('./stuInfoDao'); 8 | exports.PostDao = require('./postDao'); 9 | exports.TipDao = require('./tipDao'); 10 | exports.ItemDao = require('./itemDao'); 11 | exports.TradeDao = require('./tradeDao'); 12 | exports.ApplicationDao = require('./applicationDao'); -------------------------------------------------------------------------------- /dao/itemDao.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ajay on 2017/3/26. 3 | */ 4 | var Item = require('../model/item'); 5 | 6 | /** 7 | * 通过ID查找一个商品 8 | * @param itemId 9 | */ 10 | exports.getItemById = function (itemId, callback) { 11 | Item.findOne({_id: itemId}).exec(callback); 12 | }; 13 | 14 | 15 | 16 | /** 17 | * 根据关键字,获取一组商品 18 | * Callback: 19 | * - err, 数据库异常 20 | * - items, 商品列表 21 | * @param {String} query 关键字 22 | * @param {Object} option 选项 23 | * @param fields 所返回的数据限制 24 | * @param {Function} callback 回调函数 25 | */ 26 | exports.getItemsByQuery = function (query,fields ,option , callback) { 27 | Item.find(query,fields,option,callback); 28 | }; -------------------------------------------------------------------------------- /dao/postDao.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by MARDAN on 2016/7/10. 3 | */ 4 | var Post = require('../model/post'); 5 | var config = require('../config/config'); 6 | var mongoose = require('mongoose'); 7 | /** 8 | * 初始化帖子,发帖子是初始化 9 | * @param callback 10 | * @param postInfo 11 | */ 12 | exports.newPostAndSave = function (postInfo, callback) { 13 | var post = new Post(); 14 | post.topicType = postInfo.topicType; 15 | post.contact = postInfo.contact; 16 | post.publisherName = postInfo.publisherName; 17 | //publisher类型必须是objectId,不然ref失败 18 | post.publisher = postInfo.userId; 19 | post.publisherInfo= mongoose.Types.ObjectId(postInfo.userId); 20 | //现在只有一种帖子 1 类型 21 | //post.postType = postInfo.postType; 22 | post.postType = 1; 23 | post.title = postInfo.title; 24 | post.content = postInfo.content; 25 | post.expTime = postInfo.expTime; 26 | post.pictures = postInfo.pictures; 27 | post.publisherAvatar = postInfo.publisherAvatar; 28 | post.publisherScore = postInfo.publisherScore; 29 | post.pubTime = new Date(); 30 | post.coinBank.expDealTime = new Date(Number(post.expTime) + Number(config.autoMakeDealTime)); 31 | post.missionCoin = postInfo.missionCoin; 32 | post.save(callback); 33 | 34 | }; 35 | 36 | 37 | 38 | /** 39 | * 根据关键字,获取一组帖子的长度 40 | * Callback: 41 | * - err, 数据库异常 42 | * - users, 用户列表 43 | * @param {String} query 关键字 44 | * @param {Object} option 选项 45 | * @param fields 所返回的数据限制 46 | * @param {Function} callback 回调函数 47 | */ 48 | exports.getPostsLengthByQuery = function (query,fields ,option , callback) { 49 | Post.find(query,fields,option,function (err,posts) { 50 | if(err){ 51 | return callback('getPostsLengthByQuery'+'查询数据库失败'); 52 | }else{ 53 | return callback(null,posts.length); 54 | } 55 | }); 56 | }; 57 | 58 | /** 59 | * 查找用户的所有帖子列表 60 | * Callback: 61 | * - err, 数据库异常 62 | * - posts, 帖子列表 63 | * @param {Array} publisherId 用户id 64 | * @param {Function} callback 回调函数 65 | */ 66 | // exports.getPostsByPublisher = function (publisherId, callback) { 67 | // Post.find( {lock:0,publisher:publisherId }, callback); 68 | // }; 69 | 70 | exports.getPostsByPublisher = function (publisherId, callback) { 71 | Post.find( {lock:0,publisher:publisherId }).populate({path: 'publisherInfo',select: 'stuName _id avatar finalScore'}).exec(callback); 72 | }; 73 | 74 | 75 | /** 76 | * 根据帖子标题列表查找帖子列表 77 | * Callback: 78 | * - err, 数据库异常 79 | * - posts, 帖子列表 80 | * @param {Array} titles 帖子列表 81 | * @param {Function} callback 回调函数 82 | */ 83 | // exports.getPostsByTitles = function (titles, callback) { 84 | // Post.find({ lock:0,title: { $in: titles} }, callback); 85 | // }; 86 | exports.getPostsByTitles = function (titles, callback) { 87 | Post.find({ lock:0,title: { $in: titles} }).populate({path: 'publisherInfo',select: 'stuName _id avatar finalScore'}).exec(callback); 88 | }; 89 | 90 | 91 | /** 92 | * 根据关键字,获取一组帖子 93 | * Callback: 94 | * - err, 数据库异常 95 | * - users, 用户列表 96 | * @param {String} query 关键字 97 | * @param {Object} option 选项 98 | * @param fields 所返回的数据限制 99 | * @param {Function} callback 回调函数 100 | */ 101 | // exports.getPostsByQuery = function (query,fields ,option , callback) { 102 | // Post.find(query,fields,option,callback); 103 | // }; 104 | exports.getPostsByQuery = function (query,fields ,option , callback) { 105 | Post.find(query,fields,option).populate({path: 'publisherInfo',select: 'stuName _id avatar finalScore'}).exec(callback); 106 | } 107 | 108 | 109 | 110 | 111 | /** 112 | * 根据标题查找帖子 113 | * Callback: 114 | * - err, 数据库异常 115 | * - post, 帖子 116 | * @param {String} title 登录名 117 | * @param {Function} callback 回调函数 118 | */ 119 | // exports.getPostsByTitle = function (title, callback) { 120 | // Post.findOne({lock:0,title: title},callback); 121 | // }; 122 | 123 | exports.getPostsByTitle = function (title, callback) { 124 | Post.findOne({lock:0,title: title}).populate({path: 'publisherInfo',select: 'stuName _id avatar finalScore'}).exec(callback); 125 | }; 126 | 127 | 128 | // * 129 | // * 根据postType查找帖子列表 130 | // * Callback: 131 | // * - err, 数据库异常 132 | // * - post, 帖子 133 | // * @param {String} postType 帖子类型 134 | // * @param {Function} callback 回调函数 135 | 136 | // exports.getPostsByPostType = function (postType, callback) { 137 | // Post.find({postType: postType}, callback); 138 | // }; 139 | 140 | 141 | 142 | /** 143 | * 根据帖子ID,查找单个帖子 144 | * Callback: 145 | * - err, 数据库异常 146 | * - post, 帖子 147 | * @param {String} id 帖子ID 148 | * @param {Function} callback 回调函数 149 | */ 150 | // exports.getPostById = function (id, callback) { 151 | // Post.findOne({lock:0,_id: id},callback); 152 | // }; 153 | exports.getPostById = function (id, callback) { 154 | Post.findOne({lock:0,_id: id}).populate({path: 'publisherInfo',select: 'stuName _id avatar finalScore'}).exec(callback); 155 | }; 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /dao/stuInfoDao.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ajay on 2016/12/28. 3 | */ 4 | var StuInfo = require('../model/stuInfo').stuInfo; 5 | 6 | 7 | /** 8 | * 注册初始化 9 | * @param stuName 10 | * @param stuNum 11 | * @param callback 12 | */ 13 | exports.newStuAndSave = function (stuName, stuNum, callback) { 14 | var stuInfo = new StuInfo(); 15 | stuInfo.stuName = stuName; 16 | stuInfo.stuNum = stuNum; 17 | stuInfo.save(callback); 18 | }; 19 | 20 | /** 21 | * 根据学号,获取用户 22 | * Callback: 23 | * - err, 数据库异常 24 | * - user, 用户 25 | * @param stuNum 学号 26 | * @param {Function} callback 回调函数 27 | */ 28 | 29 | exports.getUserByStuNum = function (stuNum, callback) { 30 | StuInfo.findOne({stuNum: stuNum}, callback); 31 | }; 32 | -------------------------------------------------------------------------------- /dao/tipDao.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by MARDAN on 2016/7/26. 3 | */ 4 | var Tip = require('../model/tip'); 5 | 6 | /** 7 | * 举报帖子的初始化 8 | * @param callback 9 | * @param tipInfo 10 | */ 11 | exports.newTipAndSave = function (tipInfo, callback) { 12 | var tip = new Tip(); 13 | tip.fromName = tipInfo.fromName; 14 | tip.toName = tipInfo.toName; 15 | tip.postId = tipInfo.postId; 16 | tip.fromId = tipInfo.fromId; 17 | tip.toId = tipInfo.toId; 18 | tip.tipReason = tipInfo.tipReason; 19 | tipDate = new Date(); 20 | tip.save(callback); 21 | }; 22 | 23 | 24 | /** 25 | * 根据关键字,获取一组举报信息的长度 26 | * Callback: 27 | * - err, 数据库异常 28 | * - users, 用户列表 29 | * @param {String} query 关键字 30 | * @param {Object} option 选项 31 | * @param fields 所返回的数据限制 32 | * @param {Function} callback 回调函数 33 | */ 34 | exports.getTipsLengthByQuery = function (query,fields ,option , callback) { 35 | Tip.find(query,fields,option,callback.length); 36 | }; 37 | 38 | 39 | 40 | /** 41 | * 通过举报者和帖子id获取举报信息 42 | * @param fromId 43 | * @param postId 44 | * @param callback 45 | */ 46 | exports.getTipByUserIdAndPostId = function (fromId , postId ,callback) { 47 | Tip.findOne({fromId: fromId,postId:postId},callback); 48 | }; -------------------------------------------------------------------------------- /dao/tradeDao.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ajay on 2017/3/26. 3 | */ 4 | var Trade = require('../model/trade'); 5 | 6 | /** 7 | * 新建一个交易 8 | * @param info 一个交易的信息 9 | */ 10 | exports.newTradeAndSave = function (info, callback) { 11 | var trade = new Trade(); 12 | trade.userId = info.userId; 13 | trade.userName = info.userName; 14 | trade.itemId = info.itemId; 15 | trade.itemName = info.itemName; 16 | trade.numberOfItem = info.numberOfItem; 17 | trade.exchangeCode = info.exchangeCode; 18 | trade.save(callback); 19 | }; 20 | -------------------------------------------------------------------------------- /dao/userDao.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by MARDAN on 2016/7/10. 3 | */ 4 | var User = require('../model/user').user; 5 | 6 | 7 | /** 8 | * 注册初始化 9 | * @param stuName 10 | * @param phone 11 | * @param password 12 | * @param callback 13 | */ 14 | exports.newUserAndSave = function (phone, stuName, stuNum,password, sex, callback) { 15 | var user = new User(); 16 | user.stuName = stuName; 17 | user.stuNum = stuNum; 18 | user.phone = phone; 19 | user.password = password; 20 | user.registerTime = new Date(); 21 | user.sex = sex; 22 | user.avatar = (sex == 0 ? "/avatar/default_1.jpg":"/avatar/default_2.jpg"); 23 | user.save(callback); 24 | }; 25 | 26 | 27 | /** 28 | * 根据关键字,获取一组用户 29 | * Callback: 30 | * - err, 数据库异常 31 | * - users, 用户列表 32 | * @param {String} query 关键字 33 | * @param {Object} option 选项 34 | * @param fields 所返回的数据限制 35 | * @param {Function} callback 回调函数 36 | */ 37 | exports.getUsersByQuery = function (query,fields,option,callback) { 38 | User.find(query,fields,option,callback); 39 | }; 40 | 41 | 42 | /** 43 | * 根据关键字,获取一组用户 44 | * Callback: 45 | * - err, 数据库异常 46 | * - users, 用户列表 47 | * @param {String} query 关键字 48 | * @param {Object} option 选项 49 | * @param fields 所返回的数据限制 50 | * @param {Function} callback 回调函数 51 | */ 52 | //Adventure.findById(id, 'name', { lean: true }, function (err, doc) {}); 53 | exports.getUserByQuery = function (query,fields,option,callback) { 54 | //Adventure.findById(id, '-length').exec(function (err, adventure) {}); 55 | User.findById(query,fields,option,callback); 56 | }; 57 | 58 | /** 59 | * 根据用户手机号,获取用户 60 | * Callback: 61 | * - err, 数据库异常 62 | * - user, 用户 63 | * @param phone 用户电话 64 | * @param {Function} callback 回调函数 65 | */ 66 | exports.getUserByPhone = function (phone, callback) { 67 | User.findOne({frozen:1,phone: phone}, callback); 68 | }; 69 | 70 | 71 | /** 72 | * 根据关键字,获取一组用户的长度 73 | * Callback: 74 | * - err, 数据库异常 75 | * - users, 用户列表 76 | * @param {String} query 关键字 77 | * @param {Object} option 选项 78 | * @param fields 所返回的数据限制 79 | * @param {Function} callback 回调函数 80 | */ 81 | exports.getUsersLengthByQuery = function (query,fields ,option , callback) { 82 | User.find(query,fields,option,function (err,users) { 83 | if(err){ 84 | return callback('getUsersLengthByQuery'+'查询数据库失败'); 85 | }else{ 86 | return callback(null,users.length); 87 | } 88 | }); 89 | }; 90 | 91 | 92 | 93 | /** 94 | * 根据用户ID,查找用户 95 | * Callback: 96 | * - err, 数据库异常 97 | * - user, 用户 98 | * @param {String} id 用户ID 99 | * @param {Function} callback 回调函数 100 | */ 101 | exports.getUserById = function (id, callback) { 102 | User.findOne({_id: id,frozen:1}, callback); 103 | }; 104 | 105 | /** 106 | * 根据学生姓名列表查找用户列表 107 | * Callback: 108 | * - err, 数据库异常 109 | * - users, 用户列表 110 | * @param {Array} names 用户名列表 111 | * @param {Function} callback 回调函数 112 | */ 113 | exports.getUsersByStuNames = function (names, callback) { 114 | User.find({ 'stuName': { $in: names } }, callback); 115 | }; 116 | 117 | 118 | 119 | /** 120 | * 根据用户ID列表,获取一组用户 121 | * Callback: 122 | * - err, 数据库异常 123 | * - users, 用户列表 124 | * @param {Array} ids 用户ID列表 125 | * @param {Function} callback 回调函数 126 | */ 127 | exports.getUsersByIds = function (ids, callback) { 128 | User.find({_id: {"$in": ids}}, callback); 129 | }; 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /db/mongo.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var mongoose = require('mongoose'); 3 | 4 | var logger = require('../library/winstonlogger'); 5 | 6 | var mongodb_url = require("../config/config.js").mongodb_url; 7 | 8 | exports.connect = function() { 9 | //根据mongoose文档说autoIndex会影响性能 10 | mongoose.connect(mongodb_url, { config: { autoIndex: false }}); 11 | 12 | mongoose.connection.on('connected',function () { 13 | logger.debug("Mongodb API connected to: " + mongodb_url); 14 | }); 15 | 16 | mongoose.connection.on('error',function (err) { 17 | logger.debug('Mongoose API connection error: ' + err); 18 | }); 19 | 20 | mongoose.connection.on('disconnected', function () { 21 | logger.debug('Mongoose API connection disconnected'); 22 | }); 23 | }; 24 | 25 | exports.disconnect = function(callback) { 26 | mongoose.disconnect(callback); 27 | }; -------------------------------------------------------------------------------- /db/redis.js: -------------------------------------------------------------------------------- 1 | var redis_host = require("../config/config.js").redis_host; 2 | var redis_port = require("../config/config.js").redis_port; 3 | var redis_pwd = require("../config/config.js").redis_pwd; 4 | var redis = require('redis'); 5 | 6 | var logger = require("../library/winstonlogger"); 7 | 8 | 9 | var redisClient = 10 | redis.createClient({ 11 | host: redis_host 12 | ,port: redis_port 13 | ,password:redis_pwd 14 | ,detect_buffers: true 15 | }) 16 | .on('error', function (err) { 17 | logger.error(redis_host + ":" + redis_port + " " + err); 18 | }) 19 | .on('connect', function () { 20 | logger.debug('Redis connected ' + redis_host + ":" + redis_port); 21 | }); 22 | 23 | exports.redis = redis; 24 | exports.redisClient = redisClient; -------------------------------------------------------------------------------- /library/checkToken.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const jwt = require('jwt-simple'); 4 | const logger = require('./winstonlogger.js'); 5 | const config = require('../config/config.js'); 6 | const redisClient = require('../db/redis').redisClient; 7 | 8 | const message = require('../config/message.js'); 9 | 10 | var validateToken = function(req, res, next) { 11 | const token = req.headers.xtoken; 12 | const key = req.headers.xkey; //userID 13 | let decoded; 14 | return new Promise((onFulfilled, onRejected)=>{ 15 | 16 | if(token !== '' && token !== null && typeof token !== undefined && key !== undefined){ 17 | try{ 18 | //先对token解码 19 | decoded = jwt.decode(token, config.jwtTokenSecret); 20 | }catch(e){ 21 | res.json({statusCode: -1000, message: message.TOKEN_ERROR}); 22 | onRejected(e.message); 23 | } 24 | //检查token是否过期 25 | if(decoded.expire_time > (new Date).getTime()) { 26 | //从redis数据库中按key即userID获取数据 27 | redisClient.get(JSON.stringify(key), (err, redis_token) => { 28 | if(err){ 29 | res.json({statusCode: -1014, message: message.REDIS_ERROR}); 30 | onRejected('redis 数据库出错') 31 | }else{ 32 | onFulfilled(redis_token); 33 | } 34 | }); 35 | }else{ 36 | res.json({statusCode: -1001, message: message.TOKEN_EXPIRED}); 37 | onRejected('Token 过期'); 38 | } 39 | }else{ 40 | res.json({statusCode: -1000, message: message.TOKEN_ERROR}); 41 | onRejected('request headers 中Token为空或者参数不完整'); 42 | } 43 | }).then( (redis_token)=>{ 44 | //console.log('redis_token: ', redis_token); 45 | //对比客户端传过来的token以及存放在服务器的token 46 | if(redis_token === null){ 47 | res.json({statusCode: -1000, message: message.TOKEN_ERROR}); 48 | logger.info('Token为空'); 49 | }else if(token !== redis_token){ 50 | res.json({statusCode: -1000, message: message.TOKEN_ERROR}); 51 | logger.info('Token拒绝'); 52 | }else{ 53 | next(); 54 | } 55 | },(err_msg)=>{ 56 | if(err_msg){ 57 | logger.info(err_msg); 58 | } 59 | }) 60 | } 61 | 62 | exports.validateToken = validateToken; 63 | -------------------------------------------------------------------------------- /library/delToken.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const logger = require('./winstonlogger.js'); 4 | const config = require('../config/config.js'); 5 | const redisClient = require('../db/redis').redisClient; 6 | 7 | var delToken = function(userId, cb) { 8 | redisClient.del(JSON.stringify(userId), (err, reply)=>{ 9 | if(err){ 10 | cb(err); 11 | }else{ 12 | cb(null, reply); 13 | } 14 | }) 15 | } 16 | 17 | exports.delToken = delToken; 18 | 19 | /* example reply为1表示成功 0为失败 20 | delToken('keyName', (err, reply) => { 21 | if(err){ 22 | console.log(err); 23 | }else{ 24 | console.log(reply); 25 | } 26 | }) 27 | */ 28 | -------------------------------------------------------------------------------- /library/genToken.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const jwt = require('jwt-simple'); 4 | const logger = require('./winstonlogger.js'); 5 | const config = require('../config/config.js'); 6 | const redisClient = require('../db/redis').redisClient; 7 | 8 | var generToken = function(userId, cb) { 9 | let expire_time = (new Date).getTime() + config.token_expired_time; 10 | let token = jwt.encode({'expire_time': expire_time}, config.jwtTokenSecret); 11 | 12 | redisClient.set(JSON.stringify(userId), token, (err, reply) => { 13 | if(err){ 14 | logger.error('Token set failed'); 15 | cb(err); 16 | }else{ 17 | //logger.debug('Token set in Redis: ', reply.toString()); 18 | cb(null, token); 19 | } 20 | }) 21 | } 22 | 23 | /*example 24 | 25 | genToken('111', (err, token)=>{ 26 | if(err){ 27 | console.log(err); 28 | }else{ 29 | console.log(token); 30 | } 31 | }) 32 | 33 | */ 34 | 35 | 36 | exports.generToken = generToken; -------------------------------------------------------------------------------- /library/tools.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var schedule = require('node-schedule'); 3 | var PostDao = require('../dao/index').PostDao; 4 | var UserDao = require('../dao/index').UserDao; 5 | var https = require('http'); 6 | var querystring = require('querystring'); 7 | var redisClient = require('../db/redis').redisClient; 8 | var redis = require('../db/redis').redis; 9 | var multer = require('multer'); 10 | var fs = require('fs'); 11 | const message = require('../config/message.js'); 12 | const path = require('path'); 13 | var gm = require('gm'); 14 | var _ = require('underscore'); 15 | //贝叶斯平均计算最终评分,score为一个数组,先验值为3分,十个人评分 16 | function getFinalScore(scores){ 17 | var finalScore, 18 | totalScore = 0, 19 | finalScore = 0; 20 | var length = scores.length; 21 | scores.forEach(function(item,index){ 22 | if(item.isValidate == 1){ 23 | totalScore += item.score; 24 | } 25 | 26 | }) 27 | //var aveScore = totalScore / length; 28 | finalScore = (totalScore + 30)/(length+10); 29 | return finalScore.toFixed(1); 30 | } 31 | exports.getFinalScore = getFinalScore; 32 | //通过手机号查找用户 返回一个promise 主要是要来优化代码 33 | function pGetUserByPhone(phone){ 34 | return new Promise( (resolve,reject) => { 35 | UserDao.getUserByPhone(phone,function (err, user) { 36 | if(err){ 37 | //logger.debug('updatePass接口出错:' + err); 38 | reject(message.MONGODB_ERROR); 39 | } 40 | else if(!user){ 41 | reject(message.USER_NOT_EXIST); 42 | } 43 | else{ 44 | resolve(user); 45 | } 46 | }) 47 | 48 | }) 49 | } 50 | exports.pGetUserByPhone = pGetUserByPhone; 51 | 52 | //通过ID查找用户 返回一个promise 主要是要来优化代码 53 | function pGetUserById(userId){ 54 | return new Promise( (resolve,reject) => { 55 | UserDao.getUserById(userId,function (err, user) { 56 | if(err){ 57 | //logger.debug('updatePass接口出错:' + err); 58 | reject(message.MONGODB_ERROR); 59 | } 60 | else if(!user){ 61 | reject(message.USER_NOT_EXIST); 62 | } 63 | else{ 64 | resolve(user); 65 | } 66 | }) 67 | 68 | }) 69 | } 70 | exports.pGetUserById = pGetUserById; 71 | 72 | //通过ID查找帖子 返回一个promise 主要是要来优化代码 73 | function pGetPostById(postId){ 74 | return new Promise( (resolve,reject) => { 75 | PostDao.getPostById(postId,function (err, post) { 76 | if(err){ 77 | //logger.debug('updatePass接口出错:' + err); 78 | reject(message.MONGODB_ERROR); 79 | } 80 | else if(!post){ 81 | reject(message.POST_NOT_EXIST); 82 | } 83 | else{ 84 | resolve(post); 85 | } 86 | }) 87 | 88 | }) 89 | } 90 | exports.pGetPostById = pGetPostById; 91 | 92 | //图片文件格式过滤 93 | function fileFilter (req,file,cb){ 94 | var filename = file.originalname; 95 | var suffix = (filename.substring(filename.lastIndexOf('.'), filename.length)).toLowerCase(); 96 | if((suffix != '.jpg') && (suffix != '.gif') && (suffix != '.jpeg') && (suffix != '.png') && (suffix != '.bmp')) { 97 | //cb(null,false); 98 | cb(new Error('SUFFIX_ERROR')); 99 | } 100 | else{ 101 | cb(null,true); 102 | } 103 | } 104 | //上传图片配置,str为post,或者 avater,存放图片的路径 105 | function getOptions(str){ 106 | var storage = multer.diskStorage({ 107 | destination: function(req, file, cb){ 108 | //绝对路径存放图片 109 | if(str == 'avatar') 110 | cb(null,'C:/Users/301/Desktop/tbApi/public/avatar'); 111 | else if(str == 'post') 112 | cb(null,'C:/Users/301/Desktop/tbApi/public/images'); 113 | //默认是post 114 | else 115 | cb(null,'C:/Users/301/Desktop/tbApi/public/images'); 116 | }, 117 | filename:function (req,file,cb){ 118 | var filename = file.originalname; 119 | var suffix = (filename.substring(filename.lastIndexOf('.'), filename.length)).toLowerCase(); 120 | var filename = Date.now()+suffix;//文件名为时间戳+原文件名后缀 121 | return cb(null,filename); 122 | } 123 | }) 124 | var options = { 125 | storage: storage, 126 | fileFilter: fileFilter, 127 | limits: { 128 | fileSize : 2 * 1024 * 1024 //默认最大为2M 129 | } 130 | } 131 | return options; 132 | } 133 | exports.getOptions = getOptions; 134 | //上传多张图片接口,最多上传九张 135 | var uploadMulti = multer(getOptions('post')).array('postPics',9); 136 | var uploadMultiPics = function(req,res,cb){ 137 | uploadMulti(req,res,function(err){ 138 | if(err) { 139 | //logger.debug('上传多张图片接口出错:' + err); 140 | if(err.message == 'SUFFIX_ERROR') { 141 | cb({statusCode: -1026, message: message.FILE_TYPE_ERROR, result: ''}); 142 | } 143 | else if(err.message == 'File too large'){ 144 | cb({statusCode: -1027, message: message.FILE_SIZE_ERROR, result: ''}); 145 | } 146 | else if(err.message == 'Unexpected field'){ 147 | cb({statusCode: -1035, message: message.FILE_NAME_ERROR, result: ''}); 148 | } 149 | else{ 150 | cb({statusCode: -100, message: err.message, result: ''}); 151 | } 152 | 153 | } 154 | else{ 155 | if(req.files == undefined){ 156 | cb({statusCode: -100, message: "请使用formdata格式上传表单", result: ''}); 157 | } 158 | else if(req.files.length == 0){ 159 | req.body.pictures = []; 160 | cb(null,req.body); 161 | } 162 | else{ 163 | new Promise(function(resolve,reject){ 164 | var length = req.files.length; 165 | var cnt =0; 166 | req.files.forEach(function(photo,index){ 167 | gm(photo.path).size(function(err,value){ 168 | if(err||_.isEmpty(value)) 169 | { 170 | //删除图片 171 | req.files.forEach(function(photo,index){ 172 | fs.unlink(photo.path,function(err){ 173 | logger.debug('上传多张图片接口出错:' + err); 174 | }); 175 | }) 176 | reject({statusCode: -100, message: '获取尺寸出错', result: ''}); 177 | } 178 | else{ 179 | gm(photo.path).resize(value.width,value.height).write(photo.path,function(err){ 180 | if(err){ 181 | //删除图片 182 | req.files.forEach(function(photo,index){ 183 | fs.unlink(photo.path,function(err){ 184 | logger.debug('上传多张图片接口出错:' + err); 185 | }); 186 | }) 187 | reject({statusCode: -100, message: '图片压缩出错', result: ''}); 188 | } 189 | else{ 190 | ++cnt; 191 | if(cnt == length){ 192 | resolve(); 193 | } 194 | 195 | } 196 | 197 | 198 | }) 199 | 200 | 201 | } 202 | }) 203 | 204 | }) 205 | }) 206 | .then(function(){ 207 | var picsArray; 208 | var l = req.files.length; 209 | 210 | return new Promise(function(resolve,reject){ 211 | picsArray = req.files.map(function(photo,index){ 212 | return '/images/'+photo.filename; 213 | }) 214 | resolve(picsArray); 215 | }) 216 | }) 217 | .then(function(picsArray){ 218 | req.body.pictures = picsArray; 219 | cb(null,req.body); 220 | }) 221 | .catch(function(err){ 222 | logger.debug('上传多张图片接口出错:' + err); 223 | cb(err); 224 | }); 225 | } 226 | } 227 | }) 228 | } 229 | exports.uploadMultiPics = uploadMultiPics; 230 | 231 | function getRandomInt (length){ 232 | length = length || 4; 233 | if(length < 0 || length > 10){ 234 | length = 4; 235 | } 236 | 237 | let s = '0123456789'; 238 | let result = ''; 239 | 240 | for(let i = 0; i < length; i ++) { 241 | result += s[Math.floor(Math.random() * 10)]; 242 | } 243 | return result 244 | } 245 | exports.getRandomInt = getRandomInt; 246 | 247 | 248 | //发送验证码,参数为手机号 249 | function sendVerifyCode(type,phone,callback){ 250 | //默认是六位长度的验证码 251 | var verifycode = getRandomInt(6); 252 | 253 | var msg; 254 | if(type) 255 | msg = verifycode+'(XXXX验证码),请尽快完成验证。【XXXX】'; 256 | else 257 | msg = verifycode+'(奖品兑换码),请尽快来XXXXX兑换你的奖品。【XXXX】'; 258 | //console.log(msg); 259 | sendMsg(phone,msg,function(err,result){ 260 | //console.log(result); 261 | if(err) 262 | callback(err); 263 | else{ 264 | //console.log(result); 265 | result = JSON.parse(result); 266 | var msgStatus = {statusCode:result.error,message:result.msg,result:verifycode}; 267 | //如果状态码(result.error)为0,说明发送成功,否则状态码为负数,发送失败 268 | if(result.error==0){ 269 | redisClient.setex(phone,2*60,verifycode,function(err,res){ 270 | if(err) 271 | callback(err) 272 | else 273 | { 274 | callback(null,msgStatus); 275 | } 276 | }); 277 | } 278 | else { 279 | callback({statusCode:result.error,message:result.msg,result:''}) 280 | } 281 | } 282 | }) 283 | } 284 | exports.sendVerifyCode = sendVerifyCode; 285 | 286 | 287 | 288 | function sendMsg(phone , msg ,callback){ 289 | var postData = { 290 | mobile:phone, 291 | message:msg 292 | }; 293 | var content = querystring.stringify(postData); 294 | var options = { 295 | host:'sms-api.luosimao.com', 296 | path:'/v1/send.json', 297 | method:'POST', 298 | auth:'api:螺丝帽开发者key', 299 | agent:false, 300 | rejectUnauthorized : false, 301 | headers:{ 302 | 'Content-Type' : 'application/x-www-form-urlencoded', 303 | 'Content-Length' :content.length 304 | } 305 | }; 306 | var req = https.request(options,function(res){ 307 | var data = ''; 308 | res.setEncoding('utf8'); 309 | res.on('data', function (chunk) { 310 | data += chunk; 311 | }); 312 | res.on('end',function(){ 313 | callback(null, data); 314 | 315 | //console.log('data='+data+'send msg over'); 316 | }); 317 | res.on('error', function(err){ 318 | callback(err); 319 | }) 320 | }); 321 | //console.log(content); 322 | req.write(content); 323 | req.end(); 324 | } 325 | exports.sendMsg = sendMsg; 326 | 327 | function checkParams(paramsArray){ 328 | return new Promise((onFullfill,onReject) => { 329 | paramsArray.forEach(function(item){ 330 | if(_.isNull(item) || _.isUndefined(item) || (typeof(item)!='number' && _.isEmpty(item))) 331 | onReject(message.UNCOMPLETE_INPUT); 332 | }) 333 | onFullfill(); 334 | }) 335 | } 336 | exports.checkParams = checkParams; 337 | 338 | 339 | //定时任务 340 | var rule = new schedule.RecurrenceRule(); 341 | rule.dayOfWeek = [0, new schedule.Range(1, 6)]; 342 | rule.hour = 16; 343 | rule.minute = 9; 344 | 345 | schedule.scheduleJob(rule, function(){ 346 | new Promise(function(resolve, reject) { 347 | var date = new Date(); 348 | console.log(date); 349 | PostDao.getPostsByQuery({lock:0,'coinBank.lock':0,'coinBank.status':0,status:2,'coinBank.expDealTime':{$lt:date}},null,null,function (err,posts) { 350 | if(err){ 351 | reject(err); 352 | } 353 | //else if(posts.length==0){ 354 | //reject('没有帖子需要进行自动转账'); 355 | //} 356 | else{ 357 | reject("帖子"+posts); 358 | } 359 | }); 360 | }).catch(function (err) { 361 | console.log(err); 362 | }) 363 | 364 | }); 365 | 366 | -------------------------------------------------------------------------------- /library/winstonlogger.js: -------------------------------------------------------------------------------- 1 | var winston = require('winston'); 2 | 3 | /** 4 | * Winston logger config 5 | * 详细介绍见https://www.npmjs.com/package/winston 6 | * winston 是一个日志管理模块,它可以把数据打印在控制台 7 | * 文件或者是数据库中,也能够捕获异常,那么我们就可以根据 8 | * 日志对系统进行优化。 9 | */ 10 | winston.emitErrs = true; 11 | winston.stream({start:-1}); 12 | var logger = new winston.Logger({ 13 | transports: [ 14 | new winston.transports.File({ 15 | level: 'info', //level表示级别 error|0 warn|1 info|2 debug|4 16 | //数字越大级别越高,比如logger.error也会记录到warn info ,debug中去 17 | name: 'info-file', //传输的名字,可以根据名字来删除transports 18 | filename: '../logs/info-logs.log', 19 | json: false, 20 | colorize: true 21 | }), 22 | new winston.transports.File({ 23 | level: 'warn', 24 | name: 'warn-file', 25 | filename: '../logs/warn-logs.log', 26 | json: false, 27 | colorize: true 28 | }), 29 | new winston.transports.File({ 30 | level: 'error', 31 | name: 'error-file', 32 | filename: '../logs/error-logs.log', 33 | handleExceptions: true, 34 | timestamp:true, 35 | json: false, 36 | colorize: true 37 | }), 38 | new winston.transports.File({ 39 | level: 'debug', 40 | name: 'debug-file', 41 | filename: '../logs/debug-logs.log', 42 | timestamp:true, 43 | json: false, 44 | colorize: true 45 | }), 46 | new winston.transports.Console({ 47 | level: 'debug', 48 | handleExceptions: true, 49 | prettyPrint: true, 50 | json: false, 51 | colorize: true 52 | }) 53 | ], 54 | exitOnError: false 55 | }); 56 | 57 | module.exports = logger; -------------------------------------------------------------------------------- /model/item.js: -------------------------------------------------------------------------------- 1 | /* 2 | by ajay 2017/3/26 3 | 用于兑换物品 4 | */ 5 | var mongoose = require('mongoose'); 6 | var Schema = mongoose.Schema; 7 | 8 | var itemSchema = new Schema({ 9 | name: {type: String,required:true}, 10 | isDelete: {type: Boolean,default:false}, 11 | img: {type: String}, 12 | stock:{type:Number,default:0}, 13 | time_to_market:{type:Date,default:new Date()}, 14 | price:{type:Number,required:true} 15 | }); 16 | 17 | var itemModel = mongoose.model('items', itemSchema); 18 | 19 | module.exports = itemModel; -------------------------------------------------------------------------------- /model/post.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by MARDAN on 2016/7/8. 3 | */ 4 | // var users = require('../model/user'); 5 | var mongoose = require('mongoose'); 6 | var Schema = mongoose.Schema; 7 | 8 | var postSchema = new Schema({ 9 | topicType:{type:String, default : 1}, //1拿快递 2求撑伞 3求借东西 4二手闲置 5兼职信息 6活动组队 7食堂打包 8技术互助 9其他 0全部返回 10 | publisher :{type:String, required:true} , 11 | publisherInfo : {type:Schema.Types.ObjectId, ref:'users'} , //发布人(id) 12 | publisherName:{type:String, required:true} , 13 | publisherAvatar:{type:String} , // 14 | publisherScore:{type:Number,default:3} , 15 | lock : {type:String, default : 0} , //0未锁定|1锁定 16 | postType : {type:String, default : 0} , //type: 0 提供帮助 | 1 请求帮助 17 | title : {type:String, default : 0}, //标题 18 | content : {type:String, default : 0} , //内容 19 | scoreStatus:{type:String, default : 0}, //评分状态 0未评分|1发布人评分完毕|2参与人评分完毕|3双方评分完成 20 | expTime : {type:Date}, //报名截止时间(选填) 21 | status : {type:String, default : 0}, //状态 0 已发布未报名||1 已报名未确定任务人||2 进行中(确定了任务人)|| 3 已完成|| 4 已取消 ||5 评分中 ||6未审核 ||7审核未通过 22 | cancelReason:{type : String} , //审核未通过时的理由|任务人取消任务的理由 23 | participant :[ 24 | { 25 | selected: {type:String, default : 0} , //1 selected //参与者 26 | finalScore :Number, 27 | name:String, 28 | avatar:String , 29 | userId:String, 30 | partakeTime: Date, //参与时间 31 | status : {type:String, default : 0} //0 报名 | | 1进行中 | 2完成任务 | 3未成为任务人 | 4评分中 | 5帖子取消了 32 | } 33 | ], 34 | priority : {type:String, default : 5 }, // 优先级(用户 内容 时间)0-10 35 | favorUser: [ 36 | { 37 | userId:String, 38 | date : Date //收藏时间 39 | } 40 | ], 41 | favorCount : {type:Number, default : 0}, //收藏次数 42 | commentNum: {type:String, default : 0} , //评论数 43 | missionCoin : {type:String, default : 0}, //任务金币 44 | pubTime: {type:Date , default : Date.now()}, //发布时间 45 | contact:{type:String, default : 0}, //联系方式 46 | comment :[ 47 | { 48 | fromAvatar :String, //评论者头像 49 | fromId:String, //评论者_id 50 | fromName :String,//评论者昵称 51 | atId: String, //被@的人_id 52 | atName :String, //被@的人昵称 53 | content: String, //内容 54 | time: Date //时间 55 | }], 56 | coinBank: { 57 | lock : {type:String, default : 0} , //0未锁定|1锁定 58 | status: {type:String, default : 0}, // 0任务正在进行|1任务转账完毕|2任务被取消了 59 | fromId: String, //给钱方 60 | toId: String, //收钱方 61 | coin: {type: Number, default: 0}, //交易金币数 62 | date: Date, //交易完成日期 63 | expDealTime: Date //交易期望日期 64 | } , 65 | pictures:[], 66 | pubGradeLocked: {type:String, default : 0}, 67 | joinGradeLocked: {type:String, default: 0} 68 | 69 | }); 70 | //2017/2/23 by Ajay 71 | //添加索引 72 | postSchema.index({ 'priority':1,'pubTime':-1}); 73 | 74 | var postModel = mongoose.model('posts', postSchema); 75 | 76 | module.exports = postModel; 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | // var postSchema = new Schema({ 96 | // publisher : {type:String, required:true} , //发布人(id) 97 | // postType : {type:String, default : 0} , //type: 0 提供帮助 | 1 请求帮助 98 | // title : {type:String, default : 0}, //标题 99 | // content : {type:String, default : 0} , //内容 100 | // scoreStatus:{type:String, default : 0}, //评分状态 0未评分|1一方评分完毕|2双反评分完成 101 | // expTime : {type:Date, default : Date.now()}, //报名截止时间(选填) 102 | // status : {type:String, default : 0}, //状态 0 已发布未报名||1 已报名未确定任务人||2 进行中(确定了任务人)|| 3 已完成|| 4 已取消 103 | // participant :[ 104 | // { //参与者 105 | // userId:String, 106 | // partakeTime: Date, //参与时间 107 | // status : Number //0 报名 | | 1进行中 | 2完成任务 | 3取消 108 | // } 109 | // ], 110 | // priority : {type:String, default : 0}, // 优先级(用户 内容 时间)0-10 111 | // favorUser: [ 112 | // { 113 | // userId:String, 114 | // date : Date //收藏时间 115 | // } 116 | // ], 117 | // favorCount : {type:Number, default : 0}, //收藏次数 118 | // commentNum: {type:String, default : 0} , //评论数 119 | // missionCoin : {type:String, default : 0}, //任务金币 120 | // pubTime: {type:Date , default : Date.now}, //发布时间 121 | // contact:{type:String, default : 0}, //联系方式 122 | // comment :[ 123 | // { 124 | // fromId:String, //评论者_id 125 | // fromName :String,//评论者昵称 126 | // atId: String, //被@的人_id 127 | // atName :String, //被@的人昵称 128 | // content: String, //内容 129 | // time: Date //时间 130 | // }], 131 | // coinBank: { 132 | // status: String, // 0任务正在进行|1任务转账完毕|2任务被取消了 133 | // fromId: String, //给钱方 134 | // toId: String, //收钱方 135 | // coin: {type: Number, default: 0}, //交易金币数 136 | // date: Date //交易完成日期 137 | // } 138 | // }); 139 | 140 | // var postModel = mongoose.model('posts', postSchema); 141 | 142 | // module.exports = postModel; 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /model/stuInfo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ajay on 2016/12/28. 3 | */ 4 | var mongoose = require('mongoose'); 5 | var Schema = mongoose.Schema; 6 | 7 | 8 | 9 | var stuInfoSchema = new Schema({ 10 | stuName : { type:String , required:true }, //学生真实姓名 非空 11 | stuNum : { type:String , required:true }, //学号 12 | isSignup : { type:String , default:0 }, //0 未注册 | 1 已注册 13 | 14 | }); 15 | var stuInfoModel = mongoose.model('stuInfos', stuInfoSchema); 16 | exports.stuInfo = stuInfoModel; 17 | 18 | 19 | -------------------------------------------------------------------------------- /model/tip.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by MARDAN on 2016/7/26. 3 | */ 4 | var mongoose = require('mongoose'); 5 | var Schema = mongoose.Schema; 6 | 7 | var tipSchema = new Schema({ 8 | handled:{type:String, default : 0} , // 0是未处理,1是已处理,默认未处理 9 | fromName : String, //被举报人名字 10 | toName: String, 11 | postId :String , //被举报的帖子 12 | fromId : String , //举报方 13 | toId :String, //被举报方 14 | tipReason : String, //举报内容 15 | tipDate: Date //举报的时间 16 | }); 17 | 18 | var tipModel = mongoose.model('tips',tipSchema); 19 | module.exports = tipModel; 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | // var tipSchema = new Schema({ 32 | // isHandle:{type:String, default : 0} , // 0是未处理,1是已处理,默认未处理 33 | // stuName : String, //被举报人名字 34 | // postId :String , //被举报的帖子 35 | // fromId : String , //举报方 36 | // toId :String, //被举报方 37 | // tipReason : String, //举报内容 38 | // tipDate: Date //举报的时间 39 | // }); 40 | 41 | // var tipModel = mongoose.model('tips',tipSchema); 42 | // module.exports = tipModel; -------------------------------------------------------------------------------- /model/trade.js: -------------------------------------------------------------------------------- 1 | /* 2 | by ajay 2017/3/26 3 | 用于记录交易 4 | */ 5 | var mongoose = require('mongoose'); 6 | var Schema = mongoose.Schema; 7 | 8 | var tradeSchema = new Schema({ 9 | userId: {type:String, required:true},//兑换者ID 10 | userName: {type: String,required:true},//兑换商品的同学的名称 11 | itemId:{type:String, required:true},//兑换商品ID 12 | itemName:{type:String, required:true},//商品名 13 | numberOfItem:{type:Number,required:true},//商品数量 14 | isDeal: {type: Boolean,default:false},//是否已处理 15 | dealTime:{type:Date,default:new Date()}, 16 | exchangeCode:{type:Number,required:true} 17 | }); 18 | 19 | var tradeModel = mongoose.model('trades', tradeSchema); 20 | 21 | module.exports = tradeModel; -------------------------------------------------------------------------------- /model/user.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by MARDAN on 2016/7/8. 3 | */ 4 | var mongoose = require('mongoose'); 5 | var Schema = mongoose.Schema; 6 | 7 | 8 | 9 | var userSchema = new Schema({ 10 | //socket :{}, 11 | registerTime:{ type:String , required:true }, //注册时间 12 | stuName : { type:String , required:true }, //姓名非空 13 | phone : { type:String , required:true }, //长号 14 | password : { type:String , required:true }, //密码 15 | phone_short : { type:String , default : 0 }, //短号 16 | wechat : { type:String , default : 0 }, //微信号 17 | qq : { type:String , default : 0 }, //qq 18 | frozen : { type:String , default :1 }, //0 冻结 | 1 未冻结 19 | stuNum : { type:String , default : 0 }, //学号 20 | sex : { type:String , default : 0 }, //性别 0 男| 1 女 21 | avatar : { type:String , default : 0 }, //头像 22 | skills : { type:String , default : 0 }, //特长 23 | favorCount : { type:Number, default:0}, //收藏帖子数 24 | pubCount :{ type:Number, default:0}, //发布帖子数 25 | joinCount :{ type:Number, default:0}, //参与的帖子数 26 | lastLoginTime: { type:Date , default:new Date()}, 27 | coin : { type:Number, default:30}, //金币默认值为30 28 | scores : [ //评分 29 | { 30 | isValidate : { type:String , default:1 } , //0无效|1默认有效 31 | postId : { type:String , required:true }, //来自哪个帖子的评分 32 | fromUser : { type:String , required:true }, //(_id) 33 | score : { type:Number , default:3 }, //(0-5 0.5间隔) 34 | time : { type:Date , default:new Date()} 35 | } 36 | ], 37 | finalScore :{ type:Number , default : 3 },//最终评分,根据贝叶斯平均计算 38 | check:{ //签到信息 39 | checkDate:[], 40 | lastDate:Date, 41 | checkLog : { type:Number , default:0 } 42 | }, 43 | message : [ //信息 44 | { 45 | date :Date, //信息时间 46 | messageType: String , 47 | // 0 帖子回复 | 48 | // 1 帖子报名成功 | 49 | // 2 你已报名帖子 | 50 | // 3 你的帖子被报名 | 51 | // 4 帖子对方已转入时间币 | 52 | // 5 帖子对方评分尽快完成任务 | 53 | // 6 帖子被举报 | 54 | // 7 帖子被锁定 | 55 | // 8 帖子被解mess锁 | 56 | // 9 帖子时间币被锁定 | 57 | // 10 帖子时间币被解锁 | 58 | // 11 帖子交易评分被锁定 | 59 | // 12 帖子交易评分被解锁 | 60 | // 13 你账号被锁定 | 61 | // 14 你账号被解锁 62 | // 15 你被谁@了 63 | // 16 你没有被选为任务人 64 | // 17 帖子被取消了 65 | read: { type:String , default:0 } , //0 未读 | 1 已读 66 | content :{ 67 | userId :String , //信息触发者id 68 | postId :String, //帖子id 69 | userStuName :String , //信息触发者姓名 70 | postTitle :String //帖子标题 71 | } 72 | } 73 | ] 74 | }); 75 | var userModel = mongoose.model('users', userSchema); 76 | 77 | exports.user = userModel; 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | // var userSchema = new Schema({ 103 | // nickName : { type:String}, //昵称 104 | // stuName : { type:String , required:true }, //姓名非空 105 | // phone : { type:String , required:true }, //长号 106 | // password : { type:String , required:true }, //密码 107 | // phone_short : { type:String , default : 0 }, //短号 108 | // weChat : { type:String , default : 0 }, //微信号 109 | // qq : { type:String , default : 0 }, //qq 110 | // frozen : { type:String , default :1 }, //0 冻结 | 1 未冻结 111 | // stuNum : { type:String , default : 0 }, //学号 112 | // sex : { type:String , default : 0 }, //性别 113 | // avatar : { type:String , default : 0 }, //头像 114 | // skills : { type:String , default : 0 }, //特长 115 | // coin : { type:Number, default:30}, //金币默认值为30 116 | // scores : [ //评分 117 | // { 118 | // postId :{ type:String , required:true }, //来自哪个帖子的评分 119 | // fromUser : { type:String , required:true }, //(_id) 120 | // score : { type:Number , default:0 }, //(0-5 0.5间隔) 121 | // time : { type:Date , default:new Date()} 122 | // } 123 | // ], 124 | 125 | // check:{ //签到信息 126 | // checkDate:[], 127 | // lastDate:Date, 128 | // checkLog : { type:Number , default:0 } 129 | // }, 130 | // message : [ //信息 131 | // { 132 | // messageType: String , //0帖子回复 1管理员私信 2报名 3完成任务 4成为任务人 5时间币到账 133 | // read: String , //0 未读 | 1 已读 134 | // content :{ 135 | // fromId :String , //信息触发者id 136 | // postId :String, //帖子id 137 | // missionCoin: Number, //任务金币 138 | // content : String, //信息内容 139 | // date :Date, //信息时间 140 | // expTime : Date //任务截止时间 141 | // } 142 | // } 143 | // ] 144 | // }); 145 | // var userModel = mongoose.model('users', userSchema); 146 | 147 | // exports.user = userModel; 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /model/userActionLogs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by MARDAN on 2016/7/10. 3 | */ 4 | var mongoose = require('mongoose'); 5 | var Schema = mongoose.Schema; 6 | 7 | var userActionSchema = new Schema ({ 8 | user_id : String, 9 | user_ip : String, 10 | actionDate : Date 11 | }); 12 | 13 | var userActionModel = mongoose.model('user_Action_Log',userActionSchema); 14 | 15 | exports.userActionlog = userActionModel; 16 | 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tbApi", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "body-parser": "~1.13.2", 10 | "cookie-parser": "~1.3.5", 11 | "debug": "~2.2.0", 12 | "express": "~4.13.1", 13 | "express-limiter": "^1.6.0", 14 | "jade": "~1.11.0", 15 | "jwt-simple": "^0.5.0", 16 | "moment": "^2.14.1", 17 | "mongoose": "^4.5.4", 18 | "morgan": "~1.6.1", 19 | "multer": "^1.1.0", 20 | "redis": "^2.6.2", 21 | "rotating-file-stream": "^1.1.9", 22 | "serve-favicon": "~2.3.0", 23 | "winston": "^2.2.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pictures/微信图片_20170523161807.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Roujack/LiBond/a5a003a3b0e79d6d115f56733fa7d7175805103a/pictures/微信图片_20170523161807.jpg -------------------------------------------------------------------------------- /pictures/微信图片_20170523161817.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Roujack/LiBond/a5a003a3b0e79d6d115f56733fa7d7175805103a/pictures/微信图片_20170523161817.jpg -------------------------------------------------------------------------------- /pictures/微信图片_20170523161821.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Roujack/LiBond/a5a003a3b0e79d6d115f56733fa7d7175805103a/pictures/微信图片_20170523161821.jpg -------------------------------------------------------------------------------- /pictures/微信图片_20170523161826.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Roujack/LiBond/a5a003a3b0e79d6d115f56733fa7d7175805103a/pictures/微信图片_20170523161826.jpg -------------------------------------------------------------------------------- /pictures/微信图片_20170523161831.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Roujack/LiBond/a5a003a3b0e79d6d115f56733fa7d7175805103a/pictures/微信图片_20170523161831.jpg -------------------------------------------------------------------------------- /pictures/微信图片_20170523161837.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Roujack/LiBond/a5a003a3b0e79d6d115f56733fa7d7175805103a/pictures/微信图片_20170523161837.jpg -------------------------------------------------------------------------------- /pictures/微信图片_20170523161843.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Roujack/LiBond/a5a003a3b0e79d6d115f56733fa7d7175805103a/pictures/微信图片_20170523161843.jpg -------------------------------------------------------------------------------- /pictures/微信图片_20170523161854.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Roujack/LiBond/a5a003a3b0e79d6d115f56733fa7d7175805103a/pictures/微信图片_20170523161854.jpg -------------------------------------------------------------------------------- /pictures/微信图片_20170523161858.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Roujack/LiBond/a5a003a3b0e79d6d115f56733fa7d7175805103a/pictures/微信图片_20170523161858.jpg -------------------------------------------------------------------------------- /pictures/微信图片_20170523161908.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Roujack/LiBond/a5a003a3b0e79d6d115f56733fa7d7175805103a/pictures/微信图片_20170523161908.jpg -------------------------------------------------------------------------------- /pictures/微信图片_20170523161912.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Roujack/LiBond/a5a003a3b0e79d6d115f56733fa7d7175805103a/pictures/微信图片_20170523161912.jpg -------------------------------------------------------------------------------- /routes/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | > -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var express = require('express'); 4 | var router = express.Router(); 5 | 6 | 7 | const User = require('../controller/user.js'); 8 | const Post = require('../controller/post.js'); 9 | const Application = require('../controller/application.js'); 10 | //用户模块 11 | router.post('/user/insertStu', User.insertStu); 12 | router.post('/user/verifyStuNum', User.verifyStuNum); 13 | router.post('/user/signup', User.signup); 14 | router.post('/user/login', User.login); 15 | router.post('/user/logout', User.logout); 16 | router.post('/user/getVerCode', User.getVerCode); 17 | router.post('/user/getMyInfo', User.getMyInfo); 18 | router.post('/user/update', User.update); 19 | router.post('/user/updatePass', User.updatePass); 20 | router.post('/user/avatar', User.avatar); 21 | router.post('/user/getInfo', User.getInfo); 22 | router.post('/user/myPubPosts', User.myPubPosts); 23 | router.post('/user/myJoinPosts', User.myJoinPosts); 24 | router.post('/user/myFavoPosts', User.myFavoPosts); 25 | router.post('/user/checkin', User.checkin); 26 | router.post('/user/rank', User.rank); 27 | router.post('/user/grade', User.grade); 28 | router.post('/user/getMsg', User.getMsg); 29 | router.post('/user/markRead', User.markRead); 30 | router.post('/user/multi', User.multi); 31 | router.post('/user/getScoreStatus', User.getEvaluateStatus); 32 | router.post('/user/getDefaultAvatar', User.getDefaultAvatar); 33 | //router.post('/user/insertMsg', User.insertMsg); 34 | router.post('/search', User.search); 35 | router.post('/getURL', User.getURL); 36 | router.post('/user/buy', User.buy); 37 | router.post('/getItems', User.getItems); 38 | router.post('/insertRegister',Application.insertRegister); 39 | router.post('/exportToExcel',Application.exportToExcel); 40 | router.post('/register/getAll',Application.getAll); 41 | //router.post('/user/myUnpassPosts', User.myUnpassPosts); 42 | 43 | //帖子模块 44 | router.post('/post/favorCancel',Post.favorCancel); 45 | router.post('/post/getAll', Post.getAll); 46 | router.post('/post/getPost', Post.getPost); 47 | router.post('/post/favo', Post.favo); 48 | router.post('/post/publish', Post.publish); 49 | router.post('/post/register', Post.register); 50 | router.post('/post/assign', Post.assign); 51 | router.post('/post/cancel', Post.cancel); 52 | router.post('/post/confirm', Post.confirm); 53 | router.post('/post/comment', Post.comment); 54 | router.post('/post/tipoff', Post.tipoff); 55 | router.post('/post/getReason', Post.getReason); 56 | 57 | module.exports = router; -------------------------------------------------------------------------------- /views/error.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} 6 | -------------------------------------------------------------------------------- /views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content 8 | --------------------------------------------------------------------------------