Commit b304f3b0 authored by 杨翌文's avatar 杨翌文

项目初始化

parents
{
"directory": "public/components",
"json": "bower.json"
}
node_modules/
public/components
.sass-cache
\ No newline at end of file
'use strict';
var request = require('request');
module.exports = function (grunt) {
// show elapsed time at the end
require('time-grunt')(grunt);
// load all grunt tasks
require('load-grunt-tasks')(grunt);
var reloadPort = 35729, files;
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
develop: {
server: {
file: 'app.js'
}
},
watch: {
options: {
nospawn: true,
livereload: reloadPort
},
js: {
files: [
'app.js',
'app/**/*.js',
'config/*.js'
],
tasks: ['develop', 'delayed-livereload']
},
css: {
files: [
'public/css/*.css'
],
options: {
livereload: reloadPort
}
},
views: {
files: [
'app/views/*.swig',
'app/views/**/*.swig'
],
options: { livereload: reloadPort }
}
}
});
grunt.config.requires('watch.js.files');
files = grunt.config('watch.js.files');
files = grunt.file.expand(files);
grunt.registerTask('delayed-livereload', 'Live reload after the node server has restarted.', function () {
var done = this.async();
setTimeout(function () {
request.get('http://localhost:' + reloadPort + '/changed?files=' + files.join(','), function(err, res) {
var reloaded = !err && res.statusCode === 200;
if (reloaded)
grunt.log.ok('Delayed live reload successful.');
else
grunt.log.error('Unable to make a delayed live reload.');
done(reloaded);
});
}, 500);
});
grunt.registerTask('default', [
'develop',
'watch'
]);
};
var express = require('express'),
config = require('./config/config'),
glob = require('glob'),
mongoose = require('mongoose');
var app = express();
//链接数据库
var options = {
db: {
native_parser: true
},
server: {
poolSize: config.mongodb.poolSize
},
user: config.mongodb.username,
pass: config.mongodb.password
};
if (config.mongodb.hasOwnProperty('replset')) {
options.replset = {
rs_name: config.mongodb.replset
};
}
var mongodb = mongoose.connect(config.mongodb.uri, options, function(err) {
if (err) {
console.log('error:' + err);
}
});
//遍历数据模型定义
var mongoModels = glob.sync(config.root + '/app/models/*.js');
mongoModels.forEach(function(model) {
require(model);
});
//设置全局mongodb的数据源
global.mongodb = mongodb;
require('./config/express')(app, config);
app.listen(config.port);
\ No newline at end of file
'use strict';
var express = require('express'),
router = express.Router(),
returnCode = require('../utils/returnCode'),
_ = require('lodash');
module.exports = function(app) {
app.use('/member', router);
};
//新增会员信息
router.post('/info/create', function(req, res, next) {
var rs = {};
dataSource.Member.findOne({
where: {
uid: req.body.uid,
ent_code: Number(req.body.ent_code)
}
}).then(function(member) {
if (member) {
res.json(returnCode.UNIQUE_DATA_EXITS);
} else {
dataSource.Member.create(req.body).then(function(member) {
rs = _.assign(member, returnCode.SUCCESS);
res.json(rs);
}, function(err) {
console.error(err);
res.json(returnCode.BUSY);
});
}
}, function(err) {
console.error(err);
res.json(returnCode.BUSY);
});
});
//获取目标会员信息
router.get('/info/get/:mid', function(req, res, next) {
var mid = req.params.mid || null;
var rs = {};
if (mid) {
dataSource.Member.findOne({
where: {
id: Number(mid)
}
}).then(function(member) {
if (member) {
rs = _.assign(rs, returnCode.SUCCESS);
rs.data = member;
} else {
rs = _.assign(rs, returnCode.DATA_NOTEXITS);
}
res.json(rs);
}, function(err) {
console.error(err);
res.json(returnCode.BUSY);
});
} else {
res.json(returnCode.WRONG_PARAM);
}
});
//更新目标会员信息
router.post('/info/set/:mid', function(req, res, next) {
var mid = req.params.mid || null;
if (mid && !_.isEmpty(req.body)) {
if (req.body.uid || req.body.ent_code || req.body.id || req.body.rank_code) {
res.json(returnCode.UPDATE_READONLY_ATTR);
return;
}
dataSource.Member.update(req.body, {
where: {
id: Number(mid)
},
limit: 1,
}).then(function(rowCount) {
if (1 === rowCount[0]) {
res.json(returnCode.SUCCESS);
} else {
res.json(returnCode.DATA_NOTEXITS);
}
}, function(err) {
console.error(err);
res.json(returnCode.BUSY);
});
} else {
res.json(returnCode.WRONG_PARAM);
}
});
//更新目标会员信息并返回最新的会员数据
router.post('/info/touch/:mid', function(req, res, next) {
var mid = req.params.mid || null;
mid = Number(mid);
var rs = {};
if (mid && !_.isEmpty(req.body)) {
if (req.body.uid || req.body.ent_code || req.body.id || req.body.rank_code) {
res.json(returnCode.UPDATE_READONLY_ATTR);
return;
}
dataSource.Member.update(req.body, {
where: {
id: mid
},
limit: 1,
}).then(function(rowCount) {
if (1 === rowCount[0]) {
dataSource.Member.findOne({
where: {
id: mid
}
}).then(function(member) {
rs.data = member;
rs = _.assign(rs, returnCode.SUCCESS);
res.json(rs);
}, function(err) {
console.error(err);
res.json(returnCode.BUSY);
});
} else {
res.json(returnCode.DATA_NOTEXITS);
}
}, function(err) {
console.error(err);
res.json(returnCode.BUSY);
});
} else {
res.json(returnCode.WRONG_PARAM);
}
});
//----------------后台管理专属接口---------------------------
//查询目标企业会员列表
router.post('/info/ent/:ent_code', function(req, res, next) {
var pageNo = req.query.pageNo || 1;
var pageSize = req.query.pageSize || 10;
var where = req.body.where || {};
var order = req.body.order || 'id';
var rs = {};
var offset = (pageNo - 1) * pageSize;
where.ent_code = Number(req.params.ent_code);
dataSource.Member.findAndCountAll({
where: where,
order: order,
limit: pageSize,
offset: offset
}).then(function(result) {
if (result.count > 0) {
rs.data = {
pageNo: pageNo,
pageSize: pageSize,
total: result.count,
items: result.rows
};
} else {
rs.data = {
pageNo: pageNo,
pageSize: pageSize,
total: 0,
items: []
};
}
rs = _.assign(rs, returnCode.SUCCESS);
res.json(rs);
}, function(err) {
console.error(err);
res.json(returnCode.BUSY);
});
});
\ No newline at end of file
'use strict';
var express = require('express'),
router = express.Router(),
async = require('async'),
returnCode = require('../utils/returnCode'),
_ = require('lodash');
module.exports = function(app) {
app.use('/member', router);
};
//获取目标会员积分
router.get('/integral/get/:mid', function(req, res, next) {
var mid = req.params.mid || null;
var rs = {};
mid = Number(mid);
if (mid) {
dataSource.Integral.findOne({
where: {
mid: mid
}
}).then(function(integral) {
if (integral) {
rs.data = {
mid: integral.mid,
integral: integral.integral,
exp: integral.exp
};
res.json(_.assign(rs, returnCode.SUCCESS));
} else {
dataSource.Member.findOne({
where: {
id: mid
}
}).then(function(member) {
if (member) {
rs.data = {
mid: mid,
integral: 0,
exp: 0
};
res.json(_.assign(rs, returnCode.SUCCESS));
dataSource.Integral.create({
mid: mid,
integral: 0,
exp: 0
});
} else {
res.json(returnCode.DATA_NOTEXITS);
}
}, function(err) {
console.error(err);
res.json(returnCode.BUSY);
});
}
}, function(err) {
console.error(err);
res.json(returnCode.BUSY);
});
} else {
res.json(returnCode.WRONG_PARAM);
}
});
//增加目标会员积分
router.post('/integral/incr/:mid', function(req, res, next) {
var mid = req.params.mid || null;
var incr = req.body;
var rs = {};
mid = Number(mid);
var amount = Number(incr.amount);
async.waterfall([function(cb) { //查找积分
dataSource.Integral.findOne({
where: {
id: mid
},
include: [{
model: dataSource.Member
}]
}).then(function(integral) {
if (integral) {
cb(null, integral);
} else {
cb(returnCode.DATA_NOTEXITS);
}
}, function(err) {
console.error(err);
cb(returnCode.BUSY);
});
}, function(integral, cb) { //更新积分和经验
integral.increment(['integral', 'exp'], {
by: amount
}).then(function() {
cb(null, integral);
}, function(err) {
console.error(err);
cb(returnCode.BUSY);
});
}, function(integral, cb) { //插入积分历史
dataSource.IntegralHistory.create({
mid: mid,
amount: amount,
ent_code: integral.Member.ent_code,
change_type: 1,
change_reason: incr.change_reason
}).then(function() {
cb(null, integral);
}, function(err) {
console.error(err);
cb(returnCode.BUSY);
});
}, function(integral, cb) { //重载积分
integral.reload().then(function(newIns) {
cb(null, newIns);
}, function(err) {
console.error(err);
cb(returnCode.BUSY);
});
}], function(err, result) {
if (err) {
res.json(err);
} else {
rs.data = {
mid: result.mid,
integral: result.integral,
exp: result.exp
}
rs = _.assign(rs, returnCode.SUCCESS);
res.json(rs);
}
});
});
//减少目标会员积分
router.post('/integral/decr/:mid', function(req, res, next) {
var mid = req.params.mid || null;
var decr = req.body;
var rs = {};
mid = Number(mid);
var amount = Number(decr.amount);
async.waterfall([function(cb) { //查找积分
dataSource.Integral.findOne({
where: {
id: mid
},
include: [{
model: dataSource.Member
}]
}).then(function(integral) {
console.log(integral);
if (integral) {
cb(null, integral);
} else {
cb(returnCode.DATA_NOTEXITS);
}
}, function(err) {
console.error(err);
cb(returnCode.BUSY);
});
}, function(integral, cb) { //插入积分历史
dataSource.IntegralHistory.create({
mid: mid,
amount: amount,
ent_code: integral.Member.ent_code,
change_type: 2,
change_reason: decr.change_reason
}).then(function() {
cb(null, integral);
}, function(err) {
console.error(err);
cb(returnCode.BUSY);
});
}, function(integral, cb) { //更新积分和经验
if (integral.integral - amount >= 0) {
integral.decrement('integral', {
by: amount
}).then(function() {
cb(null, integral);
}, function(err) {
console.error(err);
cb(returnCode.BUSY);
});
} else {
cb(returnCode.INTEGRAL_NOT_ENOUGH);
}
}, function(integral, cb) { //重载积分
integral.reload().then(function(newIns) {
cb(null, newIns);
}, function(err) {
console.error(err);
cb(returnCode.BUSY);
});
}], function(err, result) {
if (err) {
res.json(err);
} else {
rs.data = {
mid: result.mid,
integral: result.integral,
exp: result.exp
}
rs = _.assign(rs, returnCode.SUCCESS);
res.json(rs);
}
});
});
//查询目标会员积分历史
router.post('/integral/history/:mid', function(req, res, next) {
var pageNo = req.query.pageNo || 1;
var pageSize = req.query.pageSize || 10;
var where = req.body.where || {};
var order = req.body.order || 'id desc';
var rs = {};
var offset = (pageNo - 1) * pageSize;
where.mid = Number(req.params.mid);
dataSource.IntegralHistory.findAndCountAll({
where: where,
order: order,
limit: pageSize,
offset: offset,
include: [{
model: dataSource.Member,
attributes: ['name', 'sex', 'mobile', 'uid']
}]
}).then(function(result) {
if (result.count > 0) {
rs.data = {
pageNo: pageNo,
pageSize: pageSize,
total: result.count,
items: result.rows
};
} else {
rs.data = {
pageNo: pageNo,
pageSize: pageSize,
total: 0,
items: []
};
}
rs = _.assign(rs, returnCode.SUCCESS);
res.json(rs);
}, function(err) {
console.error(err);
res.json(returnCode.BUSY);
});
});
//----------------后台管理专属接口---------------------------
//查询目标企业会员信息和积分列表
router.post('/integral/ent/:ent_code', function(req, res, next) {
var pageNo = req.query.pageNo || 1;
var pageSize = req.query.pageSize || 10;
var where = req.body.where || {};
var order = req.body.order || 'id desc';
var rs = {};
var offset = (pageNo - 1) * pageSize;
where.ent_code = Number(req.params.ent_code);
dataSource.IntegralHistory.findAndCountAll({
where: where,
order: order,
limit: pageSize,
offset: offset,
include: [{
model: dataSource.Member,
attributes: ['name', 'sex', 'mobile', 'uid']
}]
}).then(function(result) {
if (result.count > 0) {
rs.data = {
pageNo: pageNo,
pageSize: pageSize,
total: result.count,
items: result.rows
};
} else {
rs.data = {
pageNo: pageNo,
pageSize: pageSize,
total: 0,
items: []
};
}
rs = _.assign(rs, returnCode.SUCCESS);
res.json(rs);
}, function(err) {
console.error(err);
res.json(returnCode.BUSY);
});
});
\ No newline at end of file
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
//论坛访问控制,基于角色
var ForumAccessControlSchema = new Schema({
ent_code: {
type: Number,
require: true,
index: true
},
role: { //角色
type: Schema.Types.ObjectId,
require: true,
index: true,
ref: 'ForumRole'
},
status: { //行为状态1,允许,0拒绝
type: Number,
require: true,
default: 1
}
}, {
'collection': 'pisns_forum_access_control'
});
module.exports = mongoose.model('ForumAccessControl', ForumAccessControlSchema);
\ No newline at end of file
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
//话题评论
var ForumCommentSchema = new Schema({
ent_code: {
type: Number,
require: true,
index: true
},
from: { //评论人
type: Schema.Types.ObjectId,
require: true,
index: true,
ref: 'ForumUser'
},
to: { //回复人
type: Schema.Types.ObjectId,
require: true,
index: true,
ref: 'ForumUser'
},
comments: { //评论的评论
type.Array
},
content: { //评论内容
type: String,
require: true
},
ip: { //IP地址
type: String,
require: true
},
created: { //评论时间
type: Date,
require: true,
default: Date.now
}
}, {
'collection': 'pisns_forum_comment'
});
module.exports = mongoose.model('ForumComment', ForumCommentSchema);
\ No newline at end of file
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
//用户收藏
var ForumFavoriteSchema = new Schema({
ent_code: {
type: Number,
require: true,
index: true
},
user: { //收藏用户
type: Schema.Types.ObjectId,
require: true,
index: true,
ref: 'ForumUser'
},
title: { //收藏内容标题
type: String,
require: true
},
url: { //收藏链接地址
type: String,
require: true
}
created: { //收藏时间
type: Date,
require: true,
default: Date.now
}
}, {
'collection': 'pisns_forum_favorite'
});
module.exports = mongoose.model('ForumFavorite', ForumFavoriteSchema);
\ No newline at end of file
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
//论坛分类定义
var ForumGroupSchema = new Schema({
ent_code: {
type: Number,
require: true,
index: true
},
name: { //分类名称
type: String,
require: true
},
icon: { //分类图标
type: String,
require: true
},
order_idx: { //分类排序
type: Number,
require: true,
default: 0
},
status: { //分类状态,1启用,0禁用
type: Number,
require: true,
default: 1
}
}, {
'collection': 'pisns_forum_group'
});
module.exports = mongoose.model('ForumGroup', ForumGroupSchema);
\ No newline at end of file
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
//话题广场,板块
var ForumInfoSchema = new Schema({
ent_code: {
type: Number,
require: true,
index: true
},
group: {
type: Schema.Types.ObjectId,
require: true,
index: true,
ref: 'ForumGroup'
},
name: { //论坛名称
type: String,
require: true
},
description: { //论坛简介
type: String,
require: true
},
icon: { //论坛图标
type: String,
require: true
},
order_idx: { //论坛排序
type: Number,
require: true,
default: 0
},
pv_count: { //论坛访问量
type: Number,
require: true,
default: 0
},
status: { //论坛状态,1启用,0禁用
type: Number,
require: true,
default: 1
}
}, {
'collection': 'pisns_forum_info'
});
module.exports = mongoose.model('ForumInfo', ForumInfoSchema);
\ No newline at end of file
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
//点赞日志
var ForumPraiseLogSchema = new Schema({
ent_code: {
type: Number,
require: true,
index: true
},
user: { //点赞者
type: Schema.Types.ObjectId,
require: true,
index: true,
ref: 'ForumUser'
},
thread: { //点赞话题
type: Schema.Types.ObjectId,
require: true,
index: true,
ref: 'ForumThread'
},
ip: { //IP地址
type: String,
require: true
},
created: { //点赞时间
type: Date,
require: true,
default: Date.now
}
}, {
'collection': 'pisns_forum_praise_log'
});
module.exports = mongoose.model('ForumPraiseLog', ForumPraiseLogSchema);
\ No newline at end of file
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
//论坛角色,行为控制
var ForumRoleSchema = new Schema({
ent_code: {
type: Number,
require: true,
index: true
},
title: { //角色名称
type: String,
require: true
},
status: { //角色状态1,正常,0禁用
type: Number,
require: true,
default: 1
}
}, {
'collection': 'pisns_forum_role'
});
module.exports = mongoose.model('ForumRole', ForumRoleSchema);
\ No newline at end of file
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
//分享日志
var ForumShareLogSchema = new Schema({
ent_code: {
type: Number,
require: true,
index: true
},
user: { //分享者
type: Schema.Types.ObjectId,
require: true,
index: true,
ref: 'ForumUser'
},
thread: { //分享内容
type: Schema.Types.ObjectId,
require: true,
index: true,
ref: 'ForumThread'
},
destination:{ //分享的目标,微信好友,微信朋友圈,QQ空间,微博等等
type: String,
require: true,
index:true
},
created: { //分享时间
type: Date,
require: true,
default: Date.now
}
}, {
'collection': 'pisns_forum_share_log'
});
module.exports = mongoose.model('ForumShareLog', ForumShareLogSchema);
\ No newline at end of file
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
//话题标签,标签分类
var ForumTagSchema = new Schema({
ent_code: {
type: Number,
require: true,
index: true
},
title: { //标签标题
type: String,
require: true,
},
icon: { //标签图片
type: String
},
pv_count: { //访问量
type: Number,
require: true,
default: 0
},
order_idx: { //标签排序
type: Number,
require: true,
default: 0
},
status: { //标签状态,1启用,0禁用
type: Number,
require: true,
default: 1
}
}, {
'collection': 'pisns_forum_tag'
});
module.exports = mongoose.model('ForumTag', ForumTagSchema);
\ No newline at end of file
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
//话题,文章
var ForumThreadSchema = new Schema({
ent_code: {
type: Number,
require: true,
index: true
},
forum: {
type: Schema.Types.ObjectId,
require: true,
index: true,
ref: 'Forum'
},
title: { //话题标题
type: String,
require: true
},
content: { //话题内容
type: String,
require: true
},
icon: { //话题图标
type: String,
require: true
},
order_idx: { //论坛排序
type: Number,
require: true,
default: 0
},
top: { //话题是否置顶0否,1是
type: Number,
require: true,
default: 0
},
tag: { //话题归属标签
type: Array
},
comments: { //评论内容列表
type: Array
},
pv_count: { //话题的访问量
type: Number,
require: true,
default: 0
},
comment_count: { //评论数量
type: Number,
require: true,
default: 0
},
share_count: { //分享数量
type: Number,
require: true,
default: 0
},
praise_count: { //点赞数量
type: Number,
require: true,
default: 0
},
status: { //论坛状态,1启用,0禁用
type: Number,
require: true,
default: 1
}
}, {
'collection': 'pisns_forum_thread'
});
module.exports = mongoose.model('ForumThread', ForumThreadSchema);
\ No newline at end of file
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
//论坛用户
var ForumUserSchema = new Schema({
ent_code: {
type: Number,
require: true,
index: true
},
uid: { //用户ID,这里直接存放用户的openId
type: String,
index: true,
require: true
},
nickName: { //用户昵称,这里直接存放用户的nickname
type: String,
require: true
},
displayName: { //自定义显示名称
type: String
},
icon: { //用户头像
type: String,
require: true
},
displayIcon: { //自定义显示头像
type: String
},
classLevel: { //等级,暂时不用
type: Number,
require: true,
default: 0
},
role: { //用户角色
type: Schema.Types.ObjectId,
require: true
}
status: { //用户状态1,正常,2黑名单
type: Number,
require: true,
default: 1
}
}, {
'collection': 'pisns_forum_user'
});
module.exports = mongoose.model('ForumUser', ForumUserSchema);
\ No newline at end of file
'use strict';
module.exports = {
BUSY: {
errorcode: -1,
errormsg: '系统繁忙,请稍候再试'
},
SUCCESS: {
errorcode: 0,
errormsg: '请求成功'
},
WRONG_PARAM: {
errorcode: 10000,
errormsg: '请求参数错误,请检查'
},
DATA_NOTEXITS: {
errorcode: 10001,
errormsg: '目标数据不存在'
},
UNIQUE_DATA_EXITS: {
errorcode: 10002,
errormsg: '存在重复唯一性数据,请检查'
},
INTEGRAL_NOT_ENOUGH: {
errorcode: 10003,
errormsg: '积分不足'
},
UPDATE_READONLY_ATTR: {
errorcode: 10004,
errormsg: '不允许更新只读属性数据'
}
};
\ No newline at end of file
{
"name": "pisns-member-api",
"version": "0.0.1",
"ignore": [
"**/.*",
"node_modules",
"components"
]
}
'use strict';
var path = require('path'),
rootPath = path.normalize(__dirname + '/..'),
env = process.env.NODE_ENV || 'development';
var config = {
development: {
root: rootPath,
app: {
name: 'pisns-forum-api'
},
port: 3011,
mongodb: {
uri:'114.215.206.32:27018'
username: '',
password: '',
dbname: 'piscrm',
poolSize: 5
}
},
test: {
root: rootPath,
app: {
name: 'pisns-forum-api'
},
port: 3011,
mongo: {
uri:'114.215.206.32:27018'
username: '',
password: '',
dbname: 'sandbox',
poolSize: 5
}
},
production: {
root: rootPath,
app: {
name: 'pisns-forum-api'
},
port: 3011,
mongo: {
uri:'10.165.15.168:27017'
username: 'future',
password: 'future123456',
dbname: 'piscrm',
poolSize: 50
}
}
};
module.exports = config[env];
\ No newline at end of file
'use strict';
var express = require('express');
var glob = require('glob');
var logger = require('morgan');
var bodyParser = require('body-parser');
var compress = require('compression');
var methodOverride = require('method-override');
module.exports = function(app, config) {
if (process.env.NODE_ENV === 'production') {
app.use(logger('combined'));
} else {
app.use(logger('dev'));
}
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(compress());
app.use(methodOverride());
var controllers = glob.sync(config.root + '/app/controllers/*.js');
controllers.forEach(function(controller) {
require(controller)(app);
});
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.json({
errorcode: -1,
errormsg: 'invalid request'
});
});
}
app.use(function(err, req, res, next) {
res.json({
errorcode: -1,
errormsg: 'invalid request'
});
});
};
\ No newline at end of file
{
"name": "pisns-forum-api",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"async": "^0.9.0",
"body-parser": "~1.10.0",
"compression": "~1.2.2",
"express": "^4.10.7",
"glob": "~4.3.1",
"lodash": "~2.4.1",
"method-override": "~2.3.0",
"mongoose": "^3.8.21",
"morgan": "~1.5.0"
},
"devDependencies": {
"grunt": "~0.4.5",
"grunt-develop": "~0.4.0",
"grunt-contrib-watch": "~0.6.1",
"grunt-contrib-compass": "~0.9.0",
"request": "~2.51.0",
"time-grunt": "~1.0.0",
"load-grunt-tasks": "~1.0.0"
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment