优化邮箱登录, 增加一个用于生成分享码的接口
This commit is contained in:
parent
c16817c480
commit
5001ca558f
@ -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 }
|
||||
}
|
||||
}
|
||||
|
@ -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 })
|
||||
|
80
src/modules/ShareCodeRecord.ts
Normal file
80
src/modules/ShareCodeRecord.ts
Normal 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 })
|
@ -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) {
|
||||
|
@ -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 () => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user