wechatQrCode的逻辑实现(部分)

This commit is contained in:
Xu Chang 2022-05-30 18:35:13 +08:00
parent b0ff174e44
commit 2f580ad8eb
34 changed files with 435 additions and 78 deletions

View File

@ -6,12 +6,18 @@ export declare abstract class GeneralRuntimeContext<ED extends EntityDict> exten
private getTokenFn;
private scene;
constructor(store: RowStore<ED, GeneralRuntimeContext<ED>>, appId: string, getToken: () => Promise<string | undefined>, scene: string);
getApplicationId(): string;
getApplication(): Promise<import("oak-domain/lib/types").SelectRowShape<import("oak-app-domain/Application/Schema").Schema, {
id: 1;
name: 1;
config: 1;
type: 1;
systemId: 1;
system: {
id: 1;
name: 1;
config: 1;
};
}>>;
getToken(): Promise<import("oak-domain/lib/types").SelectRowShape<ED["token"]["Schema"], {
id: 1;

View File

@ -12,6 +12,9 @@ class GeneralRuntimeContext extends UniversalContext_1.UniversalContext {
this.getTokenFn = getToken;
this.scene = scene;
}
getApplicationId() {
return this.applicationId;
}
async getApplication() {
const { result: [application] } = await this.rowStore.select('application', {
data: {
@ -20,6 +23,11 @@ class GeneralRuntimeContext extends UniversalContext_1.UniversalContext {
config: 1,
type: 1,
systemId: 1,
system: {
id: 1,
name: 1,
config: 1,
}
},
filter: {
id: this.applicationId,

View File

@ -24,7 +24,7 @@ async function getUploadInfo(params, context) {
}, context);
try {
const { config: systemConfig } = system;
const originConfig = systemConfig?.Cos[origin];
const originConfig = systemConfig.Cos[origin];
const instance = new ExternalUploadClazz[origin](originConfig);
const uploadInfo = await instance.getUploadInfo(fileName);
return uploadInfo;

21
lib/aspects/wechatQrCode.d.ts vendored Normal file
View File

@ -0,0 +1,21 @@
import { EntityDict } from "oak-app-domain";
import { WechatQrCodeProps } from 'oak-app-domain/WechatQrCode/Schema';
import { GeneralRuntimeContext } from "../RuntimeContext";
export declare function createWechatQrCode<ED extends EntityDict, T extends keyof ED, Cxt extends GeneralRuntimeContext<ED>>(options: {
entity: T;
entityId: string;
applicationId: string;
tag?: string;
lifetimeLength?: number;
permanent?: boolean;
props: WechatQrCodeProps;
}, context: Cxt): Promise<Omit<Omit<import("oak-app-domain/WechatQrCode/Schema").OpSchema, "applicationId" | "entity" | "entityId">, import("oak-domain/lib/types").InstinctiveAttributes> & {
id: string;
} & {
applicationId: string;
application?: import("oak-app-domain/Application/Schema").UpdateOperation | undefined;
} & {
[K: string]: any;
} & {
[k: string]: any;
}>;

View File

@ -0,0 +1,61 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createWechatQrCode = void 0;
const assert_1 = __importDefault(require("assert"));
async function createWechatQrCode(options, context) {
const { entity, entityId, applicationId, tag, lifetimeLength, permanent, props } = options;
const { type: appType, config } = await context.getApplication();
if (appType === 'wechatMp') {
const { qrCodePrefix } = config;
const id = await generateNewId();
if (qrCodePrefix) {
// 设置了域名跳转,优先使用域名 + id来生成对应的ur
const data = {
id,
type: 'wechatMpDomainUrl',
tag,
entity,
entityId,
applicationId,
permanent: true,
url: `${qrCodePrefix}/id`,
expired: false,
props,
};
await context.rowStore.operate('wechatQrCode', {
action: 'create',
data,
}, context);
return data;
}
else {
// 没有域名跳转,使用小程序码
// todo这里如果有同组的公众号应该优先使用公众号的关注链接
const data = {
id,
type: 'wechatMpWxaCode',
tag,
entity,
entityId,
applicationId,
permanent: false,
expired: false,
props,
};
await context.rowStore.operate('wechatQrCode', {
action: 'create',
data,
}, context);
return data;
}
}
else {
(0, assert_1.default)(appType === 'wechatPublic');
// 还未实现,记得
throw new Error('method not implemented yet');
}
}
exports.createWechatQrCode = createWechatQrCode;

5
lib/constants.d.ts vendored
View File

@ -1,2 +1,7 @@
export declare const ROOT_ROLE_ID = "oak-root-role";
export declare const ROOT_USER_ID = "oak-root-user";
export declare const DefaultConfig: {
userEntityGrant: {
lifetimeLength: number;
};
};

View File

@ -1,5 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ROOT_USER_ID = exports.ROOT_ROLE_ID = void 0;
exports.DefaultConfig = exports.ROOT_USER_ID = exports.ROOT_ROLE_ID = void 0;
exports.ROOT_ROLE_ID = 'oak-root-role';
exports.ROOT_USER_ID = 'oak-root-user';
exports.DefaultConfig = {
userEntityGrant: {
lifetimeLength: 3600 * 1000,
},
};

View File

@ -6,6 +6,7 @@ export declare type WechatMpConfig = {
type: 'wechatMp';
appId: string;
appSecret: string;
qrCodePrefix?: string;
};
export declare type WebConfig = {
type: 'web';

View File

@ -1,8 +1,8 @@
import { String, Text } from 'oak-domain/lib/types/DataType';
import { EntityShape } from 'oak-domain/lib/types/Entity';
export declare type SystemConfig = {
Cos: {
qiniu: {
Cos?: {
qiniu?: {
accessKey: string;
secretKey: string;
uploadHost: string;
@ -10,11 +10,14 @@ export declare type SystemConfig = {
domain: string;
};
};
Map: {
amap: {
Map?: {
amap?: {
webApiKey: string;
};
};
UserEntityGrant?: {
lifetimeLength: number;
};
};
export interface Schema extends EntityShape {
name: String<32>;

View File

@ -1,4 +1,4 @@
import { String, Text } from 'oak-domain/lib/types/DataType';
import { String, Text, Datetime } from 'oak-domain/lib/types/DataType';
import { EntityShape } from 'oak-domain/lib/types/Entity';
import { Schema as User } from './User';
import { Schema as WechatQrCode } from './WechatQrCode';
@ -8,8 +8,9 @@ export interface Schema extends EntityShape {
relation: String<32>;
action: String<32>;
remark?: Text;
uuid: String<32>;
granter: User;
grantee?: User;
files: Array<WechatQrCode>;
expiresAt?: Datetime;
expired?: Boolean;
}

View File

@ -1,11 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const IActionDef = {
stm: {
confirm: ['init', 'expire'],
},
is: 'init'
};
const indexes = [
{
name: 'index_entity_entityId',
@ -22,8 +16,11 @@ const indexes = [
name: 'index_uuid',
attributes: [
{
name: 'uuid',
name: 'expired',
},
{
name: 'expiresAt',
}
],
},
];

View File

@ -1,18 +1,22 @@
import { String, Text, Datetime, Boolean } from 'oak-domain/lib/types/DataType';
import { EntityShape } from 'oak-domain/lib/types/Entity';
import { Schema as Application } from './Application';
export declare type WechatQrCodeProps = {
pathname: string;
props?: Record<string, any>;
state?: Record<string, any>;
};
export interface Schema extends EntityShape {
entity: String<32>;
entityId: String<64>;
type?: String<32>;
expiresAt: Datetime;
expired: Boolean;
autoExtend: Boolean;
sceneStr?: Text;
type: 'wechatMpDomainUrl' | 'wechatMpWxaCode' | 'wechatPublic' | 'wechatPublicForMp';
tag?: String<32>;
expiresAt?: Datetime;
expired?: Boolean;
ticket?: Text;
url?: String<64>;
isPermanent: Boolean;
permanent: Boolean;
buffer?: Text;
application: Application;
props?: Object;
props: WechatQrCodeProps;
}

View File

@ -2,7 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true });
const indexes = [
{
name: 'index_entity_entityId',
name: 'index_entity_entityId_tag',
attributes: [
{
name: 'entity',
@ -10,6 +10,9 @@ const indexes = [
{
name: 'entityId',
},
{
name: 'tag',
}
],
},
{

View File

@ -3,7 +3,7 @@ import { Feature } from 'oak-frontend-base';
import { Aspect, Context, DeduceCreateOperationData } from 'oak-domain/lib/types';
export declare class ExtraFile<ED extends EntityDict, Cxt extends Context<ED>, AD extends Record<string, Aspect<ED, Cxt>>> extends Feature<ED, Cxt, AD> {
constructor();
upload(extraFile: DeduceCreateOperationData<ED['extraFile']['Schema']>, scene: string): Promise<{
upload(extraFile: DeduceCreateOperationData<EntityDict['extraFile']['OpSchema']>, scene: string): Promise<{
url: string;
bucket: string;
}>;

View File

@ -1,4 +1,4 @@
import { EntityDict as BaseEntityDict } from 'oak-app-domain/EntityDict';
import { Trigger } from 'oak-domain/lib/types';
declare const _default: (Trigger<BaseEntityDict, "address", import("..").GeneralRuntimeContext<BaseEntityDict>> | Trigger<BaseEntityDict, "user", import("..").GeneralRuntimeContext<BaseEntityDict>> | Trigger<BaseEntityDict, "userEntityGrant", import("..").GeneralRuntimeContext<BaseEntityDict>>)[];
declare const _default: (Trigger<BaseEntityDict, "address", import("..").GeneralRuntimeContext<BaseEntityDict>> | Trigger<BaseEntityDict, "user", import("..").GeneralRuntimeContext<BaseEntityDict>> | Trigger<BaseEntityDict, "userEntityGrant", import("..").GeneralRuntimeContext<BaseEntityDict>> | Trigger<BaseEntityDict, "wechatQrCode", import("..").GeneralRuntimeContext<BaseEntityDict>>)[];
export default _default;

View File

@ -6,4 +6,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
const address_1 = __importDefault(require("./address"));
const user_1 = __importDefault(require("./user"));
const userEntityGrant_1 = __importDefault(require("./userEntityGrant"));
exports.default = [...address_1.default, ...user_1.default, ...userEntityGrant_1.default];
const wechatQrCode_1 = __importDefault(require("./wechatQrCode"));
exports.default = [...address_1.default, ...user_1.default, ...userEntityGrant_1.default, ...wechatQrCode_1.default];

View File

@ -6,9 +6,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
const lodash_1 = require("lodash");
const types_1 = require("oak-domain/lib/types");
const assert_1 = __importDefault(require("assert"));
const constants_1 = require("../constants");
const wechatQrCode_1 = require("../aspects/wechatQrCode");
const triggers = [
{
name: '当创建userEntityGrant时,查询是否有未过期的实体',
name: '当创建userEntityGrant时,查询是否有未过期可重用的对象',
entity: 'userEntityGrant',
action: 'create',
when: 'before',
@ -16,8 +18,9 @@ const triggers = [
const { data, filter } = operation;
const fn = async (userEntityGrantData) => {
const { userId } = (await context.getToken());
const { id: applicationId, config: appConfig, system: { config: SystemConfig } } = (await context.getApplication());
(0, assert_1.default)(userId);
const { action, entity, entityId, relation } = userEntityGrantData;
const { action, entity, entityId, relation, id } = userEntityGrantData;
const { result } = await context.rowStore.select('userEntityGrant', {
data: {
id: 1,
@ -25,11 +28,14 @@ const triggers = [
entity: 1,
entityId: 1,
relation: 1,
iState: 1,
expired: 1,
granterId: 1,
},
filter: {
iState: 'init',
expired: false,
expiresAt: {
$gt: Date.now() - 600 * 1000,
},
action,
entity,
entityId,
@ -42,9 +48,26 @@ const triggers = [
if (result.length) {
throw new types_1.OakCongruentRowExists(result[0], '有可重用的userEntityGrant');
}
const expiresAt = Date.now() + (SystemConfig.UserEntityGrant?.lifetimeLength || constants_1.DefaultConfig.userEntityGrant.lifetimeLength);
(0, lodash_1.assign)(userEntityGrantData, {
granterId: userId,
expiresAt,
expired: false,
});
// 如果是微信体系的应用为之创建一个默认的weChatQrCode
if (['wechatPublic', 'wechatMp'].includes(appConfig.type)) {
await (0, wechatQrCode_1.createWechatQrCode)({
entity: 'userEntityGrant',
entityId: id,
applicationId,
props: {
pathname: 'pages/userEntityGrant/confirm',
props: {
oakId: id,
},
}
}, context);
}
};
if (data instanceof Array) {
(0, assert_1.default)('授权不存在一对多的情况');

5
lib/triggers/wechatQrCode.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import { EntityDict } from 'oak-app-domain/EntityDict';
import { Trigger } from 'oak-domain/lib/types/Trigger';
import { GeneralRuntimeContext } from '../RuntimeContext';
declare const triggers: Trigger<EntityDict, 'wechatQrCode', GeneralRuntimeContext<EntityDict>>[];
export default triggers;

View File

@ -0,0 +1,47 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const assert_1 = __importDefault(require("assert"));
const oak_wechat_sdk_1 = require("oak-wechat-sdk");
const uuid_1 = require("oak-domain/lib/utils/uuid");
const lodash_1 = require("lodash");
const triggers = [
{
name: '选择userEntityGrant时动态生成需要的数据',
entity: 'wechatQrCode',
action: 'select',
when: 'after',
fn: async ({ result }, context, params) => {
let count = 0;
const application = await context.getApplication();
const { type, config } = application;
(0, assert_1.default)(type === 'wechatMp' || config.type === 'wechatMp');
const config2 = config;
const { appId, appSecret } = config2;
for (const code of result) {
const { type, expired, url, id } = code;
if (type === 'wechatMpWxaCode') {
// 小程序码去实时获取(暂时不考虑缓存)
const wechatInstance = oak_wechat_sdk_1.WechatSDK.getInstance(appId, appSecret, 'wechatMp');
const buffer = await wechatInstance.getMpUnlimitWxaCode({
scene: (0, uuid_1.shrinkUuidTo32Bytes)(id),
page: 'pages/index/index', // todo这里用其它的页面微信服务器拒绝因为没发布。应该是 pages/wechatQrCode/scan/index
});
// 把arrayBuffer转成字符串返回
const str = String.fromCharCode(...new Uint8Array(buffer));
(0, lodash_1.assign)(code, {
buffer: str,
});
}
else if (expired) {
// 如果过期了,在这里生成新的临时码并修改值(公众号)
throw new Error('not implemented yet');
}
}
return count;
}
},
];
exports.default = triggers;

View File

@ -17,6 +17,10 @@ export abstract class GeneralRuntimeContext<ED extends EntityDict> extends Unive
this.scene = scene;
}
getApplicationId() {
return this.applicationId;
}
async getApplication () {
const { result: [application] } = await this.rowStore.select('application', {
data: {
@ -24,12 +28,28 @@ export abstract class GeneralRuntimeContext<ED extends EntityDict> extends Unive
name: 1,
config: 1,
type: 1,
systemId: 1,
systemId: 1,
system: {
id: 1,
name: 1,
config: 1,
}
},
filter: {
id: this.applicationId,
}
}, this) as SelectionResult<EntityDict['application']['Schema'], {id: 1, name: 1, config: 1, type: 1, systemId: 1}>;
}, this) as SelectionResult<EntityDict['application']['Schema'], {
id: 1,
name: 1,
config: 1,
type: 1,
systemId: 1,
system: {
id: 1,
name: 1,
config: 1,
},
}>;
return application;
}

View File

@ -25,7 +25,7 @@ export async function getUploadInfo<ED extends EntityDict, Cxt extends GeneralRu
}, context);
try {
const { config: systemConfig } = system;
const originConfig = (systemConfig as SystemConfig)?.Cos[
const originConfig = (systemConfig as SystemConfig).Cos![
origin as keyof typeof systemConfig
];

View File

@ -0,0 +1,70 @@
import assert from "assert";
import { EntityDict } from "oak-app-domain";
import { WechatMpConfig } from "oak-app-domain/Application/Schema";
import { CreateOperationData as CreateWechatQrcodeData, WechatQrCodeProps } from 'oak-app-domain/WechatQrCode/Schema';
import { GeneralRuntimeContext } from "../RuntimeContext";
export async function createWechatQrCode<ED extends EntityDict, T extends keyof ED, Cxt extends GeneralRuntimeContext<ED>>(options: {
entity: T;
entityId: string;
applicationId: string;
tag?: string;
lifetimeLength?: number;
permanent?: boolean;
props: WechatQrCodeProps;
}, context: Cxt) {
const { entity, entityId, applicationId, tag, lifetimeLength, permanent, props } = options;
const { type: appType, config } = await context.getApplication();
if (appType === 'wechatMp') {
const { qrCodePrefix } = (<WechatMpConfig>config);
const id = await generateNewId();
if (qrCodePrefix) {
// 设置了域名跳转,优先使用域名 + id来生成对应的ur
const data: CreateWechatQrcodeData = {
id,
type: 'wechatMpDomainUrl',
tag,
entity,
entityId,
applicationId,
permanent: true,
url: `${qrCodePrefix}/id`,
expired: false,
props,
};
await context.rowStore.operate('wechatQrCode', {
action: 'create',
data,
}, context);
return data;
}
else {
// 没有域名跳转,使用小程序码
// todo这里如果有同组的公众号应该优先使用公众号的关注链接
const data: CreateWechatQrcodeData = {
id,
type: 'wechatMpWxaCode',
tag,
entity,
entityId,
applicationId,
permanent: false,
expired: false,
props,
};
await context.rowStore.operate('wechatQrCode', {
action: 'create',
data,
}, context);
return data;
}
}
else {
assert(appType === 'wechatPublic');
// 还未实现,记得
throw new Error('method not implemented yet');
}
}

View File

@ -1,2 +1,8 @@
export const ROOT_ROLE_ID = 'oak-root-role';
export const ROOT_USER_ID = 'oak-root-user';
export const ROOT_USER_ID = 'oak-root-user';
export const DefaultConfig = {
userEntityGrant: {
lifetimeLength: 3600 * 1000,
},
};

View File

@ -7,6 +7,7 @@ export type WechatMpConfig = {
type: 'wechatMp';
appId: string;
appSecret: string;
qrCodePrefix?: string; // 扫描二维码跳转的前缀(在小程序后台配置必须统一跳转到weCharQrCode/scan/index)
};
export type WebConfig = {

View File

@ -2,8 +2,8 @@ import { String, Int, Datetime, Image, Boolean, Text } from 'oak-domain/lib/type
import { EntityShape } from 'oak-domain/lib/types/Entity';
export type SystemConfig = {
Cos: {
qiniu: {
Cos?: {
qiniu?: {
accessKey: string;
secretKey: string;
uploadHost: string; //七牛上传域名
@ -11,11 +11,14 @@ export type SystemConfig = {
domain: string;
};
};
Map: {
amap: {
Map?: {
amap?: {
webApiKey: string; // 高德访问rest服务接口的key
};
};
UserEntityGrant?: {
lifetimeLength: number; // 授权的过期时间ms
};
};
export interface Schema extends EntityShape {

View File

@ -1,9 +1,8 @@
import { String, Text } from 'oak-domain/lib/types/DataType';
import { String, Text, Datetime } from 'oak-domain/lib/types/DataType';
import { EntityShape } from 'oak-domain/lib/types/Entity';
import { Index } from 'oak-domain/lib/types/Storage';
import { Schema as User } from './User';
import { Schema as WechatQrCode } from './WechatQrCode';
import { ActionDef } from 'oak-domain/lib/types/Action';
export interface Schema extends EntityShape {
entity: String<32>;
@ -11,24 +10,13 @@ export interface Schema extends EntityShape {
relation: String<32>;
action: String<32>;
remark?: Text;
uuid: String<32>;
granter: User;
grantee?: User;
files: Array<WechatQrCode>;
expiresAt?: Datetime;
expired?: Boolean;
}
type IAction = 'confirm';
type IState = | 'init'| 'expire';
const IActionDef: ActionDef<IAction, IState> = {
stm: {
confirm: ['init', 'expire'],
},
is: 'init'
};
type Action = IAction;
const indexes: Index<Schema>[] = [
{
name: 'index_entity_entityId',
@ -45,8 +33,11 @@ const indexes: Index<Schema>[] = [
name: 'index_uuid',
attributes: [
{
name: 'uuid',
name: 'expired',
},
{
name: 'expiresAt',
}
],
},
];

View File

@ -3,25 +3,30 @@ import { EntityShape } from 'oak-domain/lib/types/Entity';
import { Index } from 'oak-domain/lib/types/Storage';
import { Schema as Application } from './Application';
export type WechatQrCodeProps = {
pathname: string;
props?: Record<string, any>;
state?: Record<string, any>;
};
export interface Schema extends EntityShape {
entity: String<32>;
entityId: String<64>;
type?: String<32>; //类型
expiresAt: Datetime; // 过期时间
expired: Boolean; //是否过期
autoExtend: Boolean;
sceneStr?: Text;
type: 'wechatMpDomainUrl' | 'wechatMpWxaCode' | 'wechatPublic' | 'wechatPublicForMp',
tag?: String<32>; // 调用者加的tag
expiresAt?: Datetime; // 过期时间
expired?: Boolean; //是否过期
ticket?: Text;
url?: String<64>;
isPermanent: Boolean; //是否永久码
permanent: Boolean; //是否永久码
buffer?: Text; // 若没有url使用buffer存储生成的小程序码数据base64)
application: Application;
props?: Object;
props: WechatQrCodeProps;
}
const indexes: Index<Schema>[] = [
{
name: 'index_entity_entityId',
name: 'index_entity_entityId_tag',
attributes: [
{
name: 'entity',
@ -29,6 +34,9 @@ const indexes: Index<Schema>[] = [
{
name: 'entityId',
},
{
name: 'tag',
}
],
},
{

View File

@ -13,7 +13,7 @@ export class ExtraFile<
super();
}
@Action
async upload(extraFile: DeduceCreateOperationData<ED['extraFile']['Schema']>, scene: string) {
async upload(extraFile: DeduceCreateOperationData<EntityDict['extraFile']['OpSchema']>, scene: string) {
try {
const { origin, extra1: filePath, filename: fileName } = extraFile;
const uploadInfo =

View File

@ -4,5 +4,6 @@ import { Trigger } from 'oak-domain/lib/types';
import addressTriggers from './address';
import userTriggers from './user';
import userEntityGrantTriggers from './userEntityGrant';
import wechatQrCodeTriggers from './wechatQrCode';
export default [...addressTriggers, ...userTriggers, ...userEntityGrantTriggers];
export default [...addressTriggers, ...userTriggers, ...userEntityGrantTriggers, ...wechatQrCodeTriggers];

View File

@ -6,10 +6,12 @@ import { CreateOperationData as CreateUserEntityGrantData } from 'oak-app-domain
import { assign, keys } from 'lodash';
import { OakCongruentRowExists } from 'oak-domain/lib/types';
import assert from 'assert';
import { DefaultConfig } from '../constants';
import { createWechatQrCode } from '../aspects/wechatQrCode';
const triggers: Trigger<EntityDict, 'userEntityGrant', GeneralRuntimeContext<EntityDict>>[] = [
{
name: '当创建userEntityGrant时,查询是否有未过期的实体',
name: '当创建userEntityGrant时,查询是否有未过期可重用的对象',
entity: 'userEntityGrant',
action: 'create',
when: 'before',
@ -17,8 +19,9 @@ const triggers: Trigger<EntityDict, 'userEntityGrant', GeneralRuntimeContext<Ent
const { data, filter } = operation;
const fn = async (userEntityGrantData: CreateUserEntityGrantData) => {
const { userId } = (await context.getToken())!;
const { id: applicationId, config: appConfig, system: { config: SystemConfig }} = (await context.getApplication());
assert(userId);
const { action, entity, entityId, relation} = userEntityGrantData;
const { action, entity, entityId, relation, id } = userEntityGrantData;
const { result } = await context.rowStore.select('userEntityGrant', {
data: {
id: 1,
@ -26,11 +29,14 @@ const triggers: Trigger<EntityDict, 'userEntityGrant', GeneralRuntimeContext<Ent
entity: 1,
entityId: 1,
relation: 1,
iState: 1,
expired: 1,
granterId: 1,
},
filter: {
iState: 'init',
expired: false,
expiresAt: {
$gt: Date.now() - 600 * 1000,
}, // 至少有10分钟有效期的
action,
entity,
entityId,
@ -44,9 +50,27 @@ const triggers: Trigger<EntityDict, 'userEntityGrant', GeneralRuntimeContext<Ent
throw new OakCongruentRowExists(result[0] as any, '有可重用的userEntityGrant');
}
const expiresAt = Date.now() + (SystemConfig.UserEntityGrant?.lifetimeLength || DefaultConfig.userEntityGrant.lifetimeLength);
assign(userEntityGrantData, {
granterId: userId,
expiresAt,
expired: false,
});
// 如果是微信体系的应用为之创建一个默认的weChatQrCode
if (['wechatPublic', 'wechatMp'].includes(appConfig.type)) {
await createWechatQrCode({
entity: 'userEntityGrant',
entityId: id,
applicationId,
props: {
pathname: 'pages/userEntityGrant/confirm',
props: {
oakId: id,
},
}
}, context);
}
}
if (data instanceof Array) {
assert('授权不存在一对多的情况')

View File

@ -0,0 +1,49 @@
import { EntityDict } from 'oak-app-domain/EntityDict';
import { SelectTriggerAfter, Trigger } from 'oak-domain/lib/types/Trigger';
import { GeneralRuntimeContext } from '../RuntimeContext';
import assert from 'assert';
import { WechatSDK } from 'oak-wechat-sdk';
import { WechatMpConfig } from 'oak-app-domain/Application/Schema';
import { shrinkUuidTo32Bytes } from 'oak-domain/lib/utils/uuid';
import { assign } from 'lodash';
const triggers: Trigger<EntityDict, 'wechatQrCode', GeneralRuntimeContext<EntityDict>>[] = [
{
name: '选择userEntityGrant时动态生成需要的数据',
entity: 'wechatQrCode',
action: 'select',
when: 'after',
fn: async ({ result }, context, params) => {
let count = 0;
const application = await context.getApplication();
const { type, config } = application;
assert(type === 'wechatMp' || config.type === 'wechatMp');
const config2 = config as WechatMpConfig;
const { appId, appSecret } = config2;
for (const code of result) {
const { type, expired, url, id } = code;
if (type === 'wechatMpWxaCode') {
// 小程序码去实时获取(暂时不考虑缓存)
const wechatInstance = WechatSDK.getInstance(appId, appSecret, 'wechatMp');
const buffer = await wechatInstance.getMpUnlimitWxaCode({
scene: shrinkUuidTo32Bytes(id),
page: 'pages/index/index', // todo这里用其它的页面微信服务器拒绝因为没发布。应该是 pages/wechatQrCode/scan/index
});
// 把arrayBuffer转成字符串返回
const str = String.fromCharCode(...new Uint8Array(buffer));
assign(code, {
buffer: str,
});
}
else if (expired) {
// 如果过期了,在这里生成新的临时码并修改值(公众号)
throw new Error('not implemented yet');
}
}
return count;
}
} as SelectTriggerAfter<EntityDict, 'wechatQrCode', GeneralRuntimeContext<EntityDict>>,
];
export default triggers;

View File

@ -131,7 +131,8 @@ OakComponent({
filename: filename,
},
beforeExecute: async (updateData) => {
const { url, bucket } = await this.features.extraFile.upload(updateData as DeduceCreateOperationData<EntityDict['extraFile']['Schema']>, "extraFile:gallery:upload");
const { url, bucket } = await this.features.extraFile.upload(
updateData as DeduceCreateOperationData<EntityDict['extraFile']['Schema']>, "extraFile:gallery:upload");
Object.assign(updateData, {
bucket,
extra1: url,

View File

@ -9,7 +9,6 @@ OakPage({
relation: 1,
action: 1,
remark: 1,
uuid: 1,
granterId: 1,
granteeId: 1,
wechatQrCode$entity: {
@ -21,15 +20,9 @@ OakPage({
type: 1,//类型
expiresAt: 1,// 过期时间
expired: 1, //是否过期
autoExtend: 1,
sceneStr: 1,
ticket: 1,
url: 1,
isPermanent: 1, //是否永久码
},
filter: {
entity: 'userEntityGrant',
expired: false,
buffer: 1,
},
indexFrom: 0,
count: 1,

View File

@ -12,7 +12,6 @@ OakPage({
relation: 1,
action: 1,
remark: 1,
uuid: 1,
granterId: 1,
granteeId: 1,
},