优化邮箱登录, 增加一个用于生成分享码的接口

This commit is contained in:
CounterFire2023 2024-05-16 09:59:48 +08:00
parent c16817c480
commit 5001ca558f
5 changed files with 113 additions and 1 deletions

View File

@ -1,4 +1,5 @@
import logger from 'logger/logger'
import { ShareCodeRecord, DEFAULT_SHARE_CODE, ShareCodeStatus, DEFAULT_EXPIRE_TIME } from 'modules/ShareCodeRecord'
import { BaseController, router } from 'zutils'
class MainController extends BaseController {
@ -9,4 +10,25 @@ class MainController extends BaseController {
await user.updateOne({ $inc: { accountVersion: 1 } })
return {}
}
@router('post /wallet/code/generate')
async shareCode(req, res) {
logger.db('code_generate', req)
let user = req.user
let { type } = req.body
let record = await ShareCodeRecord.findOne({ account: user.id, type, status: ShareCodeStatus.PENDING })
if (!record) {
record = new ShareCodeRecord({
account: user.id,
openId: user.openId,
plat: user.plat + '',
code: DEFAULT_SHARE_CODE,
email: user.email,
type,
})
}
record.expiredAt = Date.now() + DEFAULT_EXPIRE_TIME
await record.save()
return { code: record.code }
}
}

View File

@ -30,6 +30,7 @@ export function verifyPass(userpassword: string, passwordDb: string, salt: strin
export interface AccountClass extends Base, TimeStamps {}
@dbconn()
@index({ plat: 1, openId: 1 }, { unique: true })
@index({ plat: 1, email: 1 }, { collation: { locale: 'en', strength: 2 } })
@modelOptions({ schemaOptions: { collection: 'account', timestamps: true }, options: { allowMixed: Severity.ALLOW } })
export class AccountClass extends BaseModule {
@prop({ enum: PlatEnum, default: PlatEnum.GOOGLE })

View File

@ -0,0 +1,80 @@
import { getModelForClass, index, modelOptions, pre, prop, ReturnModelType } from '@typegoose/typegoose'
import { dbconn } from 'decorators/dbconn'
import { BaseModule } from './Base'
import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('23456789abcdefghjkmnpqrstuvwxy', 8)
export const DEFAULT_SHARE_CODE = '00000000'
export const DEFAULT_EXPIRE_TIME = 5 * 60 * 1000
export enum ShareCodeType {
BIND_UAW = 1, // uaw 绑定
}
export enum ShareCodeStatus {
PENDING = 1,
SUCCESS = 2,
FAIL = 3,
EXPIRED = 4,
}
/**
*
*/
@dbconn()
@index({ type: 1, code: 1 }, { unique: true, partialFilterExpression: { status: 1 } })
@index({ account: 1, type: 1, status: 1 }, { unique: true, partialFilterExpression: { status: 1 } })
@index({ expiredAt: 1, status: 1 }, { unique: false })
@modelOptions({
schemaOptions: { collection: 'share_code_record', timestamps: true },
})
@pre<ShareCodeRecordClass>('save', async function () {
if (this.code === DEFAULT_SHARE_CODE) {
let exists = false
while (!exists) {
const code = nanoid()
const record = await ShareCodeRecord.findByCode(code, this.type)
if (!record) {
exists = true
this.code = code
}
}
}
})
class ShareCodeRecordClass extends BaseModule {
@prop({ required: true })
public account: string
@prop({ required: true })
public openId: string
@prop()
public email?: string
@prop({ required: true })
public plat: string
@prop({ required: true })
public code!: string
@prop({ default: Date.now() + DEFAULT_EXPIRE_TIME })
public expiredAt?: number
@prop({ required: true, default: ShareCodeType.BIND_UAW })
public type: ShareCodeType
@prop({ required: true, default: ShareCodeStatus.PENDING })
public status: ShareCodeStatus
public static async findByCode(
this: ReturnModelType<typeof ShareCodeRecordClass>,
code: string,
type: ShareCodeType,
) {
return this.findOne({ code, type, status: ShareCodeStatus.PENDING }).exec()
}
}
export const ShareCodeRecord = getModelForClass(ShareCodeRecordClass, { existingConnection: ShareCodeRecordClass.db })

View File

@ -2,6 +2,8 @@ import { ZError } from 'zutils'
import { IPlat } from './IPlat'
import { CodeRecord, CodeStatus, CodeType } from 'modules/CodeRecord'
import { sha1 } from 'zutils/utils/security.util'
import { Account } from 'modules/Account'
import { PlatEnum } from 'enums/PlatEnum'
const isEmail = (email: string) => {
const reg = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/
@ -34,7 +36,9 @@ export class PlatEmail implements IPlat {
if (recordCode.status !== CodeStatus.PENDING) {
throw new ZError(13, 'code expired')
}
const openId = sha1(email)
email = email.toLowerCase()
let account = await Account.findOne({ plat: PlatEnum.EMAIL, email }).collation({ locale: 'en', strength: 2 })
const openId = account ? account.openId : sha1(email)
let data: any = { email, emailReal: email, emailVerified: true }
const { api_platform } = req.headers
if (api_platform) {

View File

@ -1,6 +1,7 @@
import { singleton } from 'zutils'
import { CodeRecord, CodeStatus } from 'modules/CodeRecord'
import * as schedule from 'node-schedule'
import { ShareCodeRecord } from 'modules/ShareCodeRecord'
/**
*
@ -10,6 +11,10 @@ export default class CodeTaskSchedule {
async parseAllRecord() {
let now = Date.now()
await CodeRecord.updateMany({ expiredAt: { $lt: now }, status: CodeStatus.PENDING }, { status: CodeStatus.EXPIRED })
await ShareCodeRecord.updateMany(
{ expiredAt: { $lt: now }, status: CodeStatus.PENDING },
{ status: CodeStatus.EXPIRED },
)
}
scheduleAll() {
const job = schedule.scheduleJob('*/1 * * * *', async () => {