qrcode-framework
Version:
598 lines • 45.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const moment = require("moment");
const sequelize_1 = require("sequelize");
const Common_1 = require("../common/Common");
const ErrorCode_1 = require("../common/ErrorCode");
const BaseService_1 = require("../core/BaseService");
const model_1 = require("../model");
const NumberUtil_1 = require("../util/NumberUtil");
const DCodeWhite_1 = require("../model/dynamicCode/DCodeWhite");
class CodeService extends BaseService_1.default {
async getPasswordTip(mid) {
return model_1.ModelPasswordTip.findByPk(mid);
}
async getBySign(sign) {
const record = await model_1.ModelRecord.findOne({
where: {
sign,
},
});
return record;
}
async getById(id) {
return model_1.DynamicCode.findOne({
where: {
id,
deleted: false,
},
});
}
async getToUrlByDCodeId(id) {
const dCode = await model_1.DynamicCode.findOne({
where: {
id,
status: model_1.DYNAMIC_CODE_STATUS.UN_LOCK,
deleted: false,
invalidAt: {
[sequelize_1.Op.or]: {
[sequelize_1.Op.is]: null,
[sequelize_1.Op.gte]: Date.now(),
},
},
},
});
if (!dCode || dCode.status !== model_1.DYNAMIC_CODE_STATUS.UN_LOCK) {
const url = await this.ctx.service.configService.getConfig('INACTIVE_DYNAMIC_CODE_URL');
return url ? url.url : null;
}
if (dCode.to.type === model_1.DYNAMIC_CODE_TYPE.MODEL) {
return this.ctx.helper.getModelUrl(dCode.to.sign);
}
else {
return dCode.to.url;
}
}
async listDynamicCode(uid) {
const list = await model_1.DynamicCode.findAll({
where: {
uid,
deleted: false,
status: model_1.DYNAMIC_CODE_STATUS.UN_LOCK,
},
});
return list;
}
async getDynamicCode(uid, id) {
const code = await model_1.DynamicCode.findOne({
where: {
id,
uid,
deleted: false,
},
});
return code;
}
async getDynamicCodeById(id) {
const code = await model_1.DynamicCode.findOne({
where: {
id,
deleted: false,
},
});
return code;
}
async createModelCode(uid, code) {
if (!code || !code.styleId) {
throw new ErrorCode_1.HttpError({
message: '参数[styleId]无效',
errorCode: ErrorCode_1.ERROR_CODE.COMMON.PARAMS_INVALID,
status: 400,
});
}
const user = await this.ctx.service.userService.getWithIntegral(uid);
const userIntegral = user.integral.value;
const modelView = await model_1.HtmlModelView.findByPk(code.styleId);
if (!modelView) {
throw new ErrorCode_1.HttpError({
message: '模板不存在',
errorCode: ErrorCode_1.ERROR_CODE.HTML_MODEL.NOT_FOUND,
});
}
if (userIntegral < modelView.integral) {
throw new ErrorCode_1.HttpError({
message: '积分值不足',
errorCode: ErrorCode_1.ERROR_CODE.INTEGRAL.NOT_ENOUGH,
});
}
const sign = await this.genSign();
return await global.sequelize.transaction(async (t) => {
// 创建二维码模板记录
const record = await model_1.ModelRecord.create({
uid,
content: code.content,
title: code.title,
password: code.password,
sign,
musicId: code.musicId || 0,
styleId: code.styleId,
}, {
transaction: t,
});
// 如果模板需要消耗积分,进行相应的逻辑
if (modelView.integral) {
await Promise.all([
// 消减用户积分
user.integral.decrement({ value: modelView.integral }, {
transaction: t,
}),
model_1.UserIntegralRecord.create({
uid,
value: modelView.integral,
latestValue: userIntegral,
type: model_1.INTEGRAL_TYPE.MAKE_EXPEND,
description: '制作模板代码消耗',
meta: {
code,
sign,
},
}, {
transaction: t,
}),
]);
}
return record;
});
}
async createDynamicCode(uid, code) {
if (!code || !code.to) {
throw new ErrorCode_1.HttpError({
message: '参数[to]无效',
errorCode: ErrorCode_1.ERROR_CODE.COMMON.PARAMS_INVALID,
status: 400,
});
}
let sign;
if (NumberUtil_1.isEqual(code.type, model_1.DYNAMIC_CODE_TYPE.MODEL)) {
sign = await this.genSign();
}
return await global.sequelize.transaction(async (t) => {
// 创建二维码模板记录
let to;
if (NumberUtil_1.isEqual(code.type, model_1.DYNAMIC_CODE_TYPE.MODEL)) {
let dataObj = null;
try {
dataObj = JSON.parse(code.to.data);
}
catch (e) {
dataObj = null;
}
// 检查内容是否违规
const checkResult = await this.ctx.service.contentChecker.check(dataObj
? { content: [code.to.data] }
: { content: [code.to.content] });
const record = await model_1.ModelRecord.create({
uid,
content: code.to.content,
title: code.to.title,
password: code.to.password,
sign,
musicId: code.to.musicId || 0,
styleId: code.to.styleId,
data: dataObj,
status: checkResult ? model_1.MODEL_RECORD_STATUS.INVALID : model_1.MODEL_RECORD_STATUS.BLOCK,
}, {
transaction: t,
});
await model_1.ModelPasswordTip.create({
mid: record.id,
tip: code.to.passwordTip,
});
to = {
type: model_1.DYNAMIC_CODE_TYPE.MODEL,
sign: record.sign,
meta: code.to,
};
}
else {
to = {
type: model_1.DYNAMIC_CODE_TYPE.URL,
url: code.to,
meta: code.to,
};
}
// 如果模板需要消耗积分,进行相应的逻辑
const dynamicCode = await model_1.DynamicCode.create({
uid,
name: code.name,
description: code.description,
thumbUrl: code.thumbUrl,
url: code.url,
to,
status: model_1.DYNAMIC_CODE_STATUS.LOCK,
}, {
transaction: t,
});
return dynamicCode;
});
}
async deleteDynamicCode(uid, id, meta) {
const dCode = await model_1.DynamicCode.findByPk(id);
if (!dCode || dCode.deleted) {
throw new ErrorCode_1.HttpError({
message: '动态码不存在',
errorCode: ErrorCode_1.ERROR_CODE.COMMON.NOT_FOUND,
status: 400,
});
}
if (dCode.uid !== uid) {
throw new ErrorCode_1.HttpError({
message: '动态码不属于当前用户,无法进行操作',
errorCode: ErrorCode_1.ERROR_CODE.USER.NOT_BELONG,
status: 400,
});
}
return await global.sequelize.transaction(async (t) => {
dCode.set('deleted', true);
await model_1.ModelRecord.update({
deleted: true,
meta,
}, {
where: {
dynamicId: id,
},
transaction: t,
});
await dCode.save({ transaction: t });
return dCode;
});
}
async isValidCodes(uid, ids = []) {
const now = moment().format('YYYY-MM-DD HH:mm:ss');
const codes = await model_1.DynamicCode.findAll({
where: {
id: {
[sequelize_1.Op.in]: ids,
},
uid,
invalidAt: {
[sequelize_1.Op.or]: {
[sequelize_1.Op.is]: null,
[sequelize_1.Op.gt]: now,
},
},
status: model_1.DYNAMIC_CODE_STATUS.UN_LOCK,
deleted: false,
},
});
return codes.length === ids.length;
}
/**
* 更新动态码指向
* @param uid
* @param id
* @param code
* @param transaction
*/
async updateDynamicCodeTo(uid, id, code, transaction) {
if (!code || !code.to) {
throw new ErrorCode_1.HttpError({
message: '必要参数[code]无效',
errorCode: ErrorCode_1.ERROR_CODE.COMMON.PARAMS_INVALID,
status: 400,
});
}
const dCode = await model_1.DynamicCode.findByPk(id);
if (!dCode || dCode.deleted) {
throw new ErrorCode_1.HttpError({
message: '动态码不存在',
errorCode: ErrorCode_1.ERROR_CODE.COMMON.NOT_FOUND,
status: 400,
});
}
if (dCode.invalidAt && moment(dCode.invalidAt).isBefore(Date.now())) {
throw new ErrorCode_1.HttpError({
message: '动态码已经失效, 请续费',
errorCode: ErrorCode_1.ERROR_CODE.CODE.INVALID,
status: 400,
});
}
const exec = async (t) => {
// 如果to包含任何内容,则更新to相关信息
let sign;
// @ts-ignore
if (NumberUtil_1.isEqual(code.type, model_1.DYNAMIC_CODE_TYPE.MODEL)) {
sign = await this.genSign();
}
// 如果原指向是模板,禁用原模板
if (NumberUtil_1.isEqual(dCode.to.type, model_1.DYNAMIC_CODE_TYPE.MODEL)) {
await model_1.ModelRecord.update({
status: model_1.MODEL_RECORD_STATUS.INVALID,
}, {
where: {
sign: dCode.to.sign,
},
transaction: t,
});
}
// 创建二维码模板记录
let to;
if (NumberUtil_1.isEqual(code.type, model_1.DYNAMIC_CODE_TYPE.MODEL)) {
let dataObj = null;
try {
dataObj = JSON.parse(code.to.data);
}
catch (e) {
dataObj = null;
}
// 检查内容是否违规
const checkResult = await this.ctx.service.contentChecker.check(dataObj
? { content: [code.to.data] }
: { content: [code.to.content] });
const invalidTime = moment.utc(dCode.invalidAt).format('YYYY-MM-DD HH:mm:ss');
const record = await model_1.ModelRecord.create({
uid,
content: code.to.content,
title: code.to.title,
password: code.to.password,
sign,
dynamicId: dCode.id,
musicId: code.to.musicId || 0,
styleId: code.to.styleId,
status: checkResult ? model_1.MODEL_RECORD_STATUS.VALID : model_1.MODEL_RECORD_STATUS.BLOCK,
data: dataObj,
invalidAt: dCode.invalidAt ? invalidTime : null,
}, {
transaction: t,
});
await model_1.ModelPasswordTip.create({
mid: record.id,
tip: code.to.passwordTip,
});
to = {
type: model_1.DYNAMIC_CODE_TYPE.MODEL,
sign: record.sign,
meta: code.to,
};
}
else {
to = {
type: model_1.DYNAMIC_CODE_TYPE.URL,
url: code.to,
meta: code.to,
};
}
dCode.set('to', to);
await dCode.save({
transaction: t,
});
return dCode;
};
if (transaction) {
return await exec(transaction);
}
else {
return await global.sequelize.transaction(async (t) => {
return await exec(t);
});
}
}
async updateDynamicCode(uid, id, code) {
const dCode = await model_1.DynamicCode.findByPk(id);
if (!dCode || dCode.deleted) {
throw new ErrorCode_1.HttpError({
message: '动态码不存在',
errorCode: ErrorCode_1.ERROR_CODE.COMMON.NOT_FOUND,
status: 400,
});
}
if (!NumberUtil_1.isEqual(dCode.uid, uid)) {
throw new ErrorCode_1.HttpError({
message: '操作资源与用户不匹配',
errorCode: ErrorCode_1.ERROR_CODE.PERMISSION.DATA_ACCESS_DENIED,
status: 403,
});
}
if (dCode.invalidAt && moment(dCode.invalidAt).isBefore(Date.now())) {
throw new ErrorCode_1.HttpError({
message: '动态码已经失效, 请续费',
errorCode: ErrorCode_1.ERROR_CODE.CODE.INVALID,
status: 400,
});
}
return await global.sequelize.transaction(async (t) => {
dCode.updateProperty(code, { exclude: ['to'] });
await dCode.save({
transaction: t,
});
return dCode;
});
}
/**
* 通过时长代码获取
* @param code
* @param platform
*/
async getDynamicCodePayment(code, platform) {
let config = await this.ctx.app.redis.get(Common_1.REDIS_KEY.DYNAMIC_CODE_PAYMENT);
config = config ? JSON.parse(config) : config;
if (!config) {
await this.initDynamicCodePayment();
config = await this.ctx.app.redis.get(Common_1.REDIS_KEY.DYNAMIC_CODE_PAYMENT);
config = config ? JSON.parse(config) : config;
}
// 通过平台过滤
if (config && platform !== undefined) {
Object.keys(config).forEach((c) => {
if (config && config[c].platform !== platform && config[c].platform !== null) {
delete config[c];
}
});
}
return code ? config[code] : config;
}
/**
* 获取动态码价格信息
* @param _id 动态码ID
* @param code 动态码购买代码
* @param platform
*/
async getDCodePrice(_id, code, platform) {
const paymentInfo = await this.getDynamicCodePayment(code, platform);
const price = [];
if (paymentInfo) {
price.push({
payType: paymentInfo.payType,
price: paymentInfo.payment,
payment: paymentInfo,
});
}
return price;
}
/**
* 获取动态码修改指向价格
* @param id
* @param platform
*/
async getDCodeChangeToPrice(id, platform) {
if (!await this.ctx.app.redis.exists(Common_1.REDIS_KEY.DYNAMIC_CODE_CHANGE_PAYMENT)) {
await this.initDynamicCodeChangePayment();
}
let rArray = await this.ctx.app.redis.zrange(Common_1.REDIS_KEY.DYNAMIC_CODE_CHANGE_PAYMENT, 0, 100);
rArray = rArray.map((r) => JSON.parse(r));
const code = id ? await this.getDynamicCodeById(id) : null;
const payments = rArray.filter((r) => r.platform === null || r.platform === platform);
const price = [];
payments.forEach((p) => {
price.push({
payType: p.payType,
price: code && !code.invalidAt ? 0 : p.price,
payment: {},
});
});
return price;
}
/**
* 获取动态码所有支付选项
*/
async getDCodePrices(platform) {
const config = await this.getDynamicCodePayment(undefined, platform);
return Object.values(config);
}
/**
* 激活动态码
* @param id 动态码ID
* @param code 持续时间代码
* @param t 事务实例
*/
async activeDCodePrice(id, code, t) {
const dynamicCode = await model_1.DynamicCode.findByPk(id);
if (!dynamicCode) {
throw new ErrorCode_1.HttpError({
errorCode: ErrorCode_1.ERROR_CODE.COMMON.NOT_FOUND,
message: '动态码不存在',
status: 400,
});
}
const paymentInfo = await this.getDynamicCodePayment(code);
// 计算当前过期时间,如果已经过期,则以当前时间作为起始时间
const expiredAt = !dynamicCode.invalidAt || moment(dynamicCode.invalidAt).isBefore(Date.now())
? moment() : moment(dynamicCode.invalidAt);
// 计算新的过期时间
const newExpiredAt = expiredAt.add(paymentInfo.duration, 'm').format('YYYY-MM-DD HH:mm:ss');
dynamicCode.set('status', model_1.DYNAMIC_CODE_STATUS.UN_LOCK);
// @ts-ignore
// 如果duration是0,表示是永久,则过期时间为null
dynamicCode.set('invalidAt', paymentInfo.duration ? newExpiredAt : null);
await dynamicCode.save({ transaction: t });
if (dynamicCode.to.type === model_1.DYNAMIC_CODE_TYPE.MODEL) {
const record = await this.getBySign(dynamicCode.to.sign);
if (record) {
if (record.status !== model_1.MODEL_RECORD_STATUS.BLOCK) {
record.set('status', model_1.MODEL_RECORD_STATUS.VALID);
}
// @ts-ignore
// 如果duration是0,表示是永久,则过期时间为null
record.set('invalidAt', paymentInfo.duration ? newExpiredAt : null);
await record.save({ transaction: t });
}
}
return dynamicCode;
}
/**
* 给动态码添加拥有者
* @param id
* @param uid
* @param t
*/
async addOwner(id, uid, t) {
const dCode = await model_1.DynamicCode.findByPk(id);
if (!dCode) {
throw new ErrorCode_1.HttpError({
message: '动态码不存在',
errorCode: ErrorCode_1.ERROR_CODE.COMMON.NOT_FOUND,
status: 404,
});
}
if (dCode.uid) {
throw new ErrorCode_1.HttpError({
message: '动态码已具有所有者',
errorCode: ErrorCode_1.ERROR_CODE.CODE.HAS_OWNER,
status: 404,
});
}
const now = new Date();
dCode.changed('createdAt', true);
dCode.set({ uid, status: model_1.DYNAMIC_CODE_STATUS.UN_LOCK, createdAt: now }, { raw: true });
await dCode.save({ fields: ['uid', 'status', 'createdAt'], transaction: t });
return dCode;
}
async isWhite(id) {
return !!await DCodeWhite_1.DCodeWhite.findByPk(id);
}
async initDynamicCodePayment() {
const payments = await model_1.DynamicCodePayment.findAll();
const result = {};
payments.forEach((p) => {
result[p.code] = {
code: p.code,
payType: p.payType,
duration: p.duration,
payment: p.payment,
description: p.description,
platform: p.platform,
};
});
await this.ctx.app.redis.set(Common_1.REDIS_KEY.DYNAMIC_CODE_PAYMENT, JSON.stringify(result), 'EX', 60 * 60 * 24);
}
async initDynamicCodeChangePayment() {
const payments = await model_1.DCodeChangePayment.findAll();
const args = [];
payments.forEach((r, index) => {
args.push(index);
args.push(JSON.stringify(r));
});
await this.ctx.app.redis.zadd(Common_1.REDIS_KEY.DYNAMIC_CODE_CHANGE_PAYMENT, ...args);
}
async genSign() {
let randomStr = this.ctx.helper.randomStr(false, 6);
let i = 0;
do {
const codeItem = await this.getBySign(randomStr);
if (!codeItem) {
return randomStr;
}
else {
randomStr += this.ctx.helper.randomStr(false, 1);
i++;
}
} while (i < 5);
throw new ErrorCode_1.HttpError({
errorCode: ErrorCode_1.ERROR_CODE.CODE.CREATE_SIGN_ERROR,
message: '生成签名失败',
status: 500,
});
}
}
exports.default = CodeService;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29kZVNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJDb2RlU2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLGlDQUFpQztBQUNqQyx5Q0FBNkI7QUFDN0IsNkNBQTJDO0FBQzNDLG1EQUEwRDtBQUMxRCxxREFBOEM7QUFDOUMsb0NBWWtCO0FBRWxCLG1EQUEyQztBQUMzQyxnRUFBMkQ7QUFFM0QsTUFBcUIsV0FBWSxTQUFRLHFCQUFXO0lBQ3pDLEtBQUssQ0FBQyxjQUFjLENBQUMsR0FBRztRQUMzQixPQUFPLHdCQUFnQixDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRU0sS0FBSyxDQUFDLFNBQVMsQ0FBQyxJQUFJO1FBQ3ZCLE1BQU0sTUFBTSxHQUFHLE1BQU0sbUJBQVcsQ0FBQyxPQUFPLENBQUM7WUFDckMsS0FBSyxFQUFFO2dCQUNILElBQUk7YUFDUDtTQUNKLENBQUMsQ0FBQztRQUVILE9BQU8sTUFBTSxDQUFDO0lBQ2xCLENBQUM7SUFFTSxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQVU7UUFDM0IsT0FBTyxtQkFBVyxDQUFDLE9BQU8sQ0FBQztZQUN2QixLQUFLLEVBQUU7Z0JBQ0gsRUFBRTtnQkFDRixPQUFPLEVBQUUsS0FBSzthQUNqQjtTQUNKLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFTSxLQUFLLENBQUMsaUJBQWlCLENBQUMsRUFBVTtRQUNyQyxNQUFNLEtBQUssR0FBRyxNQUFNLG1CQUFXLENBQUMsT0FBTyxDQUFDO1lBQ3BDLEtBQUssRUFBRTtnQkFDSCxFQUFFO2dCQUNGLE1BQU0sRUFBRSwyQkFBbUIsQ0FBQyxPQUFPO2dCQUNuQyxPQUFPLEVBQUUsS0FBSztnQkFDZCxTQUFTLEVBQUU7b0JBQ1AsQ0FBQyxjQUFFLENBQUMsRUFBRSxDQUFDLEVBQUU7d0JBQ0wsQ0FBQyxjQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsSUFBSTt3QkFDYixDQUFDLGNBQUUsQ0FBQyxH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