oak-general-business/es/context/BackendRuntimeContext.js

254 lines
8.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { assert } from 'oak-domain/lib/utils/assert';
import { OakTokenExpiredException, OakUserDisabledException, } from '../types/Exception';
import { OakUnloggedInException, } from 'oak-domain/lib/types/Exception';
import { ROOT_TOKEN_ID } from '../constants';
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
import { applicationProjection } from '../types/Projection';
import { getMpUnlimitWxaCode } from '../aspects/wechatQrCode';
import { BackendRuntimeContext as BRC } from 'oak-frontend-base';
import { cloneDeep } from 'oak-domain/lib/utils/lodash';
/**
* general数据结构要求的后台上下文
*/
export class BackendRuntimeContext extends BRC {
application;
token;
amIRoot;
amIReallyRoot;
rootMode;
userId;
async refineOpRecords() {
for (const opRecord of this.opRecords) {
if (opRecord.a === 's') {
const { d } = opRecord;
for (const entity in d) {
if (entity === 'wechatQrCode') {
// todo 小程序码此时去微信服务器获得码数据
const wechatQrCodeListObj = d[entity];
for (const id in wechatQrCodeListObj) {
const wechatQrCodeData = wechatQrCodeListObj[id];
if (wechatQrCodeData.hasOwnProperty('buffer') &&
wechatQrCodeData.type === 'wechatMpWxaCode') {
const buffer = await getMpUnlimitWxaCode(id, this);
Object.assign(wechatQrCodeData, {
buffer,
});
}
}
}
else if (['application', 'system', 'platform'].includes(entity)) {
// todo 删除掉config中的敏感返回信息
}
}
}
}
}
async setTokenValue(tokenValue, userId) {
if (tokenValue) {
// 前台传递
const result = await this.select('token', {
data: {
id: 1,
ableState: 1,
user: {
id: 1,
userState: 1,
isRoot: 1,
},
userId: 1,
value: 1,
player: {
id: 1,
isRoot: 1,
},
},
filter: {
$or: [
{
value: tokenValue,
},
{
oldValue: tokenValue,
refreshedAt: {
$gte: Date.now() - 60 * 1000,
},
},
],
},
}, {
dontCollect: true,
blockTrigger: true,
});
if (result.length === 0) {
console.log(`构建BackendRuntimeContext对应tokenValue「${tokenValue}找不到相关的user`);
throw new OakTokenExpiredException();
}
const token = result[0];
if (token.ableState === 'disabled') {
console.log(`构建BackendRuntimeContext对应tokenValue「${tokenValue}已经被disable`);
throw new OakTokenExpiredException();
}
const { user, player } = token;
this.amIRoot = user?.isRoot;
this.amIReallyRoot = player?.isRoot;
this.token = token;
this.userId = token.userId;
return;
}
if (userId) {
// 若是后台环境用userId来查询处理
const [user] = await this.select('user', {
data: {
id: 1,
isRoot: 1,
},
filter: { id: userId },
}, { dontCollect: true });
assert(user, '初始化context时有userId但查询不到user');
this.amIRoot = user.isRoot;
this.amIReallyRoot = user.isRoot;
this.userId = userId;
}
}
async setApplication(appId) {
const result = await this.select('application', {
data: cloneDeep(applicationProjection),
filter: {
id: appId,
},
}, {
dontCollect: true,
blockTrigger: true,
});
assert(result.length > 0, `构建BackendRuntimeContext对应appId「${appId}」找不到application`);
this.application = result[0];
}
async initialize(data, later) {
await super.initialize(data);
if (data) {
const closeRootMode = this.openRootMode();
try {
const { a: appId, t: tokenValue, rm, userId } = data;
const promises = [];
if (appId) {
promises.push(this.setApplication(appId));
}
if (tokenValue || userId) {
promises.push(this.setTokenValue(tokenValue, userId));
}
if (promises.length > 0) {
await Promise.all(promises);
}
if (!rm) {
closeRootMode();
}
}
catch (err) {
closeRootMode();
throw err;
}
}
else {
// 否则是后台模式默认用root
this.rootMode = true;
}
}
getApplicationId() {
return this.application?.id;
}
getSystemId() {
return this.application?.systemId;
}
getApplication() {
return this.application;
}
openRootMode() {
if (this.rootMode) {
return () => undefined;
}
this.rootMode = true;
return () => (this.rootMode = false);
}
getTokenValue(allowUnloggedIn) {
if (this.rootMode) {
return ROOT_TOKEN_ID;
}
if (!this.token && !allowUnloggedIn) {
throw new OakUnloggedInException();
}
return this.token?.value;
}
getToken(allowUnloggedIn) {
if (!this.token && !allowUnloggedIn) {
throw new OakUnloggedInException();
}
if (this.token) {
const { userState } = this.token.user;
if (['disabled', 'merged'].includes(userState) &&
!this.isReallyRoot()) {
throw new OakUserDisabledException();
}
}
return this.token;
}
getCurrentUserId(allowUnloggedIn) {
if (this.userId) {
return this.userId;
}
const token = this.getToken(allowUnloggedIn);
return token?.userId;
}
setCurrentUserId(userId) {
assert(this.isReallyRoot);
this.userId = userId;
}
async getSerializedData() {
const data = await super.getSerializedData();
// 后台物化上下文直接存userId;
return {
...data,
a: this.application?.id,
rm: this.rootMode,
userId: this.getCurrentUserId(true),
};
}
isRoot() {
if (this.rootMode) {
return true;
}
return !!this.amIRoot;
}
isReallyRoot() {
return !!this.amIReallyRoot;
}
async sendMessage(data) {
return this.operate('message', {
id: await generateNewIdAsync(),
action: 'create',
data,
}, {
dontCollect: true,
});
}
allowUserUpdate() {
if (this.isReallyRoot()) {
return true;
}
const userInfo = this.token?.user;
if (userInfo) {
const { userState } = userInfo;
if (userState === 'disabled') {
throw new OakUserDisabledException('您的帐号已经被禁用,请联系客服');
}
else if (['merged'].includes(userState)) {
throw new OakTokenExpiredException('您的登录状态有异常,请重新登录 ');
}
else {
assert(userState === 'normal' || userState === 'shadow');
}
return true;
}
throw new OakUnloggedInException('您尚未登录');
}
}