347 lines
12 KiB
JavaScript
347 lines
12 KiB
JavaScript
import { assert } from 'oak-domain/lib/utils/assert';
|
||
import { applicationProjection } from '../types/Projection';
|
||
import WechatSDK from 'oak-external-sdk/lib/WechatSDK';
|
||
import fs from 'fs';
|
||
import { cloneDeep, unset } from 'oak-domain/lib/utils/lodash';
|
||
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
|
||
import { compareVersion } from 'oak-domain/lib/utils/version';
|
||
import { OakApplicationHasToUpgrade } from 'oak-domain/lib/types/Exception';
|
||
async function getApplicationByDomain(context, options) {
|
||
const { data, type, domain } = options;
|
||
let applications = await context.select('application', {
|
||
data,
|
||
filter: {
|
||
type,
|
||
system: {
|
||
domain$system: {
|
||
url: domain,
|
||
},
|
||
},
|
||
domain: {
|
||
url: domain,
|
||
},
|
||
},
|
||
}, {});
|
||
assert(applications.length <= 1, `应用指定域名(domainId)只能存在一项或未指定,域名「${domain}」`);
|
||
if (applications.length === 0) {
|
||
applications = await context.select('application', {
|
||
data: data,
|
||
filter: {
|
||
type,
|
||
system: {
|
||
domain$system: {
|
||
url: domain,
|
||
},
|
||
},
|
||
domainId: {
|
||
$exists: false,
|
||
},
|
||
},
|
||
}, {});
|
||
}
|
||
return applications;
|
||
}
|
||
function checkAppVersionSafe(application, version) {
|
||
const { dangerousVersions, warningVersions, system } = application;
|
||
const { oldestVersion, platform } = system;
|
||
const { oldestVersion: pfOldestVersion } = platform || {};
|
||
const oldest = pfOldestVersion || oldestVersion;
|
||
if (oldest) {
|
||
if (compareVersion(version, oldest) < 0) {
|
||
throw new OakApplicationHasToUpgrade();
|
||
}
|
||
}
|
||
if (dangerousVersions && dangerousVersions.includes(version)) {
|
||
throw new OakApplicationHasToUpgrade();
|
||
}
|
||
unset(application, 'dangerousVersions');
|
||
if (warningVersions) {
|
||
application.warningVersions = warningVersions.filter(ele => ele === version);
|
||
}
|
||
}
|
||
export async function getApplication(params, context) {
|
||
const { type, domain, data, appId, version } = params;
|
||
// 先找指定domain的应用,如果不存在再找系统下面的domain, 但无论怎么样都必须一项
|
||
const applications = await getApplicationByDomain(context, {
|
||
type,
|
||
domain,
|
||
data,
|
||
});
|
||
switch (type) {
|
||
case 'wechatMp': {
|
||
assert(applications.length === 1, `微信小程序环境下,同一个系统必须存在唯一的【${type}】应用,域名「${domain}」`);
|
||
const application = applications[0];
|
||
checkAppVersionSafe(application, version);
|
||
return application.id;
|
||
}
|
||
case 'native': {
|
||
assert(applications.length === 1, `APP环境下,同一个系统必须存在唯一的【${type}】应用,域名「${domain}」`);
|
||
const application = applications[0];
|
||
checkAppVersionSafe(application, version);
|
||
return application.id;
|
||
}
|
||
case 'wechatPublic': {
|
||
// 微信公众号环境下,未配置公众号,可以使用web的application
|
||
if (applications.length === 0) {
|
||
const webApplications = await getApplicationByDomain(context, {
|
||
type: 'web',
|
||
domain,
|
||
data,
|
||
});
|
||
assert(webApplications.length === 1, `微信公众号环境下, 可以未配置公众号,但必须存在web应用,域名「${domain}」`);
|
||
const application = webApplications[0];
|
||
checkAppVersionSafe(application, version);
|
||
return application.id;
|
||
}
|
||
assert(applications.length === 1, `微信公众号环境下,同一个系统必须存在唯一的【${type}】应用 或 多个${type}应用必须配置域名,域名「${domain}」`);
|
||
const application = applications[0];
|
||
checkAppVersionSafe(application, version);
|
||
return application.id;
|
||
}
|
||
case 'web': {
|
||
assert(applications.length === 1, `web环境下,同一个系统必须存在唯一的【${type}】应用 或 多个${type}应用必须配置域名,域名「${domain}」`);
|
||
const application = applications[0];
|
||
checkAppVersionSafe(application, version);
|
||
return application.id;
|
||
}
|
||
default: {
|
||
assert(false, `不支持的类型【${type}】,域名「${domain}」`);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
export async function signatureJsSDK({ url, env }, context) {
|
||
const application = context.getApplication();
|
||
const { type, config } = application;
|
||
assert(type === 'wechatPublic' && config.type === 'wechatPublic');
|
||
const config2 = config;
|
||
const { appId, appSecret } = config2;
|
||
const wechatInstance = WechatSDK.getInstance(appId, 'wechatPublic', appSecret);
|
||
const result = await wechatInstance.signatureJsSDK({ url });
|
||
return result;
|
||
}
|
||
export async function uploadWechatMedia(params, // FormData表单提交 isPermanent 变成 'true' | 'false'
|
||
context) {
|
||
const { applicationId, file, type: mediaType, description, extraFileId, } = params;
|
||
assert(applicationId);
|
||
const isPermanent = params.isPermanent === 'true';
|
||
const filename = file.originalFilename;
|
||
const filetype = file.mimetype;
|
||
const fileLength = file.size;
|
||
const fileStream = fs.createReadStream(file.filepath);
|
||
const [application] = await context.select('application', {
|
||
data: cloneDeep(applicationProjection),
|
||
filter: {
|
||
id: applicationId,
|
||
},
|
||
}, {
|
||
dontCollect: true,
|
||
});
|
||
const { type, config } = application;
|
||
assert(type === 'wechatPublic' || type === 'wechatMp');
|
||
let wechatInstance;
|
||
if (type === 'wechatPublic') {
|
||
assert(config.type === 'wechatPublic');
|
||
const config2 = config;
|
||
const { appId, appSecret } = config2;
|
||
wechatInstance = WechatSDK.getInstance(appId, 'wechatPublic', appSecret);
|
||
}
|
||
else {
|
||
assert(config.type === 'wechatMp');
|
||
const config2 = config;
|
||
const { appId, appSecret } = config2;
|
||
wechatInstance = WechatSDK.getInstance(appId, 'wechatPublic', appSecret);
|
||
}
|
||
let mediaId;
|
||
if (isPermanent) {
|
||
// 只有公众号才能上传永久素材
|
||
assert(type === 'wechatPublic');
|
||
const result = (await wechatInstance.createMaterial({
|
||
type: mediaType,
|
||
media: fileStream,
|
||
filename,
|
||
filetype,
|
||
fileLength,
|
||
description: description ? JSON.parse(description) : null,
|
||
}));
|
||
mediaId = result.media_id;
|
||
}
|
||
else {
|
||
const result = (await wechatInstance.createTemporaryMaterial({
|
||
type: mediaType,
|
||
media: fileStream,
|
||
filename,
|
||
filetype,
|
||
fileLength,
|
||
}));
|
||
mediaId = result.media_id;
|
||
}
|
||
if (extraFileId) {
|
||
const closeRootMode = context.openRootMode();
|
||
try {
|
||
await context.operate('extraFile', {
|
||
id: await generateNewIdAsync(),
|
||
action: 'update',
|
||
data: {
|
||
extra1: mediaId,
|
||
},
|
||
filter: {
|
||
id: extraFileId,
|
||
},
|
||
}, {});
|
||
closeRootMode();
|
||
}
|
||
catch (err) {
|
||
closeRootMode();
|
||
throw err;
|
||
}
|
||
}
|
||
return {
|
||
mediaId,
|
||
};
|
||
}
|
||
export async function getMaterial(params, context) {
|
||
const { mediaId, applicationId, isPermanent = false } = params;
|
||
assert(applicationId);
|
||
assert(mediaId);
|
||
const [application] = await context.select('application', {
|
||
data: cloneDeep(applicationProjection),
|
||
filter: {
|
||
id: applicationId,
|
||
},
|
||
}, {
|
||
dontCollect: true,
|
||
});
|
||
assert(application);
|
||
const { type, config } = application;
|
||
assert(type === 'wechatPublic' || type === 'wechatMp');
|
||
let wechatInstance;
|
||
if (type === 'wechatPublic') {
|
||
const config2 = config;
|
||
const { appId, appSecret } = config2;
|
||
wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
|
||
}
|
||
else {
|
||
const config2 = config;
|
||
const { appId, appSecret } = config2;
|
||
wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
|
||
}
|
||
let result;
|
||
if (isPermanent) {
|
||
// 只有公众号才能获取永久素材
|
||
assert(type === 'wechatPublic');
|
||
result = await wechatInstance.getMaterial({
|
||
mediaId,
|
||
});
|
||
}
|
||
else {
|
||
result = await wechatInstance.getTemporaryMaterial({
|
||
mediaId,
|
||
});
|
||
}
|
||
if (result instanceof ArrayBuffer) {
|
||
return Buffer.from(result).toString('base64');
|
||
}
|
||
return result;
|
||
}
|
||
export async function deleteMaterial(params, context) {
|
||
const { mediaId, applicationId } = params;
|
||
assert(applicationId);
|
||
assert(mediaId);
|
||
const [application] = await context.select('application', {
|
||
data: cloneDeep(applicationProjection),
|
||
filter: {
|
||
id: applicationId,
|
||
},
|
||
}, {
|
||
dontCollect: true,
|
||
});
|
||
assert(application);
|
||
const { type, config } = application;
|
||
assert(type === 'wechatPublic');
|
||
const config2 = config;
|
||
const { appId, appSecret } = config2;
|
||
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
|
||
const result = await wechatInstance.deleteMaterial({
|
||
mediaId,
|
||
});
|
||
return result;
|
||
}
|
||
export async function batchGetArticle(params, context) {
|
||
const { applicationId, offset, count, noContent } = params;
|
||
assert(applicationId);
|
||
const [application] = await context.select('application', {
|
||
data: cloneDeep(applicationProjection),
|
||
filter: {
|
||
id: applicationId,
|
||
},
|
||
}, {
|
||
dontCollect: true,
|
||
});
|
||
assert(application);
|
||
const { type, config } = application;
|
||
assert(type === 'wechatPublic');
|
||
let appId, appSecret;
|
||
const config2 = config;
|
||
appId = config2.appId;
|
||
appSecret = config2.appSecret;
|
||
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
|
||
const result = await wechatInstance.batchGetArticle({
|
||
offset,
|
||
count,
|
||
noContent,
|
||
});
|
||
return result;
|
||
}
|
||
export async function getArticle(params, context) {
|
||
const { applicationId, articleId } = params;
|
||
assert(applicationId);
|
||
const [application] = await context.select('application', {
|
||
data: cloneDeep(applicationProjection),
|
||
filter: {
|
||
id: applicationId,
|
||
},
|
||
}, {
|
||
dontCollect: true,
|
||
});
|
||
assert(application);
|
||
const { type, config } = application;
|
||
assert(type === 'wechatPublic');
|
||
let appId, appSecret;
|
||
const config2 = config;
|
||
appId = config2.appId;
|
||
appSecret = config2.appSecret;
|
||
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
|
||
const result = await wechatInstance.getArticle({
|
||
articleId,
|
||
});
|
||
return result;
|
||
}
|
||
export async function batchGetMaterialList(params, context) {
|
||
const { applicationId } = params;
|
||
assert(applicationId);
|
||
const [application] = await context.select('application', {
|
||
data: cloneDeep(applicationProjection),
|
||
filter: {
|
||
id: applicationId,
|
||
},
|
||
}, {
|
||
dontCollect: true,
|
||
});
|
||
assert(application);
|
||
const { type, config } = application;
|
||
assert(type === 'wechatPublic');
|
||
let appId, appSecret;
|
||
const config2 = config;
|
||
appId = config2.appId;
|
||
appSecret = config2.appSecret;
|
||
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
|
||
const { type: materialType, offset, count } = params;
|
||
const result = await wechatInstance.batchGetMaterialList({
|
||
type: materialType,
|
||
offset,
|
||
count,
|
||
});
|
||
return result;
|
||
}
|