修改箱子助力流程

This commit is contained in:
CounterFire2023 2024-04-08 14:24:15 +08:00
parent b518d21ad1
commit 3312b8c1ed
4 changed files with 170 additions and 15 deletions

View File

@ -24,6 +24,9 @@
1. 探索状态(12), 移除signCfg, 增加seqStat, 用于标识连续签到奖励领取状态
1. 增加领取连续签到奖励(25)的接口
#### 20240408
1. 增加宝箱助力状态查询(26), 用于助力上链前查询是否符合条件
### 1. 钱包预登录
#### Request
@ -690,7 +693,7 @@ body:
```js
{
"days": 3 // 领取的累计签到天数
"code": 3 // 领取的累计签到天数
}
```
@ -703,4 +706,37 @@ body:
}
```
###
### 26.\* 宝箱助力状态查询
#### Request
- URL`/api/chest/enhance/state`
- 方法:`POST`
- 头部:
- Authorization: Bearer JWT_token
body:
```js
{
"code": "1123", // 宝箱的分享code, code和id选择传一个, 如果两个都传, 优先使用id来查询箱子
"id": "123123"
}
```
#### Response
```js
{
userCurrent: 1, // 用户当日已助力次数
userMax: 10, // 用户当日最大可助力次数
chestCurrent: 1, // 宝箱当前助力次数
chestMax: 10, // 宝箱最大可助力次数
enhanced: 0, // 用户是否已经为当前宝箱助力
}
```
###

View File

@ -49,3 +49,8 @@ export const SCORE_INVITE_REBATE = 'invite_rebate'
// google reCaptcha最小分数
export const RECAPTCHA_MIN_SCORE = 0.5
// 基础用户每日可助力次数
export const MAX_ENHANCE_COUNT_BASE = 1
// 高级用户每日可助力次数
export const MAX_ENHANCE_COUNT_ADV = 10

View File

@ -6,10 +6,12 @@ import { formatDate } from 'zutils/utils/date.util'
import { ScoreRecord } from 'models/ScoreRecord'
import { ChestRecord } from 'models/chain/ChestRecord'
import { generateNewChest } from 'services/game.svr'
import { SCORE_OPEN_CHEST } from 'common/Constants'
import { MAX_ENHANCE_COUNT_ADV, MAX_ENHANCE_COUNT_BASE, SCORE_OPEN_CHEST } from 'common/Constants'
import { formatAddress } from 'zutils/utils/chain.util'
import { isObjectIdString, isValidShareCode } from 'common/Utils'
import { checkReCaptcha } from 'services/google.svr'
import { GeneralScription } from 'models/chain/GeneralScription'
import { ChestEnhanceRecord } from 'models/ChestEnhanceRecord'
/**
*
@ -89,6 +91,50 @@ class BoxController extends BaseController {
}
return result
}
/**
*
*/
@router('post /api/chest/enhance/state')
async enhanceState(req) {
const { code, id } = req.params
const user = req.user
if (code && !isValidShareCode(code)) {
throw new ZError(11, 'invalid share code')
}
if (id && !isObjectIdString(id)) {
throw new ZError(11, 'invalid chest id')
}
if (!code && !id) {
throw new ZError(11, 'must provide share code or chest id')
}
let chest: any
if (id) {
chest = await ActivityChest.findById(id)
} else {
chest = await ActivityChest.findOne({ shareCode: code, activity: user.activity })
}
if (!chest) {
throw new ZError(12, 'chest not found')
}
if (chest.status === ChestStatusEnum.OPENED) {
throw new ZError(14, 'chest already opened')
}
if (chest.status === ChestStatusEnum.LOCKED) {
throw new ZError(15, 'chest is locked')
}
const enhanced = chest.bonusUsers.includes(user.id) ? 1 : 0
const userMax = user.twitterId && user.discordId ? MAX_ENHANCE_COUNT_ADV : MAX_ENHANCE_COUNT_BASE
const dateTag = formatDate(new Date())
const userCurrent = await ChestEnhanceRecord.countDocuments({ user: user.id, activity: user.activity, dateTag })
return {
userCurrent,
userMax,
enhanced,
chestCurrent: chest.bonusUsers.length,
chestMax: chest.maxBounsCount,
}
}
/**
*
*/
@ -102,6 +148,14 @@ class BoxController extends BaseController {
if (!isValidShareCode(code)) {
throw new ZError(11, 'invalid share code')
}
const chainRecord = await GeneralScription.findOne({
from: user.address.toLowerCase(),
op: 'chest_enhance',
data: code,
})
if (!chainRecord) {
throw new ZError(13, 'waiting for chain confirm')
}
// TODO:: 待规则确定后, 检查用户是否符合助力条件
const chest = await ActivityChest.findOne({ shareCode: code, activity: user.activity })
@ -124,6 +178,12 @@ class BoxController extends BaseController {
if (process.env.NODE_ENV === 'production' && chest.user === uid) {
throw new ZError(15, 'can not enhance self')
}
const userMax = user.twitterId && user.discordId ? MAX_ENHANCE_COUNT_ADV : MAX_ENHANCE_COUNT_BASE
const dateTag = formatDate(new Date())
const userCurrent = await ChestEnhanceRecord.countDocuments({ user: user.id, activity: user.activity, dateTag })
if (userCurrent >= userMax) {
throw new ZError(16, 'user enhance times exceed')
}
const score = Math.floor(Math.random() * (chest.bounsCfg[1] - chest.bounsCfg[0] + 1) + chest.bounsCfg[0])
await ActivityChest.updateOne(
{ _id: chest.id },
@ -132,20 +192,31 @@ class BoxController extends BaseController {
$push: { bonusUsers: uid, bonusScores: score },
},
)
const chestsForUser = await ActivityChest.find({ user: uid, activity: user.activity })
// 如果用户没有宝箱, 则说明用户是新用户, 生成一个宝箱
if (chestsForUser.length === 0) {
const newChest = generateNewChest(uid, user.activity, 1, ChestStatusEnum.NORMAL)
await newChest.save()
return {
score: 0,
chests: [newChest.toJson()],
}
} else {
return {
score: 0,
}
const enhanceRecord = new ChestEnhanceRecord({
user: uid,
activity: user.activity,
dateTag,
chest: chest.id,
score,
})
await enhanceRecord.save()
return {
score,
}
// const chestsForUser = await ActivityChest.find({ user: uid, activity: user.activity })
// 如果用户没有宝箱, 则说明用户是新用户, 生成一个宝箱
// if (chestsForUser.length === 0) {
// const newChest = generateNewChest(uid, user.activity, 1, ChestStatusEnum.NORMAL)
// await newChest.save()
// return {
// score: 0,
// chests: [newChest.toJson()],
// }
// } else {
// return {
// score: 0,
// }
// }
}
/**

View File

@ -0,0 +1,43 @@
import { getModelForClass, index, modelOptions, prop } from '@typegoose/typegoose'
import { dbconn } from 'decorators/dbconn'
import { BaseModule } from './Base'
@dbconn()
@index({ user: 1, activity: 1, dateTag: 1 }, { unique: false })
@index({ user: 1, activity: 1, chest: 1 }, { unique: false })
@index({ activity: 1, chest: 1 }, { unique: false })
@modelOptions({
schemaOptions: { collection: 'chest_enhance_record', timestamps: true },
})
class ChestEnhanceRecordClass extends BaseModule {
@prop({ required: true })
public user: string
@prop({ required: true })
public activity: string
@prop()
public chest: string
@prop()
public dateTag: string
@prop()
public score: number
public toJson() {
return {
user: this.user,
activity: this.activity,
chest: this.chest,
score: this.score,
dateTag: this.dateTag,
//@ts-ignore
time: this.createdAt.getTime(),
}
}
}
export const ChestEnhanceRecord = getModelForClass(ChestEnhanceRecordClass, {
existingConnection: ChestEnhanceRecordClass['db'],
})