import { ActivityInfo } from 'models/ActivityInfo' import { ActivityUser } from 'models/ActivityUser' import { rankKey, rankLevel } from 'services/rank.svr' import { BaseController, ROLE_ANON, ZError, ZRedisClient, role, router } from 'zutils' import { SyncLocker } from 'common/SyncLocker' import { ScoreRecord } from 'models/ScoreRecord' import { formatAddress } from 'zutils/utils/chain.util' import { formatNumShow, isValidShareCode } from 'common/Utils' import { checkReCaptcha } from 'services/google.svr' import { RANK_SCORE_SCALE, SCORE_INVITE_REBATE } from 'common/Constants' import logger from 'logger/logger' const MAX_LIMIT = 100 export default class ActivityController extends BaseController { @role(ROLE_ANON) @router('get /api/activity/:id') async info(req) { let { id } = req.params if (!id) { throw new ZError(11, 'invalid activity id') } let activity = await ActivityInfo.findById(id) if (!activity) { throw new ZError(12, 'activity not found') } return activity.toJson() } /** * 更新邀请码 * @param req * @returns */ @router('post /api/activity/upload_invite_code') async uploadInviteCode(req) { await new SyncLocker().checkLock(req) logger.db('upload_invite_code', req) await checkReCaptcha(req, 'invite_user') let { code } = req.params if (!isValidShareCode(code)) { throw new ZError(11, 'invalid invite code') } let user = req.user if (user.inviteUser) { throw new ZError(11, 'invite user already set') } // if (!user.allTaskFinished()) { // throw new ZError(12, 'not all tasks finished') // } // In production, users cannot invite themselves if (process.env.NODE_ENV === 'production' && code === user.inviteCode) { throw new ZError(13, 'cannot invite yourself') } let inviteUser = await ActivityUser.findByCode(code, user.activity) if (!inviteUser) { throw new ZError(12, 'invalid invite code') } // const dateTag = formatDate(new Date()) // // 更新邀请积分-邀请人 // await updateRankScore({ // user: inviteUser.id, // score: shareCfg.inviter, // activity: user.activity, // scoreType: SCORE_INVITE_USER, // scoreParams: { // date: dateTag, // user: user.id, // }, // }) // // 更新邀请积分-被邀请人 // await updateRankScore({ // user: user.id, // score: shareCfg.invitee, // activity: user.activity, // scoreType: SCORE_INVITE_INVITEE, // scoreParams: { // date: dateTag, // user: inviteUser.id, // }, // }) user.inviteUser = inviteUser.id await user.save() // return { score: shareCfg.invitee } return { score: 0 } } /** * 邀请列表 */ @router('get /api/activity/invite_list') async inviteUserList(req) { let user = req.user const totalKey = rankKey(user.activity) const keyInvite = `${user.activity}:invite` let users = await ActivityUser.find({ inviteUser: user.id }) let records = await ScoreRecord.find({ type: SCORE_INVITE_REBATE, user: user.id, activity: user.activity }) let scoreMap = new Map() for (let r of records) { if (!scoreMap.has(r.data.fromUser)) { scoreMap.set(r.data.fromUser, 0) } scoreMap.set(r.data.fromUser, scoreMap.get(r.data.fromUser) + r.score) } let results = [] for (let u of users) { const totalScore = await new ZRedisClient().zscore(totalKey, u.id) // const inviteScore = await new ZRedisClient().zscore(keyInvite, `${user.id}_${u.id}`) const score = totalScore ? parseInt(totalScore + '') / RANK_SCORE_SCALE : 0 const scoreInvite = scoreMap.get(u.id) || 0 results.push({ // user: u.id, level: rankLevel(score), nickname: u.twitterName || u.discordName || formatAddress(u.address), avatar: u.twitterAvatar || '', score: formatNumShow(score), scoreInvite: formatNumShow(scoreInvite), }) } return results } /** * 积分详情列表 */ @router('get /api/activity/score_list') async scoreList(req) { let user = req.user const records = await ScoreRecord.find({ user: user.id, activity: user.activity, score: { $gt: 0 } }).sort({ _id: -1, }) return records.map(record => { return { score: formatNumShow(record.score), type: record.type, //@ts-ignore time: record.createdAt.getTime(), } }) } @role(ROLE_ANON) @router('get /api/activity/leaderboard/:activity/:page') async inviteCode(req) { let { page, activity, limit } = req.params page = parseInt(page || '0') limit = parseInt(limit || MAX_LIMIT) page = page < 0 ? 0 : page const start = page * limit const end = start + limit - 1 const records = await new ZRedisClient().zrevrange(`${activity}:score`, start, end) let results: any = [] // const yesterdayKey = rankKey(activity, yesterday()) for (let i = 0; i < records.length; i += 2) { const id = records[i] let score = formatNumShow(parseInt(records[i + 1]) / RANK_SCORE_SCALE) const user = await ActivityUser.findById(id) const rank = start + i / 2 + 1 results.push({ rank, level: rankLevel(rank), nickname: user?.twitterName || user?.discordName || user?.address ? formatAddress(user.address) : 'unknown', avatar: user?.twitterAvatar || '', score, // yesterday: yesterdayScore ? parseInt(yesterdayScore + '') : 0, }) } return results } }