114 lines
3.3 KiB
TypeScript
114 lines
3.3 KiB
TypeScript
import { getModelForClass, index, modelOptions, mongoose, pre, prop, ReturnModelType, Severity } from '@typegoose/typegoose'
|
|
import { dbconn } from 'decorators/dbconn'
|
|
// @ts-ignore
|
|
import findOrCreate from 'mongoose-findorcreate'
|
|
import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses'
|
|
import { BaseModule } from './Base'
|
|
import { convert } from 'utils/number.util'
|
|
|
|
const alphabet = '3fBCM8j17XNA9xYun4wmLWep2oHFlhPcgyEJskqOz6GK0UtV5ZRaDSvrTbidQI'
|
|
|
|
export enum TaskStatusEnum {
|
|
NOT_START = 0,
|
|
RUNNING = 1,
|
|
SUCCESS = 2,
|
|
CLAIMED = 3,
|
|
PART_SUCCESS = 4,
|
|
}
|
|
|
|
@modelOptions({ schemaOptions: { _id: false }, options: { allowMixed: Severity.ALLOW }})
|
|
export class TaskStatus {
|
|
@prop()
|
|
id: string
|
|
@prop()
|
|
task: string
|
|
// 0: not start, 1: running, 2: success
|
|
@prop({ enum: TaskStatusEnum, default: TaskStatusEnum.NOT_START })
|
|
status: TaskStatusEnum
|
|
@prop()
|
|
dateTag: string
|
|
@prop()
|
|
timeStart: number
|
|
@prop()
|
|
timeFinish: number
|
|
@prop()
|
|
timeClaim: number
|
|
@prop({ type: mongoose.Schema.Types.Mixed })
|
|
data: any
|
|
}
|
|
|
|
interface ActivityUserClass extends Base, TimeStamps {}
|
|
@dbconn()
|
|
@index({ address: 1, activity: 1 }, { unique: true })
|
|
@index({ inviteCode: 1, activity: 1 }, { unique: true })
|
|
@index({ inviteUser: 1, activity: 1 }, { unique: false })
|
|
@index({ twitterId: 1 }, { unique: true, partialFilterExpression: { twitterId: { $exists: true } } })
|
|
@index({ discordId: 1 }, { unique: true, partialFilterExpression: { discordId: { $exists: true } } })
|
|
@modelOptions({ schemaOptions: { collection: 'activity_user', timestamps: true }, options: { allowMixed: Severity.ALLOW } })
|
|
@pre<ActivityUserClass>('save', async function () {
|
|
if (!this.inviteCode) {
|
|
// 取ObjectId的time和inc段,
|
|
// 将time段倒序(倒序后, 如果以0开始, 则移除0, 随机拼接一个hex字符), 然后拼接inc段, 再转换成52进制
|
|
let timeStr = this.id.slice(0, 8).split("").reverse().join("");
|
|
if (timeStr.indexOf('0') === 0) {
|
|
let randomStr = convert({ numStr: (Math.random() * 51 | 0 + 1) + '', base:10, to: 52})
|
|
timeStr = randomStr + timeStr.slice(1)
|
|
}
|
|
let shortId = timeStr + this.id.slice(-6)
|
|
this.inviteCode = convert({numStr: shortId, base: 16, to: 52, alphabet})
|
|
}
|
|
})
|
|
class ActivityUserClass extends BaseModule {
|
|
@prop({ required: true })
|
|
public address: string
|
|
|
|
@prop({ required: true })
|
|
public activity: string
|
|
// 用户的邀请码
|
|
@prop()
|
|
public inviteCode: string
|
|
// 用户的邀请人
|
|
@prop()
|
|
public inviteUser: string
|
|
|
|
@prop({ default: false })
|
|
public locked: boolean
|
|
@prop()
|
|
public lockedTime?: Date
|
|
@prop()
|
|
public comment?: string
|
|
|
|
@prop()
|
|
public twitterId?: string
|
|
|
|
@prop()
|
|
public twitterName?: string
|
|
|
|
@prop()
|
|
public discordId?: string
|
|
@prop()
|
|
public discordName?: string
|
|
|
|
@prop({default: 1})
|
|
public boost: number
|
|
/**
|
|
* boost过期时间
|
|
* 计算得分时, 如果boost过期, 则不计算boost
|
|
*/
|
|
@prop()
|
|
public boostExpire?: Date
|
|
|
|
@prop()
|
|
public lastLogin?: Date
|
|
|
|
@prop({ type: () => [TaskStatus], default: [] })
|
|
public taskProgress?: TaskStatus[]
|
|
|
|
public static async findByCode(this: ReturnModelType<typeof ActivityUserClass>, inviteCode: string, activity: string) {
|
|
return this.findOne({ inviteCode, activity }).exec()
|
|
}
|
|
|
|
}
|
|
|
|
export const ActivityUser = getModelForClass(ActivityUserClass, { existingConnection: ActivityUserClass.db })
|