You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
canteen/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/fission.js

193 lines
4.8 KiB

const {
dbCmd,
userCollection
} = require('../../common/constants')
const {
ERROR
} = require('../../common/error')
/**
* 获取随机邀请码邀请码由大写字母加数字组成由于存在手动输入邀请码的场景从可选字符中去除 01IO
* @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
}