完善一些检查
This commit is contained in:
parent
6ff402e670
commit
a0ba5249fc
41
configs/chest.json
Normal file
41
configs/chest.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"chests": [
|
||||||
|
{
|
||||||
|
"level": 1,
|
||||||
|
"name": "Wooden Chest",
|
||||||
|
"initScoreMin": 10,
|
||||||
|
"initScoreMax": 50,
|
||||||
|
"maxBonus": 10,
|
||||||
|
"minBonus": 5,
|
||||||
|
"maxBounsCount": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 2,
|
||||||
|
"name": "Iron Chest",
|
||||||
|
"initScoreMin": 20,
|
||||||
|
"initScoreMax": 60,
|
||||||
|
"maxBonus": 20,
|
||||||
|
"minBonus": 10,
|
||||||
|
"maxBounsCount": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 3,
|
||||||
|
"name": "Bronze Chest",
|
||||||
|
"initScoreMin": 30,
|
||||||
|
"initScoreMax": 80,
|
||||||
|
"maxBonus": 30,
|
||||||
|
"minBonus": 15,
|
||||||
|
"maxBounsCount": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": 4,
|
||||||
|
"name": "Sliver Chest",
|
||||||
|
"initScoreMin": 40,
|
||||||
|
"initScoreMax": 100,
|
||||||
|
"maxBonus": 40,
|
||||||
|
"minBonus": 20,
|
||||||
|
"maxBounsCount": 50
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
4
configs/share_cfg.json
Normal file
4
configs/share_cfg.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"inviter": 10,
|
||||||
|
"invitee": 10
|
||||||
|
}
|
@ -1,9 +1,10 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"_id": "first_activity",
|
"_id": "uaw_activity",
|
||||||
"name": "First Activity1",
|
"name": "UAW Activity",
|
||||||
"description": "This is the first test activity",
|
"description": "UAW",
|
||||||
"tasks": [{
|
"tasks": [
|
||||||
|
{
|
||||||
"id": "e2yhq2lj30vwcpedv7p",
|
"id": "e2yhq2lj30vwcpedv7p",
|
||||||
"task": "TwitterConnect",
|
"task": "TwitterConnect",
|
||||||
"title": "",
|
"title": "",
|
||||||
@ -147,7 +148,7 @@
|
|||||||
"task": "TwitterRetweet",
|
"task": "TwitterRetweet",
|
||||||
"title": "",
|
"title": "",
|
||||||
"type": 2,
|
"type": 2,
|
||||||
"desc": "Showcase your performance in Counter Fire to your friends!",
|
"desc": "Showcase your performance in Counter Fire to your friends!",
|
||||||
"category": "Social Tasks",
|
"category": "Social Tasks",
|
||||||
"score": 300,
|
"score": 300,
|
||||||
"autoclaim": false,
|
"autoclaim": false,
|
||||||
@ -170,117 +171,8 @@
|
|||||||
"start": "2024-01-01 00:00",
|
"start": "2024-01-01 00:00",
|
||||||
"end": "2025-01-01 00:00",
|
"end": "2025-01-01 00:00",
|
||||||
"params": {"time": 6, "failRate": 60}
|
"params": {"time": 6, "failRate": 60}
|
||||||
}, {
|
}
|
||||||
"id": "e2f7fplj30vwcpe0l97",
|
],
|
||||||
"task": "DailyCheckIn",
|
|
||||||
"title": "",
|
|
||||||
"type": 1,
|
|
||||||
"desc": "Check-in for 3 consecutive days.",
|
|
||||||
"category": "Referral to Earn",
|
|
||||||
"score": 100,
|
|
||||||
"autoclaim": false,
|
|
||||||
"pretasks": [],
|
|
||||||
"cfg": {},
|
|
||||||
"start": "2024-01-01 00:00",
|
|
||||||
"end": "2025-01-01 00:00",
|
|
||||||
"params": {"days": 3}
|
|
||||||
}, {
|
|
||||||
"id": "e2f7fplj30vwcpe0l98",
|
|
||||||
"task": "OkxLogin",
|
|
||||||
"title": "",
|
|
||||||
"type": 1,
|
|
||||||
"desc": "Sign in via OKX Wallet.",
|
|
||||||
"category": "Referral to Earn",
|
|
||||||
"score": 300,
|
|
||||||
"autoclaim": false,
|
|
||||||
"pretasks": [],
|
|
||||||
"cfg": {"account": "okx", "icon": "okx"},
|
|
||||||
"start": "2024-01-01 00:00",
|
|
||||||
"end": "2025-01-01 00:00",
|
|
||||||
"params": {"item": {"lottery_ticket": 1}}
|
|
||||||
}, {
|
|
||||||
"id": "e2f7fplj30vwcpe0l96",
|
|
||||||
"task": "DailyCheckIn",
|
|
||||||
"title": "",
|
|
||||||
"type": 2,
|
|
||||||
"desc": "Daily check-in! Score more Flames with 7 days of consecutive check-ins. Ignite it now!",
|
|
||||||
"category": "Social Tasks",
|
|
||||||
"score": 20,
|
|
||||||
"autoclaim": false,
|
|
||||||
"pretasks": [],
|
|
||||||
"cfg": {"score": [0, 15, 20, 20, 40, 40, 60]},
|
|
||||||
"start": "2024-01-01 00:00",
|
|
||||||
"end": "2025-01-01 00:00",
|
|
||||||
"params": {"days": 1, "score": [0, 15, 20, 20, 40, 40, 60]}
|
|
||||||
}, {
|
|
||||||
"id": "e2f7t4lj30vwcpe0ldr",
|
|
||||||
"task": "ShareCode",
|
|
||||||
"title": "",
|
|
||||||
"desc": "Click here if your are referred by a friend!",
|
|
||||||
"type": 1,
|
|
||||||
"category": "Social Tasks",
|
|
||||||
"show": true,
|
|
||||||
"autoclaim": false,
|
|
||||||
"pretasks": [],
|
|
||||||
"cfg": {},
|
|
||||||
"score": 500,
|
|
||||||
"params": {"score": [500]}
|
|
||||||
}, {
|
|
||||||
"id": "e2f7t4lj31vwcpe0ldr",
|
|
||||||
"task": "BurnNft",
|
|
||||||
"type": 1,
|
|
||||||
"show": true,
|
|
||||||
"repeat": 2,
|
|
||||||
"title": "Hero NFT",
|
|
||||||
"desc": "Click to burn and redeem Flame",
|
|
||||||
"category": "CF Pal",
|
|
||||||
"autoclaim": false,
|
|
||||||
"pretasks": [],
|
|
||||||
"cfg": {"address": "0xCD4bb3402f1a444a1AF10F31946Ed37DaC0eaC4d"},
|
|
||||||
"score": 200,
|
|
||||||
"params": {"address": "0xCD4bb3402f1a444a1AF10F31946Ed37DaC0eaC4d"}
|
|
||||||
}, {
|
|
||||||
"id": "e2f7t4lj32vwcpe0ldr",
|
|
||||||
"task": "BurnNft",
|
|
||||||
"type": 1,
|
|
||||||
"show": true,
|
|
||||||
"repeat": 2,
|
|
||||||
"title": "Candy Badge",
|
|
||||||
"desc": "Click to burn and redeem Flame",
|
|
||||||
"category": "CF Pal",
|
|
||||||
"pretasks": [],
|
|
||||||
"cfg": {"address": "0x6a673D946a976776fd5F163d9d831b2fEB600015"},
|
|
||||||
"score": 100,
|
|
||||||
"params": {"address": "0x6a673D946a976776fd5F163d9d831b2fEB600015"}
|
|
||||||
}, {
|
|
||||||
"id": "e2f7t4lj33vwcpe0ldr",
|
|
||||||
"task": "BurnNft",
|
|
||||||
"type": 1,
|
|
||||||
"show": true,
|
|
||||||
"repeat": 2,
|
|
||||||
"title": "Explorer Badge",
|
|
||||||
"desc": "Click to burn and redeem Flame",
|
|
||||||
"category": "CF Pal",
|
|
||||||
"autoclaim": false,
|
|
||||||
"pretasks": [],
|
|
||||||
"cfg": {"address": "0x7b6399DFbed8Bc46F6A498C6B1040E80c2B5C4bc"},
|
|
||||||
"score": 100,
|
|
||||||
"params": {"address": "0x7b6399DFbed8Bc46F6A498C6B1040E80c2B5C4bc"}
|
|
||||||
}, {
|
|
||||||
"id": "e2f7t4lj33vwcpe0ldr",
|
|
||||||
"task": "BurnNft",
|
|
||||||
"type": 1,
|
|
||||||
"show": true,
|
|
||||||
"repeat": 2,
|
|
||||||
"title": "Gacha Badge",
|
|
||||||
"desc": "Click to burn and redeem Flame",
|
|
||||||
"category": "CF Pal",
|
|
||||||
"autoclaim": false,
|
|
||||||
"pretasks": [],
|
|
||||||
"cfg": {"address": "0xe2E4D5a4045fBFcbCBECAf5b8A94303712d2FA97"},
|
|
||||||
"score": 200,
|
|
||||||
"params": {"address": "0xe2E4D5a4045fBFcbCBECAf5b8A94303712d2FA97"}
|
|
||||||
}],
|
|
||||||
"startTime": 1711086450119,
|
"startTime": 1711086450119,
|
||||||
"endTime": 1713678477701
|
"endTime": 1713678477701
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"_id": "uaw_activity",
|
"_id": "first_activity",
|
||||||
"name": "UAW Activity",
|
"name": "First Activity1",
|
||||||
"description": "UAW",
|
"description": "This is the first test activity",
|
||||||
"tasks": [
|
"tasks": [{
|
||||||
{
|
|
||||||
"id": "e2yhq2lj30vwcpedv7p",
|
"id": "e2yhq2lj30vwcpedv7p",
|
||||||
"task": "TwitterConnect",
|
"task": "TwitterConnect",
|
||||||
"title": "",
|
"title": "",
|
||||||
@ -171,8 +170,117 @@
|
|||||||
"start": "2024-01-01 00:00",
|
"start": "2024-01-01 00:00",
|
||||||
"end": "2025-01-01 00:00",
|
"end": "2025-01-01 00:00",
|
||||||
"params": {"time": 6, "failRate": 60}
|
"params": {"time": 6, "failRate": 60}
|
||||||
}
|
}, {
|
||||||
],
|
"id": "e2f7fplj30vwcpe0l97",
|
||||||
|
"task": "DailyCheckIn",
|
||||||
|
"title": "",
|
||||||
|
"type": 1,
|
||||||
|
"desc": "Check-in for 3 consecutive days.",
|
||||||
|
"category": "Referral to Earn",
|
||||||
|
"score": 100,
|
||||||
|
"autoclaim": false,
|
||||||
|
"pretasks": [],
|
||||||
|
"cfg": {},
|
||||||
|
"start": "2024-01-01 00:00",
|
||||||
|
"end": "2025-01-01 00:00",
|
||||||
|
"params": {"days": 3}
|
||||||
|
}, {
|
||||||
|
"id": "e2f7fplj30vwcpe0l98",
|
||||||
|
"task": "OkxLogin",
|
||||||
|
"title": "",
|
||||||
|
"type": 1,
|
||||||
|
"desc": "Sign in via OKX Wallet.",
|
||||||
|
"category": "Referral to Earn",
|
||||||
|
"score": 300,
|
||||||
|
"autoclaim": false,
|
||||||
|
"pretasks": [],
|
||||||
|
"cfg": {"account": "okx", "icon": "okx"},
|
||||||
|
"start": "2024-01-01 00:00",
|
||||||
|
"end": "2025-01-01 00:00",
|
||||||
|
"params": {"item": {"lottery_ticket": 1}}
|
||||||
|
}, {
|
||||||
|
"id": "e2f7fplj30vwcpe0l96",
|
||||||
|
"task": "DailyCheckIn",
|
||||||
|
"title": "",
|
||||||
|
"type": 2,
|
||||||
|
"desc": "Daily check-in! Score more Flames with 7 days of consecutive check-ins. Ignite it now!",
|
||||||
|
"category": "Social Tasks",
|
||||||
|
"score": 20,
|
||||||
|
"autoclaim": false,
|
||||||
|
"pretasks": [],
|
||||||
|
"cfg": {"score": [0, 15, 20, 20, 40, 40, 60]},
|
||||||
|
"start": "2024-01-01 00:00",
|
||||||
|
"end": "2025-01-01 00:00",
|
||||||
|
"params": {"days": 1, "score": [0, 15, 20, 20, 40, 40, 60]}
|
||||||
|
}, {
|
||||||
|
"id": "e2f7t4lj30vwcpe0ldr",
|
||||||
|
"task": "ShareCode",
|
||||||
|
"title": "",
|
||||||
|
"desc": "Click here if your are referred by a friend!",
|
||||||
|
"type": 1,
|
||||||
|
"category": "Social Tasks",
|
||||||
|
"show": true,
|
||||||
|
"autoclaim": false,
|
||||||
|
"pretasks": [],
|
||||||
|
"cfg": {},
|
||||||
|
"score": 500,
|
||||||
|
"params": {"score": [500]}
|
||||||
|
}, {
|
||||||
|
"id": "e2f7t4lj31vwcpe0ldr",
|
||||||
|
"task": "BurnNft",
|
||||||
|
"type": 1,
|
||||||
|
"show": true,
|
||||||
|
"repeat": 2,
|
||||||
|
"title": "Hero NFT",
|
||||||
|
"desc": "Click to burn and redeem Flame",
|
||||||
|
"category": "CF Pal",
|
||||||
|
"autoclaim": false,
|
||||||
|
"pretasks": [],
|
||||||
|
"cfg": {"address": "0xCD4bb3402f1a444a1AF10F31946Ed37DaC0eaC4d"},
|
||||||
|
"score": 200,
|
||||||
|
"params": {"address": "0xCD4bb3402f1a444a1AF10F31946Ed37DaC0eaC4d"}
|
||||||
|
}, {
|
||||||
|
"id": "e2f7t4lj32vwcpe0ldr",
|
||||||
|
"task": "BurnNft",
|
||||||
|
"type": 1,
|
||||||
|
"show": true,
|
||||||
|
"repeat": 2,
|
||||||
|
"title": "Candy Badge",
|
||||||
|
"desc": "Click to burn and redeem Flame",
|
||||||
|
"category": "CF Pal",
|
||||||
|
"pretasks": [],
|
||||||
|
"cfg": {"address": "0x6a673D946a976776fd5F163d9d831b2fEB600015"},
|
||||||
|
"score": 100,
|
||||||
|
"params": {"address": "0x6a673D946a976776fd5F163d9d831b2fEB600015"}
|
||||||
|
}, {
|
||||||
|
"id": "e2f7t4lj33vwcpe0ldr",
|
||||||
|
"task": "BurnNft",
|
||||||
|
"type": 1,
|
||||||
|
"show": true,
|
||||||
|
"repeat": 2,
|
||||||
|
"title": "Explorer Badge",
|
||||||
|
"desc": "Click to burn and redeem Flame",
|
||||||
|
"category": "CF Pal",
|
||||||
|
"autoclaim": false,
|
||||||
|
"pretasks": [],
|
||||||
|
"cfg": {"address": "0x7b6399DFbed8Bc46F6A498C6B1040E80c2B5C4bc"},
|
||||||
|
"score": 100,
|
||||||
|
"params": {"address": "0x7b6399DFbed8Bc46F6A498C6B1040E80c2B5C4bc"}
|
||||||
|
}, {
|
||||||
|
"id": "e2f7t4lj33vwcpe0ldr",
|
||||||
|
"task": "BurnNft",
|
||||||
|
"type": 1,
|
||||||
|
"show": true,
|
||||||
|
"repeat": 2,
|
||||||
|
"title": "Gacha Badge",
|
||||||
|
"desc": "Click to burn and redeem Flame",
|
||||||
|
"category": "CF Pal",
|
||||||
|
"autoclaim": false,
|
||||||
|
"pretasks": [],
|
||||||
|
"cfg": {"address": "0xe2E4D5a4045fBFcbCBECAf5b8A94303712d2FA97"},
|
||||||
|
"score": 200,
|
||||||
|
"params": {"address": "0xe2E4D5a4045fBFcbCBECAf5b8A94303712d2FA97"}
|
||||||
|
}],
|
||||||
"startTime": 1711086450119,
|
"startTime": 1711086450119,
|
||||||
"endTime": 1713678477701
|
"endTime": 1713678477701
|
||||||
}
|
}
|
@ -18,7 +18,7 @@
|
|||||||
"@fastify/formbody": "^7.4.0",
|
"@fastify/formbody": "^7.4.0",
|
||||||
"@fastify/helmet": "^10.1.0",
|
"@fastify/helmet": "^10.1.0",
|
||||||
"@fastify/jwt": "^6.7.1",
|
"@fastify/jwt": "^6.7.1",
|
||||||
"@typegoose/typegoose": "^12.1.0",
|
"@typegoose/typegoose": "^12.2.0",
|
||||||
"bson": "^4.0.4",
|
"bson": "^4.0.4",
|
||||||
"dotenv": "^16.0.3",
|
"dotenv": "^16.0.3",
|
||||||
"ethers": "^5.6.8",
|
"ethers": "^5.6.8",
|
||||||
@ -26,7 +26,7 @@
|
|||||||
"fastify-plugin": "^3.0.0",
|
"fastify-plugin": "^3.0.0",
|
||||||
"fastify-xml-body-parser": "^2.2.0",
|
"fastify-xml-body-parser": "^2.2.0",
|
||||||
"mongodb-extended-json": "^1.11.1",
|
"mongodb-extended-json": "^1.11.1",
|
||||||
"mongoose": "8.1.0",
|
"mongoose": "8.2.3",
|
||||||
"node-schedule": "^2.0.0",
|
"node-schedule": "^2.0.0",
|
||||||
"siwe": "^2.1.4",
|
"siwe": "^2.1.4",
|
||||||
"tracer": "^1.1.6",
|
"tracer": "^1.1.6",
|
||||||
|
@ -14,3 +14,5 @@ export const CONFIRM_MAIL_HTML = `
|
|||||||
<p>点击链接进入确认页面, 如果无法跳转, 就复制链接, 电脑上直接用浏览器打开, 手机上使用MetaMask的浏览器打开</p>
|
<p>点击链接进入确认页面, 如果无法跳转, 就复制链接, 电脑上直接用浏览器打开, 手机上使用MetaMask的浏览器打开</p>
|
||||||
<p><a href="{{link}}" target="_blank">{{link2}}</a></p>
|
<p><a href="{{link}}" target="_blank">{{link2}}</a></p>
|
||||||
`
|
`
|
||||||
|
// 是否需要手动开启游戏
|
||||||
|
export const MANUAL_OPEN_GAME = true
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { ActivityInfo } from 'models/ActivityInfo'
|
import { ActivityInfo } from 'models/ActivityInfo'
|
||||||
import { ActivityUser } from 'models/ActivityUser'
|
import { ActivityUser } from 'models/ActivityUser'
|
||||||
import { rankKey, rankLevel } from 'services/rank.svr'
|
import { rankKey, rankLevel, updateRankScore } from 'services/rank.svr'
|
||||||
import { BaseController, ROLE_ANON, SyncLocker, ZError, ZRedisClient, role, router } from 'zutils'
|
import { BaseController, ROLE_ANON, SyncLocker, ZError, ZRedisClient, role, router } from 'zutils'
|
||||||
import { ScoreRecord } from 'models/ScoreRecord'
|
import { ScoreRecord } from 'models/ScoreRecord'
|
||||||
import { formatAddress } from 'zutils/utils/chain.util'
|
import { formatAddress } from 'zutils/utils/chain.util'
|
||||||
|
import { formatDate } from 'zutils/utils/date.util'
|
||||||
|
const shareCfg = require('../../configs/share_cfg.json')
|
||||||
|
|
||||||
const MAX_LIMIT = 100
|
const MAX_LIMIT = 100
|
||||||
export default class ActivityController extends BaseController {
|
export default class ActivityController extends BaseController {
|
||||||
@ -38,6 +40,30 @@ export default class ActivityController extends BaseController {
|
|||||||
if (!inviteUser) {
|
if (!inviteUser) {
|
||||||
throw new ZError(12, 'invalid invite code')
|
throw new ZError(12, 'invalid invite code')
|
||||||
}
|
}
|
||||||
|
// TODO:: 检查自己是否符合条件
|
||||||
|
const dateTag = formatDate(new Date())
|
||||||
|
// 更新邀请积分-邀请人
|
||||||
|
await updateRankScore({
|
||||||
|
user: inviteUser.id,
|
||||||
|
score: shareCfg.inviter,
|
||||||
|
activity: user.activity,
|
||||||
|
scoreType: 'invite_user',
|
||||||
|
scoreParams: {
|
||||||
|
date: dateTag,
|
||||||
|
user: user.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// 更新邀请积分-被邀请人
|
||||||
|
await updateRankScore({
|
||||||
|
user: user.id,
|
||||||
|
score: shareCfg.invitee,
|
||||||
|
activity: user.activity,
|
||||||
|
scoreType: 'invite_invitee',
|
||||||
|
scoreParams: {
|
||||||
|
date: dateTag,
|
||||||
|
user: inviteUser.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
user.inviteUser = inviteUser.id
|
user.inviteUser = inviteUser.id
|
||||||
await user.save()
|
await user.save()
|
||||||
return {}
|
return {}
|
||||||
|
@ -5,6 +5,13 @@ import { mongoose } from '@typegoose/typegoose'
|
|||||||
import { rankKey, rankLevel, updateRankScore } from 'services/rank.svr'
|
import { rankKey, rankLevel, updateRankScore } from 'services/rank.svr'
|
||||||
import { formatDate } from 'zutils/utils/date.util'
|
import { formatDate } from 'zutils/utils/date.util'
|
||||||
import { ScoreRecord } from 'models/ScoreRecord'
|
import { ScoreRecord } from 'models/ScoreRecord'
|
||||||
|
import { ChestRecord } from 'models/chain/ChestRecord'
|
||||||
|
const chestCfg = require('../../configs/chest.json')
|
||||||
|
const chestLevelMap = new Map()
|
||||||
|
|
||||||
|
for (let cfg of chestCfg.chests) {
|
||||||
|
chestLevelMap.set(cfg.level, cfg)
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 宝箱相关接口
|
* 宝箱相关接口
|
||||||
*/
|
*/
|
||||||
@ -67,25 +74,37 @@ class BoxController extends BaseController {
|
|||||||
const { code } = req.params
|
const { code } = req.params
|
||||||
const user = req.user
|
const user = req.user
|
||||||
const uid = user.uid
|
const uid = user.uid
|
||||||
const score = 10 //TODO:: 根据规则生成助力积分
|
|
||||||
const session = await mongoose.startSession()
|
const session = await mongoose.startSession()
|
||||||
session.startTransaction()
|
session.startTransaction()
|
||||||
try {
|
try {
|
||||||
|
// TODO:: 检查用户是否符合助力条件
|
||||||
const chest = await ActivityChest.findOne({ shareCode: code, activity: user.activity }).session(session)
|
const chest = await ActivityChest.findOne({ shareCode: code, activity: user.activity }).session(session)
|
||||||
if (chest.bonusUsers.includes(uid)) {
|
if (chest.bonusUsers.includes(uid)) {
|
||||||
throw new ZError(10, 'user already enhanced')
|
throw new ZError(10, 'user already enhanced')
|
||||||
}
|
}
|
||||||
if (chest.bonusUsers.length >= chest.maxBonus) {
|
if (chest.bonusUsers.length >= chest.maxBounsCount) {
|
||||||
throw new ZError(12, 'enhanced times exceed')
|
throw new ZError(12, 'enhanced times exceed')
|
||||||
}
|
}
|
||||||
|
if (chest.status === 9) {
|
||||||
|
throw new ZError(13, 'chest already opened')
|
||||||
|
}
|
||||||
|
if (chest.status === 0) {
|
||||||
|
throw new ZError(14, 'chest is locked')
|
||||||
|
}
|
||||||
|
if (chest.user === uid) {
|
||||||
|
throw new ZError(15, 'can not enhance self')
|
||||||
|
}
|
||||||
|
const score = Math.floor(Math.random() * (chest.bounsCfg[1] - chest.bounsCfg[0] + 1) + chest.bounsCfg[0])
|
||||||
chest.bonusUsers.push(uid)
|
chest.bonusUsers.push(uid)
|
||||||
chest.bonusScores.push(score)
|
chest.bonusScores.push(score)
|
||||||
chest.scoreBonus += score
|
chest.scoreBonus += score
|
||||||
await chest.save({ session })
|
await chest.save({ session })
|
||||||
|
// TODO:: 新用户给一个锁住的箱子
|
||||||
await session.commitTransaction()
|
await session.commitTransaction()
|
||||||
session.endSession()
|
session.endSession()
|
||||||
return {
|
return {
|
||||||
score: 1, // TODO:: 根据规则生成自己获得助力积分
|
score: 1,
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
session.abortTransaction()
|
session.abortTransaction()
|
||||||
@ -96,6 +115,12 @@ class BoxController extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 开启宝箱
|
* 开启宝箱
|
||||||
|
* 流程如下:
|
||||||
|
* 1. 客户端组装json string: data:,{"p":"cf-20","op":"chest_open","id":"${chestId}"}
|
||||||
|
* 2. 将字符串转成hex
|
||||||
|
* 3. 将hex字符串作为data, 发起一笔至特定地址的0ETH交易
|
||||||
|
* 4. 服务端监听到交易后, 解析input, 获取chestId
|
||||||
|
* 5. 服务端调用此接口, 传入chestId, 完成开箱操作
|
||||||
*/
|
*/
|
||||||
@router('post /api/chest/open')
|
@router('post /api/chest/open')
|
||||||
async openChest(req) {
|
async openChest(req) {
|
||||||
@ -105,6 +130,10 @@ class BoxController extends BaseController {
|
|||||||
if (!chestid) {
|
if (!chestid) {
|
||||||
throw new ZError(11, 'chestid is required')
|
throw new ZError(11, 'chestid is required')
|
||||||
}
|
}
|
||||||
|
const openRecord = await ChestRecord.findOne({ from: user.address, chestId: chestid })
|
||||||
|
if (!openRecord) {
|
||||||
|
throw new ZError(12, 'onchain open record not found')
|
||||||
|
}
|
||||||
const chest = await ActivityChest.findById(chestid)
|
const chest = await ActivityChest.findById(chestid)
|
||||||
if (!chest) {
|
if (!chest) {
|
||||||
throw new ZError(12, 'chest not found')
|
throw new ZError(12, 'chest not found')
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
import { MANUAL_OPEN_GAME } from 'common/Constants'
|
||||||
import { ActivityGame } from 'models/ActivityGame'
|
import { ActivityGame } from 'models/ActivityGame'
|
||||||
import { DAILY_SIGN, SIGN_TOTAL, TicketRecord, USE_TICKET } from 'models/TicketRecord'
|
import { DAILY_SIGN, SIGN_TOTAL, TicketRecord, USE_TICKET } from 'models/TicketRecord'
|
||||||
import { queryCheckInList } from 'services/chain.svr'
|
import { queryCheckInList } from 'services/chain.svr'
|
||||||
import { checkInToday, seqSignCfg, seqSignScore, totalSignCfg, totalSignScore } from 'services/sign.svr'
|
import { checkInToday, seqSignCfg, seqSignScore, totalSignCfg, totalSignScore } from 'services/sign.svr'
|
||||||
import { ZError, SyncLocker, ZRedisClient, BaseController, ROLE_ANON, role, router } from 'zutils'
|
import { ZError, SyncLocker, ZRedisClient, BaseController, ROLE_ANON, role, router } from 'zutils'
|
||||||
import { formatDate } from 'zutils/utils/date.util'
|
import { formatDate } from 'zutils/utils/date.util'
|
||||||
|
const chestCfg = require('../../configs/chest.json')
|
||||||
/**
|
/**
|
||||||
* 探索游戏相关接口
|
* 探索游戏相关接口
|
||||||
*/
|
*/
|
||||||
@ -18,7 +20,7 @@ class GameController extends BaseController {
|
|||||||
const { address } = user
|
const { address } = user
|
||||||
const dateTag = formatDate(new Date())
|
const dateTag = formatDate(new Date())
|
||||||
const gameRecord = await ActivityGame.insertOrUpdate({ user: user.id, activity: user.activity }, {})
|
const gameRecord = await ActivityGame.insertOrUpdate({ user: user.id, activity: user.activity }, {})
|
||||||
if (gameRecord.status === 0) {
|
if (MANUAL_OPEN_GAME && gameRecord.status === 0) {
|
||||||
throw new ZError(11, 'map not open')
|
throw new ZError(11, 'map not open')
|
||||||
}
|
}
|
||||||
if (dateTag === gameRecord.lastSignDay) {
|
if (dateTag === gameRecord.lastSignDay) {
|
||||||
@ -101,17 +103,27 @@ class GameController extends BaseController {
|
|||||||
score,
|
score,
|
||||||
})
|
})
|
||||||
const gameRecord = await ActivityGame.insertOrUpdate({ user: user.id, activity: user.activity }, {})
|
const gameRecord = await ActivityGame.insertOrUpdate({ user: user.id, activity: user.activity }, {})
|
||||||
|
if (MANUAL_OPEN_GAME && gameRecord.status === 0) {
|
||||||
|
throw new ZError(12, 'map not open')
|
||||||
|
}
|
||||||
gameRecord.tickets += score
|
gameRecord.tickets += score
|
||||||
await gameRecord.save()
|
await gameRecord.save()
|
||||||
await record.save()
|
await record.save()
|
||||||
return { ticket: score }
|
return { ticket: score }
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* //TODO::开启地图
|
* 开启地图
|
||||||
*/
|
*/
|
||||||
@router('get /api/game/open')
|
@router('get /api/game/open')
|
||||||
async openMap(req) {
|
async openMap(req) {
|
||||||
const user = req.user
|
const user = req.user
|
||||||
|
const gameInfo = await ActivityGame.insertOrUpdate({ user: user.id, activity: user.activity }, {})
|
||||||
|
if (gameInfo.status === 1) {
|
||||||
|
throw new ZError(11, 'already opened')
|
||||||
|
}
|
||||||
|
// TODO:: check condition
|
||||||
|
gameInfo.status = 1
|
||||||
|
await gameInfo.save()
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -121,6 +133,9 @@ class GameController extends BaseController {
|
|||||||
async gameStat(req, res) {
|
async gameStat(req, res) {
|
||||||
const user = req.user
|
const user = req.user
|
||||||
const record = await ActivityGame.insertOrUpdate({ user: user.id, activity: user.activity }, {})
|
const record = await ActivityGame.insertOrUpdate({ user: user.id, activity: user.activity }, {})
|
||||||
|
if (MANUAL_OPEN_GAME && record.status === 0) {
|
||||||
|
throw new ZError(12, 'map not open')
|
||||||
|
}
|
||||||
const signCfg = seqSignCfg
|
const signCfg = seqSignCfg
|
||||||
const dateTag = formatDate(new Date())
|
const dateTag = formatDate(new Date())
|
||||||
const checkRecord = await checkInToday(user.address, dateTag)
|
const checkRecord = await checkInToday(user.address, dateTag)
|
||||||
@ -180,7 +195,7 @@ class GameController extends BaseController {
|
|||||||
step = parseInt(step)
|
step = parseInt(step)
|
||||||
|
|
||||||
const record = await ActivityGame.insertOrUpdate({ user: user.id, activity: user.activity }, {})
|
const record = await ActivityGame.insertOrUpdate({ user: user.id, activity: user.activity }, {})
|
||||||
if (record.status === 0) {
|
if (MANUAL_OPEN_GAME && record.status === 0) {
|
||||||
throw new ZError(12, 'map not open')
|
throw new ZError(12, 'map not open')
|
||||||
}
|
}
|
||||||
if (record.tickets < step) {
|
if (record.tickets < step) {
|
||||||
|
@ -13,6 +13,9 @@ var ejson = require('mongodb-extended-json')
|
|||||||
const fs = require('fs') // Used to get all the files in a directory
|
const fs = require('fs') // Used to get all the files in a directory
|
||||||
const list = fs.readdirSync(dir)
|
const list = fs.readdirSync(dir)
|
||||||
for (var i = 0; i < list.length; i++) {
|
for (var i = 0; i < list.length; i++) {
|
||||||
|
if (list[i].endsWith('.json') === false) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
// Remove the file extension
|
// Remove the file extension
|
||||||
const collection_name = list[i].replace('.json', '')
|
const collection_name = list[i].replace('.json', '')
|
||||||
const parsedJSON = require(dir + '/' + list[i])
|
const parsedJSON = require(dir + '/' + list[i])
|
||||||
|
@ -44,7 +44,10 @@ class ActivityChestClass extends BaseModule {
|
|||||||
public level: number
|
public level: number
|
||||||
// 最大助力次数
|
// 最大助力次数
|
||||||
@prop()
|
@prop()
|
||||||
public maxBonus: number
|
public maxBounsCount: number
|
||||||
|
// 助力积分配置[min, max]
|
||||||
|
@prop({ type: () => [Number], default: [] })
|
||||||
|
public bounsCfg: number[]
|
||||||
// 基础积分
|
// 基础积分
|
||||||
@prop({ default: 0 })
|
@prop({ default: 0 })
|
||||||
public scoreInit: number
|
public scoreInit: number
|
||||||
@ -64,7 +67,7 @@ class ActivityChestClass extends BaseModule {
|
|||||||
stat: this.status,
|
stat: this.status,
|
||||||
shareCode: this.shareCode,
|
shareCode: this.shareCode,
|
||||||
level: this.level,
|
level: this.level,
|
||||||
maxBonus: this.maxBonus,
|
maxBounsCount: this.maxBounsCount,
|
||||||
scoreInit: this.scoreInit,
|
scoreInit: this.scoreInit,
|
||||||
scoreBonus: this.scoreBonus,
|
scoreBonus: this.scoreBonus,
|
||||||
bounsCount: this.bonusUsers.length,
|
bounsCount: this.bonusUsers.length,
|
||||||
|
60
src/models/chain/ChestRecord.ts
Normal file
60
src/models/chain/ChestRecord.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { getModelForClass, index, modelOptions, prop } from '@typegoose/typegoose'
|
||||||
|
import { dbconn } from 'decorators/dbconn'
|
||||||
|
import { BaseModule } from '../Base'
|
||||||
|
import { hexToUtf8 } from 'zutils/utils/string.util'
|
||||||
|
import logger from 'logger/logger'
|
||||||
|
|
||||||
|
@dbconn('chain')
|
||||||
|
@index({ from: 1 }, { unique: false })
|
||||||
|
@index({ from: 1, chestId: 1 }, { unique: true })
|
||||||
|
@index({ from: 1, blockTime: 1 }, { unique: false })
|
||||||
|
@modelOptions({
|
||||||
|
schemaOptions: { collection: 'chest_open_record', timestamps: true },
|
||||||
|
})
|
||||||
|
export class ChestRecordClass extends BaseModule {
|
||||||
|
@prop({ required: true })
|
||||||
|
public from!: string
|
||||||
|
@prop()
|
||||||
|
public to: string
|
||||||
|
@prop({ required: true })
|
||||||
|
public hash: string
|
||||||
|
@prop()
|
||||||
|
public blockNumber: string
|
||||||
|
@prop()
|
||||||
|
public blockHash: string
|
||||||
|
@prop()
|
||||||
|
public blockTime: number
|
||||||
|
@prop()
|
||||||
|
public dateTag: string
|
||||||
|
@prop()
|
||||||
|
public chestId: string
|
||||||
|
@prop()
|
||||||
|
public value: string
|
||||||
|
@prop()
|
||||||
|
public input: string
|
||||||
|
|
||||||
|
public static async saveEvent(event: any) {
|
||||||
|
const dataStr = hexToUtf8(event.input)
|
||||||
|
const regexp = /data:,{\"p\":\"cf-20\",\"op\":\"chest_open\",\"id\":\"(.+?)\"}/
|
||||||
|
const match = dataStr.match(regexp)
|
||||||
|
if (!match) {
|
||||||
|
logger.log('not a chest open event:', event.hash)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
event.chestId = match[1]
|
||||||
|
logger.log('open chest with id:', event.chestId)
|
||||||
|
return ChestRecord.insertOrUpdate({ hash: event.hash }, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
public toJson() {
|
||||||
|
return {
|
||||||
|
address: this.from,
|
||||||
|
day: this.dateTag,
|
||||||
|
time: this.blockTime,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ChestRecord = getModelForClass(ChestRecordClass, {
|
||||||
|
existingConnection: ChestRecordClass['db'],
|
||||||
|
})
|
3
src/services/activity.svr.ts
Normal file
3
src/services/activity.svr.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const isActivityReady = (activity: any) => {
|
||||||
|
return true
|
||||||
|
}
|
@ -38,7 +38,7 @@ export const queryCheckInSeq = async (address: string) => {
|
|||||||
return record.toJson()
|
return record.toJson()
|
||||||
}
|
}
|
||||||
|
|
||||||
export const queryBurnNftList = async (address: string, user: string, chain: number) => {
|
export const queryBurnNftList = async (address: string, user: string, chain: string) => {
|
||||||
address = address.toLowerCase()
|
address = address.toLowerCase()
|
||||||
user = user.toLowerCase()
|
user = user.toLowerCase()
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ export default class BurnNft extends ITask {
|
|||||||
const { task } = data
|
const { task } = data
|
||||||
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
let cfg = this.activity.tasks.find((t: TaskCfg) => t.id === task.id)
|
||||||
const address = cfg.params.address.toLowerCase()
|
const address = cfg.params.address.toLowerCase()
|
||||||
const chain = parseInt(process.env.CHAIN)
|
const chain = process.env.CHAIN
|
||||||
const nftList = await queryBurnNftList(address, this.user.address, chain)
|
const nftList = await queryBurnNftList(address, this.user.address, chain)
|
||||||
const localNft = await NftBurnRecord.find({
|
const localNft = await NftBurnRecord.find({
|
||||||
user: this.user.id,
|
user: this.user.id,
|
||||||
|
42
yarn.lock
42
yarn.lock
@ -659,15 +659,15 @@
|
|||||||
resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz"
|
resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz"
|
||||||
integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
|
integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
|
||||||
|
|
||||||
"@typegoose/typegoose@^12.1.0":
|
"@typegoose/typegoose@^12.2.0":
|
||||||
version "12.1.0"
|
version "12.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typegoose/typegoose/-/typegoose-12.1.0.tgz#06da94152fef00e69978ecd5de6db83a7ae420b7"
|
resolved "https://registry.yarnpkg.com/@typegoose/typegoose/-/typegoose-12.2.0.tgz#c1aeba14f80ae94069000a9a2db0128c1e35b8fe"
|
||||||
integrity sha512-RhqsFvTCTshtYxuzsHCGwPLJXgX1sc5aguZJ4w3ax6shVHaVQSG4VZddo/BowfP+0CSjp4J8XeCtrunkzkhJOg==
|
integrity sha512-6gC5aIfccXw4IZOMe3oSef63M6leDyMvuycfwzQdVi8M9C5UnpaV8tO1xzmxiOxUHDST0GdDW/aWCCX6MtOQxg==
|
||||||
dependencies:
|
dependencies:
|
||||||
lodash "^4.17.20"
|
lodash "^4.17.20"
|
||||||
loglevel "^1.8.1"
|
loglevel "^1.9.1"
|
||||||
reflect-metadata "^0.2.1"
|
reflect-metadata "^0.2.1"
|
||||||
semver "^7.5.4"
|
semver "^7.6.0"
|
||||||
tslib "^2.6.2"
|
tslib "^2.6.2"
|
||||||
|
|
||||||
"@types/bn.js@^4.11.3":
|
"@types/bn.js@^4.11.3":
|
||||||
@ -2998,10 +2998,10 @@ lodash@^4.17.20:
|
|||||||
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
|
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
|
||||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||||
|
|
||||||
loglevel@^1.8.1:
|
loglevel@^1.9.1:
|
||||||
version "1.8.1"
|
version "1.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.1.tgz#5c621f83d5b48c54ae93b6156353f555963377b4"
|
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.1.tgz#d63976ac9bcd03c7c873116d41c2a85bafff1be7"
|
||||||
integrity sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==
|
integrity sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==
|
||||||
|
|
||||||
long-timeout@0.1.1:
|
long-timeout@0.1.1:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
@ -3232,10 +3232,10 @@ mongodb@6.3.0:
|
|||||||
bson "^6.2.0"
|
bson "^6.2.0"
|
||||||
mongodb-connection-string-url "^3.0.0"
|
mongodb-connection-string-url "^3.0.0"
|
||||||
|
|
||||||
mongoose@8.1.0:
|
mongoose@8.2.3:
|
||||||
version "8.1.0"
|
version "8.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-8.1.0.tgz#25be9a39295c0cbffc971fdd4fb6302dceeb2ded"
|
resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-8.2.3.tgz#26c2074b0d65fa83fa2fd899d3327a2a820fd4c8"
|
||||||
integrity sha512-kOA4Xnq2goqNpN9EmYElGNWfxA9H80fxcr7UdJKWi3UMflza0R7wpTihCpM67dE/0MNFljoa0sjQtlXVkkySAQ==
|
integrity sha512-ZB8K8AgbVgLCcqjtmZMxaQBEztwEEZCtAIPMx2Q56Uo4WWKmwf5Nu/EEIFo8d/17P946X0z6xzxwIqCxUMKxrA==
|
||||||
dependencies:
|
dependencies:
|
||||||
bson "^6.2.0"
|
bson "^6.2.0"
|
||||||
kareem "2.5.1"
|
kareem "2.5.1"
|
||||||
@ -3337,6 +3337,13 @@ node-addon-api@^2.0.0:
|
|||||||
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz"
|
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz"
|
||||||
integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==
|
integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==
|
||||||
|
|
||||||
|
node-fetch@2:
|
||||||
|
version "2.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
|
||||||
|
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
|
||||||
|
dependencies:
|
||||||
|
whatwg-url "^5.0.0"
|
||||||
|
|
||||||
node-fetch@2.6.7:
|
node-fetch@2.6.7:
|
||||||
version "2.6.7"
|
version "2.6.7"
|
||||||
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz"
|
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz"
|
||||||
@ -3937,6 +3944,13 @@ semver@^7.5.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
lru-cache "^6.0.0"
|
lru-cache "^6.0.0"
|
||||||
|
|
||||||
|
semver@^7.6.0:
|
||||||
|
version "7.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d"
|
||||||
|
integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==
|
||||||
|
dependencies:
|
||||||
|
lru-cache "^6.0.0"
|
||||||
|
|
||||||
send@0.18.0:
|
send@0.18.0:
|
||||||
version "0.18.0"
|
version "0.18.0"
|
||||||
resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz"
|
resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user