123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- const {
- dbCmd,
- userCollection
- } = require('../../common/constants')
- const {
- ERROR
- } = require('../../common/error')
- /**
- * 获取随机邀请码,邀请码由大写字母加数字组成,由于存在手动输入邀请码的场景,从可选字符中去除 0、1、I、O
- * @param {number} len 邀请码长度,默认6位
- * @returns {string} 随机邀请码
- */
- function getRandomInviteCode (len = 6) {
- const charArr = ['2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
- let code = ''
- for (let i = 0; i < len; i++) {
- code += charArr[Math.floor(Math.random() * charArr.length)]
- }
- return code
- }
- /**
- * 获取可用的邀请码,至多尝试十次以获取可用邀请码。从10亿可选值中随机,碰撞概率较低
- * 也有其他方案可以尝试,比如在数据库内设置一个从0开始计数的数字,每次调用此方法时使用updateAndReturn使数字加1并返回加1后的值,根据这个值生成对应的邀请码,比如(22222A + 1 == 22222B),此方式性能理论更好,但是不适用于旧项目
- * @param {object} param
- * @param {string} param.inviteCode 初始随机邀请码
- */
- async function getValidInviteCode () {
- let retry = 10
- let code
- let codeValid = false
- while (retry > 0 && !codeValid) {
- retry--
- code = getRandomInviteCode()
- const getUserRes = await userCollection.where({
- my_invite_code: code
- }).limit(1).get()
- if (getUserRes.data.length === 0) {
- codeValid = true
- break
- }
- }
- if (!codeValid) {
- throw {
- errCode: ERROR.SET_INVITE_CODE_FAILED
- }
- }
- return code
- }
- /**
- * 根据邀请码查询邀请人
- * @param {object} param
- * @param {string} param.inviteCode 邀请码
- * @param {string} param.queryUid 受邀人id,非空时校验不可被下家或自己邀请
- * @returns
- */
- async function findUserByInviteCode ({
- inviteCode,
- queryUid
- } = {}) {
- if (typeof inviteCode !== 'string') {
- throw {
- errCode: ERROR.SYSTEM_ERROR
- }
- }
- // 根据邀请码查询邀请人
- let getInviterRes
- if (queryUid) {
- getInviterRes = await userCollection.where({
- _id: dbCmd.neq(queryUid),
- inviter_uid: dbCmd.not(dbCmd.all([queryUid])),
- my_invite_code: inviteCode
- }).get()
- } else {
- getInviterRes = await userCollection.where({
- my_invite_code: inviteCode
- }).get()
- }
- if (getInviterRes.data.length > 1) {
- // 正常情况下不可能进入此条件,以防用户自行修改数据库出错,在此做出判断
- throw {
- errCode: ERROR.SYSTEM_ERROR
- }
- }
- const inviterRecord = getInviterRes.data[0]
- if (!inviterRecord) {
- throw {
- errCode: ERROR.INVALID_INVITE_CODE
- }
- }
- return inviterRecord
- }
- /**
- * 根据邀请码生成邀请信息
- * @param {object} param
- * @param {string} param.inviteCode 邀请码
- * @param {string} param.queryUid 受邀人id,非空时校验不可被下家或自己邀请
- * @returns
- */
- async function generateInviteInfo ({
- inviteCode,
- queryUid
- } = {}) {
- const inviterRecord = await findUserByInviteCode({
- inviteCode,
- queryUid
- })
- // 倒叙拼接当前用户邀请链
- const inviterUid = inviterRecord.inviter_uid || []
- inviterUid.unshift(inviterRecord._id)
- return {
- inviterUid,
- inviteTime: Date.now()
- }
- }
- /**
- * 检查当前用户是否可以接受邀请,如果可以返回用户记录
- * @param {string} uid
- */
- async function checkInviteInfo (uid) {
- // 检查当前用户是否已有邀请人
- const getUserRes = await userCollection.doc(uid).field({
- my_invite_code: true,
- inviter_uid: true
- }).get()
- const userRecord = getUserRes.data[0]
- if (!userRecord) {
- throw {
- errCode: ERROR.ACCOUNT_NOT_EXISTS
- }
- }
- if (userRecord.inviter_uid && userRecord.inviter_uid.length > 0) {
- throw {
- errCode: ERROR.CHANGE_INVITER_FORBIDDEN
- }
- }
- return userRecord
- }
- /**
- * 指定用户接受邀请码邀请
- * @param {object} param
- * @param {string} param.uid 用户uid
- * @param {string} param.inviteCode 邀请人的邀请码
- * @returns
- */
- async function acceptInvite ({
- uid,
- inviteCode
- } = {}) {
- await checkInviteInfo(uid)
- const {
- inviterUid,
- inviteTime
- } = await generateInviteInfo({
- inviteCode,
- queryUid: uid
- })
- if (inviterUid === uid) {
- throw {
- errCode: ERROR.INVALID_INVITE_CODE
- }
- }
- // 更新当前用户的邀请人信息
- await userCollection.doc(uid).update({
- inviter_uid: inviterUid,
- invite_time: inviteTime
- })
- // 更新当前用户邀请的用户的邀请人信息,这步可能较为耗时
- await userCollection.where({
- inviter_uid: uid
- }).update({
- inviter_uid: dbCmd.push(inviterUid)
- })
- return {
- errCode: 0,
- errMsg: ''
- }
- }
- module.exports = {
- acceptInvite,
- generateInviteInfo,
- getValidInviteCode
- }
|