Commit e7e4fa08 authored by zhaofei's avatar zhaofei

s

parent ff980819
{
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@tbmp/mp-cloud-sdk": {
"version": "1.1.4",
"resolved": "https://registry.npm.taobao.org/@tbmp/mp-cloud-sdk/download/@tbmp/mp-cloud-sdk-1.1.4.tgz",
"integrity": "sha1-DMuRzXfRfFLNbwyxWENoz9/Rqd0="
},
"async-validator": {
"version": "3.4.0",
"resolved": "https://registry.npm.taobao.org/async-validator/download/async-validator-3.4.0.tgz?cache=0&sync_timestamp=1596623608639&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fasync-validator%2Fdownload%2Fasync-validator-3.4.0.tgz",
"integrity": "sha1-hxs+WUEkv0xOt7zRqeeLRPOwnK4="
},
"dayjs": {
"version": "1.9.4",
"resolved": "https://registry.npm.taobao.org/dayjs/download/dayjs-1.9.4.tgz?cache=0&sync_timestamp=1603435778328&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdayjs%2Fdownload%2Fdayjs-1.9.4.tgz",
"integrity": "sha1-/N6YTiJ/QpbwTnsFcgra0uEHHxs="
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.20.tgz?cache=0&sync_timestamp=1597336053864&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.20.tgz",
"integrity": "sha1-tEqbYpe8tpjxxRo1RaKzs2jVnFI="
},
"miniapp-router": {
"version": "0.1.9",
"resolved": "https://registry.npm.taobao.org/miniapp-router/download/miniapp-router-0.1.9.tgz",
"integrity": "sha1-fRwYj37+eWMbzyRzRYP45Ly0G70="
},
"moment": {
"version": "2.29.1",
"resolved": "https://registry.npm.taobao.org/moment/download/moment-2.29.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmoment%2Fdownload%2Fmoment-2.29.1.tgz",
"integrity": "sha1-sr52n6MZQL6e7qZGnAdeNQBvo9M="
}
}
}
.tea
.DS_Store
.vscode
debug.log
node_modules
\ No newline at end of file
# 数据模拟
```bash
cnpm install
```
```bash
cd mockServer
```
```bash
cnpm install
```
```bash
➜ mockServer npm run start
```
## 库表规范
http://cf.dui88.com/pages/viewpage.action?pageId=63937755
## sdk 接口文档说明
http://cf.dui88.com/pages/viewpage.action?pageId=66194323
{
"runtime": "nodejs8",
"version": "1.0"
}
\ No newline at end of file
This diff is collapsed.
const { pipeActivityInfo } = require('./base.controller');
const UserService = require('../service/user.service');
const AwardsService = require('../service/awards.service');
const { CODE_TYPES } = require('../constants');
const { ResultsModel } = require('../sdk');
let resultModel = new ResultsModel();
/**
* 我的奖品列表
* @param {*} context
*/
const getMyPrizeList = async (context) => {
// 判断活动
let pipeRes = await pipeActivityInfo(context);
// 活动结束可以查看我的奖品
if (pipeRes.code && pipeRes.code !== CODE_TYPES.ERROR_ACTIVITY_OVER.code) {
return pipeRes;
}
let awardSer = new AwardsService(context);
let result = await awardSer.getMyPrizeList({openId: context.openId, activityId: context.data.activityId});
return resultModel.success(result);
}
/**
* 领取实物
* @param {*} context
*/
const receiveObjectPrize = async(context) => {
// 判断活动
let pipeRes = await pipeActivityInfo(context);
// 活动结束可以领取实物
if (pipeRes.code && pipeRes.code !== CODE_TYPES.ERROR_ACTIVITY_OVER.code) {
return pipeRes;
}
let { provinceName, cityName, detailInfo, countyName, streetName, cityCode, _id, name, phone, activityId } = context.data;
if (!_id) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `缺少_id`)
}
if (!name) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `缺少name`)
}
if (!phone) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `缺少phone`)
}
if (!provinceName) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `缺少provinceName`)
}
if (!cityName) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `缺少cityName`)
}
if (!countyName) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `缺少countyName`)
}
if (!detailInfo) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `缺少detailInfo`)
}
let awardSer = new AwardsService(context);
let result = await awardSer.recieveObjectPrize(_id, {activityId, provinceName, cityName, detailInfo, countyName, streetName, cityCode, name, phone});
if (result.code) {
return resultModel.error(result);
}
return resultModel.success(result);
}
/**
* 权益重新领取
* @param {*} context
*/
const receiveEnamePrize = async(context) => {
let pipeRes = await pipeActivityInfo(context);
// 活动结束可以领取权益
if (pipeRes.code && pipeRes.code !== CODE_TYPES.ERROR_ACTIVITY_OVER.code) {
return pipeRes;
}
let {_id} = context.data;
if (!_id) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `缺少_id`)
}
let awardsSer = new AwardsService(context);
let result = await awardsSer.recieveEnamePrize(_id, pipeRes._id);
if (result.code) {
return resultModel.error(result);
}
if (result.remark) {
return resultModel.error(result, result.remark);
}
return resultModel.success(result);
}
module.exports = {
getMyPrizeList,
receiveObjectPrize,
receiveEnamePrize
}
\ No newline at end of file
const BaseService = require('../service/base.service');
const { CODE_TYPES, ACTIVITY_STATUS, OPEN_PRIZE_STATUS } = require('../constants');
const { ResultsModel } = require('../sdk');
let resultModel = new ResultsModel();
// 活动判断
const pipeActivityInfo = async (context) => {
let activitySer = new BaseService(context);
let { activityId } = context.data;
// 参数校验
if (!activityId) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `activityId必填`);
}
// 活动基本情况
let activityInfo = await activitySer.getBaseInfo(activityId);
// 活动不存在
if (!activityInfo && activityInfo.deleteStatus === ACTIVITY_STATUS.DELETE) {
return resultModel.error(CODE_TYPES.ERROR_NO_ACTIVITY);
}
let { startTime, endTime } = activityInfo;
let currentTime = Date.now();
if (currentTime < startTime) {
return resultModel.error(CODE_TYPES.ERROR_ACTIVITY_NOSTART, `活动未开始`);
}
if (currentTime > endTime) {
return resultModel.error(CODE_TYPES.ERROR_ACTIVITY_OVER, `活动已结束`);
}
return activityInfo;
}
// 活动基本信息
const getActivityBaseInfoById = async(context) => {
let activitySer = new BaseService(context);
let { activityId } = context.data;
// 参数校验
if (!activityId) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `activityId必填`);
}
// 活动基本情况
let activityInfo = await activitySer.getBaseInfo(activityId);
// 活动不存在
if (!activityInfo && activityInfo.deleteStatus === ACTIVITY_STATUS.DELETE) {
return resultModel.error(CODE_TYPES.ERROR_NO_ACTIVITY);
}
let { startTime, endTime, rule, _id, title } = activityInfo
return resultModel.success({
title,
startTime,
endTime,
rule,
activityId: _id,
rankLimit: 100,
openPrizeTime: endTime,
openPrize: (activityInfo.openPrizeStatus && activityInfo.openPrizeStatus === OPEN_PRIZE_STATUS.SUCCESS)
});
}
module.exports = {
pipeActivityInfo,
getActivityBaseInfoById
}
\ No newline at end of file
const { pipeActivityInfo } = require('./base.controller');
const UserJoinService = require("../service/userJoin.service");
const UserService = require('../service/user.service');
const StatService = require("../service/stat.service");
const { CODE_TYPES, ONCE_DIAMOND_REDUCE, JOIN_INFO_STATUS, DATA_TYPE, SHOE_TYPE_REWARDS, SHOE_TYPE_MAP, USE_SHOES_DATA } = require('../constants');
const { getToday, getSellerSession } = require('../utils');
const { ResultsModel } = require('../sdk');
let resultModel = new ResultsModel();
const getGameInfo = async context => {
// const pipeRes = await pipeActivityInfo(context);
// if (pipeRes.code) {
// return pipeRes;
// }
let { activityId } = context.data;
let { openId } = context;
const userService = new UserService(context);
const userJoinSer = new UserJoinService(context);
const userInfo = await userService.getUserInfo();
if (!userInfo) return resultModel.error(CODE_TYPES.ERROR_NO_USER);
let { diamond, resurgenceCards, member, toolInfo } = userInfo;
//初始积分
let { session } = await getSellerSession(context, activityId);
let initialCredits = await userService.queryUserCredits(session) || 0
console.log('initialCredits:'+initialCredits)
let joinCount = await userJoinSer.getJoinCount({activityId, openId});
let result = {
diamond,
resurgenceCards,
guideComplete: joinCount > 0,
initialCredits: member.flag ? initialCredits : 0,
toolInfo
}
return resultModel.success(result);
}
// 开始游戏
const startGame = async context => {
let pipeRes = await pipeActivityInfo(context);
if (pipeRes.code) {
return pipeRes;
}
const userService = new UserService(context);
const statService = new StatService(context);
const userInfo = await userService.getUserInfo();
const userJoinSer = new UserJoinService(context);
if (!userInfo) return resultModel.error(CODE_TYPES.ERROR_NO_USER);
let { activityId } = context.data;
const { openId } = context
const { diamond, userNick, maxScore, shoes, member } = userInfo;
if (diamond < ONCE_DIAMOND_REDUCE) {
return resultModel.error(CODE_TYPES.ERROR_NO_GAME_COUNT);
}
let joinCount = await userJoinSer.getJoinCount({activityId, openId});
let todayJoinCount = await userJoinSer.getJoinCount({activityId, openId, createDay: getToday() });
const joinId = await userJoinSer.insertGameInfo({ userNick, maxScore, shoes, score: 0, isVip: member.flag, cards: 0 });
let lastTool = await userJoinSer.getLastGameInfo()
console.log('lastTool'+JSON.stringify(lastTool))
let lastToolType = (lastTool && lastTool.toolType) ? lastTool.toolType : 1
await userService.updateUser(userInfo._id, {
guideComplete: joinCount > 0
});
return resultModel.success({
id: joinId,
guideComplete: joinCount > 0,
isFirstTime: todayJoinCount == 0,
lastToolType
});
}
const submitGame = async context => {
const { activityId, id, score, shoes } = context.data;
if (!activityId) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `activityId必填`);
}
if (!id) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `id必填`);
}
if (!score && score !== 0) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `score必填`);
}
if (!shoes && shoes !== 0) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `shoes必填`);
}
let pipeRes = await pipeActivityInfo(context);
if (pipeRes.code) {
return pipeRes;
}
const userService = new UserService(context);
const userJoinSer = new UserJoinService(context);
const statService = new StatService(context);
const userInfo = await userService.getUserInfo();
if (!userInfo) return resultModel.error(CODE_TYPES.ERROR_NO_USER);
const joinInfo = await userJoinSer.getGameInfo(id,activityId);
if (!joinInfo) return resultModel.error(CODE_TYPES.ERROR_NO_JOIN_INFO);
if (!(joinInfo.status && joinInfo.status == JOIN_INFO_STATUS.START)) {
resultModel.error(CODE_TYPES.ERROR_JOIN_STATUS_ERROR);
}
let { totalScore:oldTotalScore, maxScore, totalShoes:oldShoes, resurgenceCards:oldCards } = userInfo
let newMaxScore = +maxScore > score ? maxScore : parseInt(score)
await userJoinSer.updateGameInfo(id, activityId, {
submitGame: Date.now(),
submitDay: getToday(),
score: parseInt(score),
maxScore: newMaxScore,
duration: Date.now() - joinInfo.createTime,
status: JOIN_INFO_STATUS.FINISH
});
const totalScore = +oldTotalScore + parseInt(score);
const totalShoes = oldShoes + shoes;
await userService.updateUser(userInfo._id, {
totalScore,
totalShoes,
maxScoreTime: Date.now(),
maxScore: newMaxScore,
});
const { rank } = await userService.getUserRank(newMaxScore);
console.log('rank:'+rank)
const list = await userService.getSideScoreUser(newMaxScore,rank)
console.log('rankList:'+list)
//埋点统计
await statService.addStatNumberUv({ activityId, type: DATA_TYPE.addShoesUv, value: shoes })
return resultModel.success({
score,
rankList:list,
maxScore: newMaxScore,
shoes
});
}
//选择道具
const chooseTool = async context => {
const { openId } = context
const { activityId, id, toolType} = context.data;
if (!activityId) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `activityId必填`);
}
if (!toolType) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `toolType必填`);
}
const userService = new UserService(context);
const userInfo = await userService.getUserInfo();
if (!userInfo) return resultModel.error(CODE_TYPES.ERROR_NO_USER);
const userJoinSer = new UserJoinService(context);
const statService = new StatService(context);
const joinCount = await userJoinSer.getJoinCount({activityId, openId});
const joinInfo = await userJoinSer.getGameInfo(id,activityId);
if (!joinInfo) return resultModel.error(CODE_TYPES.ERROR_NO_JOIN_INFO);
let { diamond } = userInfo
//完成新手引导赠送 1次款鞋2 toolType == 2 && joinCount === 1
if(toolType == 1 || (toolType == 2 && joinCount === 1)) {
await userJoinSer.updateGameInfo(id, activityId, {
toolType,
});
await statService.addStat({ activityId, type: USE_SHOES_DATA[toolType] });
//埋点数据 消耗砖石
await statService.addStatNumberUv({ activityId, type: DATA_TYPE.reduceDiamondUv, value: ONCE_DIAMOND_REDUCE })
await userService.updateUser(userInfo._id, {
diamond: diamond > ONCE_DIAMOND_REDUCE ? diamond - ONCE_DIAMOND_REDUCE : 0
});
return resultModel.success({
id,
toolType,
diamond: diamond > ONCE_DIAMOND_REDUCE ? diamond - ONCE_DIAMOND_REDUCE : 0
})
}
if(+diamond < (SHOE_TYPE_REWARDS[toolType] + ONCE_DIAMOND_REDUCE)) {
return resultModel.error(CODE_TYPES.ERROR_NO_GAME_COUNT);
}
await userJoinSer.updateGameInfo(id, activityId, {
toolType
});
//兑换鞋子
await userService.updateUser(userInfo._id, {
diamond: +diamond - (SHOE_TYPE_REWARDS[toolType] + ONCE_DIAMOND_REDUCE)
});
//消耗砖石打点
await statService.addStatNumberUv({ activityId, type:DATA_TYPE.reduceDiamondUv, value: (SHOE_TYPE_REWARDS[toolType] + ONCE_DIAMOND_REDUCE) });
await statService.addStat({ activityId, type: USE_SHOES_DATA[toolType] });
return resultModel.success({
id,
toolType,
diamond: +diamond - (SHOE_TYPE_REWARDS[toolType] + ONCE_DIAMOND_REDUCE)
})
}
//游戏复活
const doResurrection = async context => {
const { activityId, id } = context.data;
if (!activityId) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `activityId必填`);
}
if (!id) {
return resultModel.error(CODE_TYPES.PARAMS_ERROR, `id必填`);
}
const userService = new UserService(context);
const userJoinSer = new UserJoinService(context);
const statService = new StatService(context);
const userInfo = await userService.getUserInfo();
if (!userInfo) return resultModel.error(CODE_TYPES.ERROR_NO_USER);
let { resurgenceCards: oldCards } = userInfo
if(oldCards < 1) {
return resultModel.error(CODE_TYPES.ERROR_NO_CARD_COUNT);
}
const joinInfo = await userJoinSer.getGameInfo(id,activityId);
if (!joinInfo) return resultModel.error(CODE_TYPES.ERROR_NO_JOIN_INFO);
let { cards } = joinInfo
if(cards && cards >= 2) {
return resultModel.error(CODE_TYPES.ERROR_NO_USE_CARD);
}
await userJoinSer.updateGameInfo(id, activityId, {
cards: cards ? cards + 1 : 1
});
const resurgenceCards = oldCards > 1 ? oldCards - 1 : 0;
await userService.updateUser(userInfo._id, {
resurgenceCards
});
await statService.addStatNumberUv({ activityId, type: DATA_TYPE.reduceCardUv, value: 1 })
return resultModel.success({
id,
resurgenceCards: oldCards > 1 ? oldCards - 1 : 0
});
}
module.exports = {
getGameInfo,
startGame,
submitGame,
chooseTool,
doResurrection
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
const ACCESS_DB_NAME = 'c_user_access';
const USER_DB_NAME = 'c_user';
const USER_JOIN_DB_NAME = 'c_user_join';
const DATA_DB_NAME = 'c_stat_info';
const AWARDS_DB_NAME = 'c_awards_info';
const ERROR_LOG_DB_NAME = 'error_log';
const SELLER_INFO_DB_NAME = 'a_seller_info';
const PRIZE_CONFIG_DB_NAME = 'b_prize_config';
const ACTIVITY_CONFIG_DB_NAME = 'b_activity_config';
module.exports = {
ACCESS_DB_NAME,
USER_DB_NAME,
AWARDS_DB_NAME,
ERROR_LOG_DB_NAME,
SELLER_INFO_DB_NAME,
PRIZE_CONFIG_DB_NAME,
ACTIVITY_CONFIG_DB_NAME,
USER_JOIN_DB_NAME,
DATA_DB_NAME
}
const {
getActivityBaseInfoById
} = require('./controller/base.controller');
const {
login,
getVipInfo,
doJoin,
addData,
getUserCredits,
addUserCredits
} = require('./controller/user.controller');
const {
getBrowseGoodsList,
getOrderList,
getTaskList,
completeTask,
doCompleteTask,
isHelp
} = require('./controller/task.controller');
const {
getGameInfo,
startGame,
submitGame,
chooseTool,
doResurrection
} = require('./controller/game.controller');
const {
getMyPrizeList,
receiveObjectPrize,
receiveEnamePrize
} = require('./controller/awards.controller');
module.exports = {
login,
getVipInfo,
getActivityBaseInfoById,
getBrowseGoodsList,
getOrderList,
getTaskList,
completeTask,
doCompleteTask,
isHelp,
getGameInfo,
startGame,
submitGame,
chooseTool,
doResurrection,
doJoin,
getMyPrizeList,
receiveObjectPrize,
receiveEnamePrize,
addData,
getUserCredits,
addUserCredits
}
\ No newline at end of file
This diff is collapsed.
{
"name": "mockserver",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon --watch sdk --watch ../ --watch server.js server.js mock"
},
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.19.2",
"body-parser": "^1.19.0",
"cookie-parser": "^1.4.5",
"express": "^4.17.1",
"http-proxy-middleware": "^1.0.5",
"qs": "^6.9.4",
"request": "^2.88.2",
"request-promise": "^4.2.5",
"string-object-to-object": "^1.0.3"
},
"port": 5555,
"serverProxy": {
"target": "http://10.172.58.215/"
},
"devDependencies": {
"nodemon": "^2.0.4"
}
}
const {CURD_REQUEST} = require('./request');
class BaseDao {
constructor(context, dbName) {
this.db = context.db;
this.TABLE = dbName;
}
/**
* 查询一条数据
* @param query
* @param options
*/
async findOne(query, options) {
let result = await CURD_REQUEST({db: this.db, TABLE: this.TABLE, type: `find`, query: query || {}, options: options || {}});
return result[0];
}
/**
* 查询多条数据
* @param query
* @param options
*/
async find(query, options) {
console.log(`db`, this.db)
let result = await CURD_REQUEST({db: this.db, TABLE: this.TABLE, type: `find`, query: query || {}, options: options || {}});
return result;
}
/**
* 插入单条数据
* @param document
*/
async insertOne(document) {
console.log(`insertOne`, document)
let result = await CURD_REQUEST({db: this.db, TABLE: this.TABLE, type: `insert`, document: document || {}});
return result;
}
/**
* 插入多条数据
* @param documents 插入对象
*/
async insertMany(documents) {
let result = await CURD_REQUEST({db: this.db, TABLE: this.TABLE, type: `insert`, document: documents || [{}]});
return result;
}
/**
* 更新数据
* @param query
* @param options
*/
async update(query, options) {
let result = await CURD_REQUEST({db: this.db, TABLE: this.TABLE, type: `update`, query: query || {}, options: options || {}});
let res = result.nModified > 0 ? 1: 0;
console.log(`update结果`, res);
return res;
}
/**
* 删除多条数据
* @param query
* @param options
*/
async delete(query, options) {
let result = await CURD_REQUEST({db: this.db, TABLE: this.TABLE, type: `delete`, query: query || {}, options: options || {}});
return result;
}
/**
* 获取条目数
* @param query
* @param options
*/
async count(query, options) {
let result = await CURD_REQUEST({db: this.db, TABLE: this.TABLE, type: `count`, query: query || {}, options: options || {}});
return result;
}
}
module.exports = BaseDao;
\ No newline at end of file
const {TBAPI_REQUEST} = require('./request');
let TBAPIS = {}
const APIS = [
`getItemListByItemIds`,
`getPrizeByEname`,
`getShopVipUrl`,
`queryVipinfo`,
`benefitSend`,
`queryCredits`,
`changeCredits`,
`getShopInfo`,
`getBuyerOrderList`,
];
APIS.forEach(v => {
TBAPIS[v] = async (query) => {
let result = await TBAPI_REQUEST(process.db, v, query);
console.log(`TBAPIS.${v}----参数`, process.db, v, query);
console.log(`result`, result);
return result.tbvalue;
};
});
module.exports = TBAPIS;
\ No newline at end of file
const dateFormatter = (thisDate, fmt = 'yyyy-MM-dd hh:mm:ss') => {
thisDate = new Date(thisDate)
console.log(`thisDate`, thisDate)
const o = {
'M+': thisDate.getMonth() + 1,
'd+': thisDate.getDate(),
'h+': thisDate.getHours(),
'm+': thisDate.getMinutes(),
's+': thisDate.getSeconds(),
'q+': Math.floor((thisDate.getMonth() + 3) / 3),
S: thisDate.getMilliseconds(),
};
if (/(y+)/.test(fmt))
fmt = fmt.replace(
RegExp.$1,
(thisDate.getFullYear() + '').substr(4 - RegExp.$1.length)
);
for (const k in o) {
if (new RegExp('(' + k + ')').test(fmt)) {
fmt = fmt.replace(
RegExp.$1,
RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
);
}
}
return fmt;
};
module.exports = dateFormatter
\ No newline at end of file
const BaseDao = require('./BaseDao');
const TBAPIS = require('./TBAPIS');
const transformBeijingDate = require('./transformBeijingDate');
const dateFormatter = require('./dateFormatter')
module.exports = {
BaseDao,
TBAPIS,
transformBeijingDate,
dateFormatter
}
\ No newline at end of file
var axios = require('axios')
let port = require('../package.json').port|| 5555;
const request = async (path, params) => {
let res = await axios({
method: 'post',
url: path,
data: params,
baseURL: `http://127.0.0.1:${port}`
});
if (!res.data.data) {
console.log(`调用${path}${JSON.stringify(params)}\n返回结果`, res.data)
return false
}
return res.data.data
}
const CURD_REQUEST= async ({db, TABLE, type, query, options, document}) => {
// 参数
let data={
dbName: db,
TABLE,
query,
options,
document
};
console.log(`请求参数`, data)
let path=`/proxy/dataMock/${type}`;
return await request(path, data);
};
const TBAPI_REQUEST=async (db,funName,query) => {
// 参数
let data={
dbName: db,
funName
};
let path=`/proxy/dataMock/tbapi`;
let params={
dbName: data.dbName,
funName: data.funName,
query
}
return await request(path, params);
};
module.exports={
CURD_REQUEST,
TBAPI_REQUEST
};
\ No newline at end of file
module.exports = (day) => {
if (day) {
return new Date(day).getTime();
}else {
return new Date().getTime();
}
}
\ No newline at end of file
var express = require('express');
var bodyParser = require("body-parser");
var cookieParser = require("cookie-parser");
var {createProxyMiddleware} = require('http-proxy-middleware');
const routers = require('../index');
const {port, serverProxy } = require('./package.json');
var app = express();
app.use(cookieParser());
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(bodyParser.json());
app.get('/', (req, res) => {
res.json({message: `ok`});
});
// 执行本地云函数方法
app.post('/handler', async (req, res) => {
console.log(req.body);
let {data, openId, db } = req.body;
if(!db) {
res.json({message: `参数错误,缺少数据库db`});
}
if(!openId) {
res.json({message: `参数错误,缺少openId`});
}
try{
let query = JSON.parse(JSON.stringify(data))
}catch(e) {
res.json({message: `查询参数格式错误`});
}
let {handler, data: queryData} = data
if (!handler) {
res.json({message: `格式错误, handler参数不能为空`});
}
if (!queryData) {
res.json({message: `格式错误, data参数不能为空`});
}
if(!process.db) {
process.db = db;
}
req.context = {
openId,
db,
data: queryData
};
if(routers[handler]) {
let result = await routers[handler](req.context);
res.json(result);
}else {
res.json({message: `函数${handler}不存在`});
}
});
// 获取本地export的数据库表及云函数
app.get('/getDBHandlers', async(req, res) => {
let dbs = require('../db');
let handlers = routers;
// dbsInfo
let dbArray = []
let handlerArray = []
Object.keys(dbs).map(v => {
dbArray.push(dbs[v]);
});
Object.keys(handlers).map(v => {
handlerArray.push(v)
});
console.log(dbArray, handlerArray)
res.json({
dbs: dbArray,
handlers: handlerArray,
success: true
});
})
const ProxyOption = {
target: serverProxy.target,
changeOrigin: true,
pathRewrite: (path, req) => {
console.log(`path`, path)
return path.replace('/proxy', '');
},
onProxyReq: (proxyReq, req, res) => {
console.log(`req.body`, req.body)
if (req.body) {
let bodyData = JSON.stringify(req.body);
console.log(`bodyData`, bodyData)
// incase if content-type is application/x-www-form-urlencoded -> we need to change to application/json
proxyReq.setHeader('Content-Type', 'application/json');
proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
// stream the content
proxyReq.write(bodyData);
}
}
}
app.use('/proxy', createProxyMiddleware(ProxyOption));
app.listen(port || 5555);
const data = {
"activityId":"5f35eded0cb7330c94e04eda",
"userNick":"123",
"avatar":"9000989900",
}
const data2 = {
"activityId":"5f35eded0cb7330c94e04eda",
"taskType":"freeMasonrys"
}
\ No newline at end of file
This diff is collapsed.
{
"name": "testst2",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"adler-32": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz",
"integrity": "sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU=",
"requires": {
"exit-on-epipe": "~1.0.1",
"printj": "~1.1.0"
}
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
},
"cfb": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.0.tgz",
"integrity": "sha512-sXMvHsKCICVR3Naq+J556K+ExBo9n50iKl6LGarlnvuA2035uMlGA/qVrc0wQtow5P1vJEw9UyrKLCbtIKz+TQ==",
"requires": {
"adler-32": "~1.2.0",
"crc-32": "~1.2.0",
"printj": "~1.1.2"
}
},
"codepage": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz",
"integrity": "sha1-jL4lSBMjVZ19MHVxsP/5HnodL5k=",
"requires": {
"commander": "~2.14.1",
"exit-on-epipe": "~1.0.1"
},
"dependencies": {
"commander": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz",
"integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw=="
}
}
},
"commander": {
"version": "2.17.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
"integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
},
"crc-32": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz",
"integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==",
"requires": {
"exit-on-epipe": "~1.0.1",
"printj": "~1.1.0"
}
},
"dayjs": {
"version": "1.8.33",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.33.tgz",
"integrity": "sha512-881TDLZCdpJFKbraWRHcUG8zfMLLX400ENf9rFZDuWc5zYMss6xifo2PhlDX0ftOmR2NRmaIY47bAa4gKQfXqw=="
},
"exit-on-epipe": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz",
"integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw=="
},
"frac": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA=="
},
"node-xlsx": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/node-xlsx/-/node-xlsx-0.15.0.tgz",
"integrity": "sha512-rQyhWDJ/k60wQemov7a8MlToastWTidrAVFRwTWV+s53LN/SRwU4lnmc5xuFXx/ay+uaLAsAQBp6BkVob5OjOA==",
"requires": {
"buffer-from": "^1.1.0",
"xlsx": "^0.14.1"
}
},
"printj": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
"integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ=="
},
"ssf": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/ssf/-/ssf-0.10.3.tgz",
"integrity": "sha512-pRuUdW0WwyB2doSqqjWyzwCD6PkfxpHAHdZp39K3dp/Hq7f+xfMwNAWIi16DyrRg4gg9c/RvLYkJTSawTPTm1w==",
"requires": {
"frac": "~1.1.2"
}
},
"taobao-mini-sdk": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/taobao-mini-sdk/-/taobao-mini-sdk-0.1.2.tgz",
"integrity": "sha512-glePe3kdmNNVoEkoPyHRzi5hM1XwIMgJ0Vhh1ouMrzD5sRhG+qCByKhHCjmBddRdEr92DY/3fGrh9lsokF2f+A=="
},
"xlsx": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.14.5.tgz",
"integrity": "sha512-s/5f4/mjeWREmIWZ+HtDfh/rnz51ar+dZ4LWKZU3u9VBx2zLdSIWTdXgoa52/pnZ9Oe/Vu1W1qzcKzLVe+lq4w==",
"requires": {
"adler-32": "~1.2.0",
"cfb": "^1.1.2",
"codepage": "~1.14.0",
"commander": "~2.17.1",
"crc-32": "~1.2.0",
"exit-on-epipe": "~1.0.1",
"ssf": "~0.10.2"
}
}
}
}
{
"name": "testst2",
"version": "1.0.0",
"description": "",
"main": "index.js",
"author": "",
"license": "ISC",
"sdkVersion": "*",
"dependencies": {
"node-xlsx": "^0.15.0",
"taobao-mini-sdk": "0.1.2",
"dayjs": "^1.8.28"
},
"config": {
"notNeedLogin": []
}
}
// 特别注意以下的引用方式,需要.default
const { BaseDao, TBAPI, Utils } = require('taobao-mini-sdk/lib/index').default;
const { DEFAULT_CODE_TYPES, dateFormatter,transformBeijingDate,getStartTimestamp,getEndTimestamp, ResultsModel} = Utils.default;
const TBAPIS = TBAPI.default;
let default_sdk = {
DEFAULT_CODE_TYPES,
ResultsModel,
dateFormatter,
getStartTimestamp,
getEndTimestamp
};
let Config
let mock = process.argv[2];
console.log(`mock`, mock);
// 云函数环境
if (mock !== 'mock') {
Config = Object.assign({}, default_sdk, {
BaseDao,
TBAPIS,
transformBeijingDate
});
}
// 本地环境
else {
let MockConfig = require('./mockServer/sdk');
Config = Object.assign({}, default_sdk, MockConfig);
console.log(Config);
}
module.exports = Config;
/**
* 访问明细
*/
const {
BaseDao
} = require('../sdk');
const { getToday } = require('../utils');
const { ACCESS_DB_NAME } = require('../db');
class UserAccessService {
constructor(context) {
this.context = context;
this.accessdao = new BaseDao(context, ACCESS_DB_NAME);
}
/**
* 增加访问记录
* @param {是否关注店铺} newFollow
*/
async addAccess(isVip = false, type, newFollow = false) {
let {
openId,
data
} = this.context;
let {
activityId,
userNick,
avatar,
inviteId
} = data;
return await this.accessdao.insertOne({
openId,
activityId,
userNick,
avatar,
isReceiveShare: !!inviteId,
inviteId,
isVip,
newFollow,
accessTime: Date.now(),
createTime: Date.now(),
updateTime: Date.now(),
createDay: getToday(),
type
});
}
async addComeAccess(type) {
let { openId, data } = this.context;
let { activityId, userNick = "" } = data;
return await this.accessdao.insertOne({
openId,
activityId,
userNick,
accessTime: Date.now(),
createTime: Date.now(),
updateTime: Date.now(),
createDay: getToday(),
type,
});
}
}
module.exports = UserAccessService;
/**
* 奖励
*/
const { BaseDao } = require('../sdk');
const UserService = require('./user.service');
const { CODE_TYPES, DRAW_STATUS, PRIZE_TYPE, ACTIVITY_STATUS, SHIP_STATUS } = require('../constants');
const {AWARDS_DB_NAME, PRIZE_CONFIG_DB_NAME } = require('../db');
const { sendTBAward, getSellerSession } = require('../utils');
class AwardsService extends UserService{
constructor(context) {
super(context);
this.awardsdao = new BaseDao(context, AWARDS_DB_NAME);
this.activityprizedao = new BaseDao(context, PRIZE_CONFIG_DB_NAME);
}
// 根据奖品Id扣库存
async reduceStock(_id) {
let result = await this.activityprizedao.findOne({_id, deleteStatus: ACTIVITY_STATUS.NORMAL});
// 奖品不存在
if (!result) {
return CODE_TYPES.ERROR_NO_PRIZE;
}
let {switchStock, stock, useStock} = result;
// 若不限制库存
if (switchStock === 2) {
return true;
}
// 若库存不足
if (useStock >= stock) {
return CODE_TYPES.ERROR_NO_STOCK;
}
try{
await this.activityprizedao.update(
{
_id ,
$where: "this.useStock < this.stock"
},
{
$inc: {
useStock: +1
}
}
);
return true;
}catch(e) {
console.log(`扣库存(实物)失败:`, e);
return CODE_TYPES.SYSTEM_ERROR;
}
}
/**
* 插入奖品记录
* @param {*} award
*/
async addAward(award) {
try {
return await this.awardsdao.insertOne({
...award,
createTime: Date.now(),
updateTime: Date.now()
});
}catch(e) {
console.log(`插入中奖记录错误:`, e);
return CODE_TYPES.SYSTEM_ERROR;
}
}
/**
* 我的奖品
* @param {*} param0
*/
async getMyPrizeList({openId, activityId}) {
// 获取奖品领取过期时间
let { awardReceiveExpiredTime, endTime } = await this.getBaseInfo(activityId);
//奖品失效时间为活动后48h
let endPrizeTime = endTime + 48 * 60 * 60 * 1000;
let myprizeList = await this.awardsdao.find({openId, activityId}, {
sort: {
createTime: -1
}
});
// 若有过期时间,且已过期
if (endPrizeTime) {
let currentTime = Date.now()
myprizeList.map(v => {
if(currentTime > endPrizeTime) {
if ([DRAW_STATUS.WAITAWARD, DRAW_STATUS.RETRY].includes(v.drawStatus)) {
v.drawStatus = DRAW_STATUS.EXPIRED;
v.remark = `奖品已过期`;
}
}
v.expiredTime = endPrizeTime;
})
}
return {
endPrizeTime,
list: myprizeList
};
}
// 领取实物
async recieveObjectPrize(_id, {activityId, provinceName, cityName, detailInfo, countyName, streetName, cityCode, name, phone}) {
// 若有过期时间,且已过期
let { awardReceiveExpiredTime } = await this.getBaseInfo(activityId);
if (awardReceiveExpiredTime && Date.now() > awardReceiveExpiredTime) {
return CODE_TYPES.ERROR_PRIZE_EXPIRED
}
let award = await this.awardsdao.findOne({_id});
console.log(`receiveObject-award`, award);
// 奖品不存在
if (!award) {
return CODE_TYPES.ERROR_NO_PRIZE;
}
// 已领取
if (award.drawStatus === DRAW_STATUS.SUCCESS) {
return CODE_TYPES.ERROR_RECEIVE_PRIZE;
}
// 不是实物,非法操作
if (award.type !== PRIZE_TYPE.OBJECT) {
return CODE_TYPES.ERROR_FORBIDDEN_OPE;
}
try {
let result = await this.awardsdao.update({_id}, {
$set: {
receiveName: name,
phone,
drawStatus: DRAW_STATUS.SUCCESS,
address: {
provinceName,
cityName,
countyName,
detailInfo,
streetName,
cityCode,
},
shipStatus: SHIP_STATUS.UNSHIPPED,
receiveTime: Date.now(),
updateTime: Date.now()
}
});
return true;
}catch(e) {
console.log(`领取实物错误:`, e);
return CODE_TYPES.SYSTEM_ERROR;
}
}
// 发放淘宝权益(奖品数据已插入到awards_info表,且状态drawStatus 为1或者6)
async recieveEnamePrize(_id, activityId) {
// 若有过期时间,且已过期
let { awardReceiveExpiredTime } = await this.getBaseInfo(activityId);
if (awardReceiveExpiredTime && Date.now() > awardReceiveExpiredTime) {
return CODE_TYPES.ERROR_PRIZE_EXPIRED;
}
let result = {};
let award = await this.awardsdao.findOne({_id});
// 奖品不存在
if (!award) {
return CODE_TYPES.ERROR_NO_PRIZE;
}
// 已领取
if (award.drawStatus === DRAW_STATUS.SUCCESS) {
return CODE_TYPES.ERROR_RECEIVE_PRIZE;
}
console.log(`award.drawStatus`, award.drawStatus);
// 状态不是1,6
if (![DRAW_STATUS.WAITAWARD, DRAW_STATUS.RETRY].includes(award.drawStatus)) {
return CODE_TYPES.ERROR_FORBIDDEN_OPE;
}
let { session } = await getSellerSession(this.context);
// 发放淘宝权益
result = await sendTBAward(this.context, session, award);
// 更新
await this.awardsdao.update({_id}, {
$set: {
drawStatus: result.drawStatus,
remark: result.remark,
updateTime: Date.now()
}
});
return result;
}
/**
* 获取活动配置项奖品
* @param {*} _id
*/
async getActivityPrizeById(_id) {
return await this.activityprizedao.findOne({_id, deleteStatus: ACTIVITY_STATUS.NORMAL}, {
sort: {
index: 1
}
});
}
}
module.exports = AwardsService;
\ No newline at end of file
/**
* 基本信息
*/
const { BaseDao, transformBeijingDate, dateFormatter } = require('../sdk');
const { ACTIVITY_CONFIG_DB_NAME } = require('../db');
class BaseService {
constructor(context) {
this.context = context;
this.activitydao = new BaseDao(context, ACTIVITY_CONFIG_DB_NAME);
}
/**
* @desc 活动基本信息
* @param {活动id} activityId
* @returns 返回活动详情,若不存在活动,返回为null
*/
async getBaseInfo(activityId) {
if (!activityId) {
activityId = this.context.data.activityId
}
return await this.activitydao.findOne({_id: activityId});
}
}
module.exports = BaseService;
\ No newline at end of file
/**
* 访问明细
*/
const { BaseDao } = require("../sdk");
const { getToday } = require("../utils");
const { DATA_DB_NAME } = require("../db");
class StatService {
constructor(context) {
this.context = context;
this.statService = new BaseDao(context, DATA_DB_NAME);
}
/**
* 增加访问记录
* @param {数据信息} info
*/
async addStat(info) {
let { openId } = this.context;
return await this.statService.insertOne({
...info,
openId,
createTime: Date.now(),
updateTime: Date.now(),
createDay: getToday(),
});
}
/**
* 增加积分 砖石 复活卡 消耗 砖石 复活卡 获得 记录
* @param {数据信息} info
*/
async addStatNumberUv(info) {
let { openId } = this.context;
let { activityId, type, value } = info
let record = await this.statService.findOne({
openId,
activityId,
type,
createDay: getToday()
});
if (null == record) {
return await this.statService.insertOne({
...info,
openId,
createTime: Date.now(),
updateTime: Date.now(),
createDay: getToday(),
});
}
//已经有数据
let oldValue = record.value ? record.value : 0
return await this.statService.update({ _id: record._id }, {
$set :{
...record,
value: oldValue + value,
openId,
updateTime: Date.now(),
}
});
}
/**
* 编辑访问记录 数据缓存使用
* @param {数据信息} info
*/
async updateStat(_id,info) {
let { openId } = this.context;
return await this.statService.update({_id},{
$set: {
...info,
openId,
updateTime: Date.now()
}
});
}
async getStatTypeInfo(info) {
let { openId } = this.context;
let result = await this.statService.find({
...info,
openId,
},{
limit: 1,
sort: {
updateTime: -1
}
});
return result[0]
}
async getStatCount(info) {
let { openId } = this.context;
return this.statService.count({
...info,
openId,
});
}
}
module.exports = StatService;
This diff is collapsed.
This diff is collapsed.
/**
* 访问明细
*/
const { BaseDao } = require("../sdk");
const { getToday } = require("../utils");
const { USER_JOIN_DB_NAME } = require("../db");
const {JOIN_INFO_STATUS} = require('../constants');
class UserJoinService {
constructor(context) {
this.context = context;
this.userJoinDao = new BaseDao(context, USER_JOIN_DB_NAME);
}
// 用户开始游戏
async insertGameInfo(userInfo) {
const { openId, data } = this.context;
const { activityId } = data;
return this.userJoinDao.insertOne({
openId,
activityId,
...userInfo,
status: JOIN_INFO_STATUS.START,
createTime: Date.now(),
updateTime: Date.now(),
createDay: getToday(),
});
}
// 更新用户游戏数据
async updateGameInfo(_id, activityId, info) {
return this.userJoinDao.update(
{
_id,
activityId,
},
{
$set: {
...info,
updateTime: Date.now(),
},
}
);
}
async getGameInfo(_id, activityId) {
return this.userJoinDao.findOne({
_id,
activityId,
});
}
//上一次游戏信息
async getLastGameInfo() {
const { openId, data: { activityId } } = this.context;
const lastList = await this.userJoinDao.find({ openId, activityId, toolType: { $in: [1,2,3] } }, {
limit: 1,
sort: {
updateTime: -1
}
});
console.log('lastList'+lastList)
return lastList[0]
}
async getGameInfoListByToolType(activityId, toolType) {
const { openId } = this.context;
return this.userJoinDao.find({
activityId,
openId,
toolType,
});
}
async getUserJoinTotalScore(activityId) {
const { openId } = this.context;
return this.context.cloud.db.collection(USER_JOIN_DB_NAME).aggregate([
{
$match: { activityId, openId },
},
{
$group: {
_id: "$toolType",
score: { $sum: "$score" },
},
},
]);
}
async getJoinCount(info) {
return this.userJoinDao.count({
...info
});
}
}
module.exports = UserJoinService;
// 获取商家session
const getSellerSession = require('./package/getSession');
// 获取当天时间进行format
const getToday = require('./package/getToday');
// 发放淘宝奖品(权益/积分)
const sendTBAward = require('./package/sendTBAward');
// 通用并发接口
const lockUpdate = require('./package/lockUpdate');
// 用户订单
const getUserOrderlist = require('./package/getUserOrderlist');
//打印调用日志
const { logger, addErrorLog } = require('./package/log');
module.exports = {
getSellerSession,
getToday,
sendTBAward,
lockUpdate,
getUserOrderlist,
logger,
addErrorLog
}
/**
* 获取商家session
*/
const { SELLER_INFO_DB_NAME, ACTIVITY_CONFIG_DB_NAME } = require('../../db');
const { BaseDao } = require('../../sdk')
const getSellerSession = async (context, activityId) => {
if (!activityId) {
activityId = context.data.activityId;
}
let activitydao = new BaseDao(context, ACTIVITY_CONFIG_DB_NAME)
let sellerdao = new BaseDao(context, SELLER_INFO_DB_NAME)
let activityConfigResult = await activitydao.find({ _id: activityId });
if (!activityConfigResult || !activityConfigResult[0]) return {};
let result = await sellerdao.find({
openId: activityConfigResult[0].openId
});
console.log(`getSellerSession`, result);
if (!result || !result[0]) return {};
return {
session: result[0].accessToken
};
}
module.exports = getSellerSession;
\ No newline at end of file
const { transformBeijingDate, dateFormatter } = require('../../sdk');
// 获取今天的时间
const getToday = ()=> {
return dateFormatter(transformBeijingDate(), 'yyyy/MM/dd');
}
module.exports = getToday;
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
.tea
.DS_Store
.vscode
debug.log
node_modules
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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