diff --git a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/Bot.tsx b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/Bot.tsx index 0ae134ca..b13a0d05 100644 --- a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/Bot.tsx +++ b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/Bot.tsx @@ -1,48 +1,43 @@ import React from 'react'; -import { FullModalField, Switch } from '@capital/component'; +import { + DefaultFullModalInputEditorRender, + FullModalField, + Switch, +} from '@capital/component'; import { useOpenAppInfo } from '../context'; -import { OpenAppCapability } from '../types'; -import { postRequest, useAsyncFn } from '@capital/common'; +import { Translate } from '../../translate'; +import { useOpenAppAction } from './useOpenAppAction'; const Bot: React.FC = React.memo(() => { - const { refresh, appId, capability } = useOpenAppInfo(); - - const [{ loading }, handleChangeBotCapability] = useAsyncFn( - async (checked: boolean) => { - const newCapability: OpenAppCapability[] = [...capability]; - const findIndex = newCapability.findIndex((c) => c === 'bot'); - - if (checked) { - if (findIndex === -1) { - newCapability.push('bot'); - } - } else { - if (findIndex !== -1) { - newCapability.splice(findIndex, 1); - } - } - - await postRequest('/openapi/app/setAppCapability', { - appId, - capability: newCapability, - }); - await refresh(); - }, - [appId, capability, refresh] - ); + const { capability, bot } = useOpenAppInfo(); + const { loading, handleChangeAppCapability, handleUpdateBotInfo } = + useOpenAppAction(); return (
handleChangeAppCapability('bot', checked)} /> } /> + + {capability.includes('bot') && ( + + handleUpdateBotInfo('callbackUrl', String(str)) + } + /> + )}
); }); diff --git a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/OAuth.tsx b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/OAuth.tsx index 32dba9e8..f0c2c1fe 100644 --- a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/OAuth.tsx +++ b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/OAuth.tsx @@ -5,44 +5,12 @@ import { Switch, } from '@capital/component'; import { useOpenAppInfo } from '../context'; -import { OpenAppCapability } from '../types'; -import { postRequest, useAsyncFn, useAsyncRequest } from '@capital/common'; +import { useOpenAppAction } from './useOpenAppAction'; const OAuth: React.FC = React.memo(() => { - const { refresh, appId, capability, oauth } = useOpenAppInfo(); - - const [{ loading }, handleChangeOAuthCapability] = useAsyncRequest( - async (checked: boolean) => { - const newCapability: OpenAppCapability[] = [...capability]; - const findIndex = newCapability.findIndex((c) => c === 'oauth'); - const isExist = findIndex !== -1; - - if (checked && !isExist) { - newCapability.push('oauth'); - } else if (!checked && isExist) { - newCapability.splice(findIndex, 1); - } - - await postRequest('/openapi/app/setAppCapability', { - appId, - capability: newCapability, - }); - await refresh(); - }, - [appId, capability, refresh] - ); - - const [, handleUpdateOAuthInfo] = useAsyncFn( - async (name: string, value: any) => { - await postRequest('/openapi/app/setAppOAuthInfo', { - appId, - fieldName: name, - fieldValue: value, - }); - await refresh(); - }, - [] - ); + const { capability, oauth } = useOpenAppInfo(); + const { loading, handleChangeAppCapability, handleUpdateOAuthInfo } = + useOpenAppAction(); return (
@@ -52,7 +20,7 @@ const OAuth: React.FC = React.memo(() => { handleChangeAppCapability('oauth', checked)} /> } /> diff --git a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/useOpenAppAction.tsx b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/useOpenAppAction.tsx new file mode 100644 index 00000000..72e38e52 --- /dev/null +++ b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/useOpenAppAction.tsx @@ -0,0 +1,65 @@ +import { postRequest, useAsyncFn } from '@capital/common'; +import { useOpenAppInfo } from '../context'; +import type { OpenAppBot, OpenAppCapability, OpenAppOAuth } from '../types'; + +/** + * 开放应用操作 + */ +export function useOpenAppAction() { + const { refresh, appId, capability } = useOpenAppInfo(); + + const [{ loading }, handleChangeAppCapability] = useAsyncFn( + async (targetCapability: OpenAppCapability, checked: boolean) => { + const newCapability: OpenAppCapability[] = [...capability]; + const findIndex = newCapability.findIndex((c) => c === targetCapability); + + if (checked) { + if (findIndex === -1) { + newCapability.push(targetCapability); + } + } else { + if (findIndex !== -1) { + newCapability.splice(findIndex, 1); + } + } + + await postRequest('/openapi/app/setAppCapability', { + appId, + capability: newCapability, + }); + await refresh(); + }, + [appId, capability, refresh] + ); + + const [, handleUpdateOAuthInfo] = useAsyncFn( + async (name: T, value: OpenAppOAuth[T]) => { + await postRequest('/openapi/app/setAppOAuthInfo', { + appId, + fieldName: name, + fieldValue: value, + }); + await refresh(); + }, + [] + ); + + const [, handleUpdateBotInfo] = useAsyncFn( + async (name: T, value: OpenAppBot[T]) => { + await postRequest('/openapi/app/setAppBotInfo', { + appId, + fieldName: name, + fieldValue: value, + }); + await refresh(); + }, + [appId, refresh] + ); + + return { + loading, + handleChangeAppCapability, + handleUpdateOAuthInfo, + handleUpdateBotInfo, + }; +} diff --git a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/types.ts b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/types.ts index 74a4b266..f91bca74 100644 --- a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/types.ts +++ b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/types.ts @@ -6,10 +6,14 @@ const openAppCapability = [ export type OpenAppCapability = typeof openAppCapability[number]; -interface OpenAppOAuth { +export interface OpenAppOAuth { redirectUrls: string[]; } +export interface OpenAppBot { + callbackUrl: string; +} + export interface OpenApp { _id: string; appId: string; @@ -19,6 +23,7 @@ export interface OpenApp { appIcon: string; capability: OpenAppCapability[]; oauth?: OpenAppOAuth; + bot?: OpenAppBot; owner: string; } diff --git a/client/web/plugins/com.msgbyte.openapi/src/translate.ts b/client/web/plugins/com.msgbyte.openapi/src/translate.ts index 16085180..7a6280f2 100644 --- a/client/web/plugins/com.msgbyte.openapi/src/translate.ts +++ b/client/web/plugins/com.msgbyte.openapi/src/translate.ts @@ -6,4 +6,20 @@ export const Translate = { 'zh-CN': '管理员没有开放 Openapi 服务', 'en-US': 'The administrator did not open the Openapi service', }), + enableBotCapability: localTrans({ + 'zh-CN': '开启机器人能力', + 'en-US': 'Enable Bot Capability', + }), + bot: { + callback: localTrans({ + 'zh-CN': '消息回调地址', + 'en-US': 'Callback Url', + }), + callbackTip: localTrans({ + 'zh-CN': + '机器人被 @ 的时候会向该地址发送请求(收件箱接受到新内容时会发送回调)', + 'en-US': + 'The bot will send a request to this address when it is mentioned (callback will be sent when the inbox receives new content)', + }), + }, }; diff --git a/server/models/openapi/app.ts b/server/models/openapi/app.ts index 4336ae3e..f7d5c632 100644 --- a/server/models/openapi/app.ts +++ b/server/models/openapi/app.ts @@ -29,13 +29,14 @@ export function filterAvailableAppCapability( ) as OpenAppCapability[]; } -class OpenAppOAuth { - @prop({ - type: () => String, - }) +export interface OpenAppOAuth { redirectUrls: string[]; } +export interface OpenAppBot { + callbackUrl: string; +} + /** * 开放平台应用 */ @@ -70,11 +71,12 @@ export class OpenApp extends TimeStamps implements Base { }) capability: OpenAppCapability[]; - @prop({ - type: () => OpenAppOAuth, - }) + @prop() oauth?: OpenAppOAuth; + @prop() + bot?: OpenAppBot; + /** * 根据appId获取openapp的实例 * 用于获得获得完整数据(包括secret) diff --git a/server/services/openapi/app.service.ts b/server/services/openapi/app.service.ts index 44631129..84741097 100644 --- a/server/services/openapi/app.service.ts +++ b/server/services/openapi/app.service.ts @@ -8,8 +8,10 @@ import { import _ from 'lodash'; import { filterAvailableAppCapability, + OpenAppBot, OpenAppDocument, OpenAppModel, + OpenAppOAuth, } from '../../models/openapi/app'; import { Types } from 'mongoose'; import { nanoid } from 'nanoid'; @@ -67,6 +69,13 @@ class OpenAppService extends TcService { fieldValue: 'any', }, }); + this.registerAction('setAppBotInfo', this.setAppBotInfo, { + params: { + appId: 'string', + fieldName: 'string', + fieldValue: 'any', + }, + }); } /** @@ -201,11 +210,11 @@ class OpenAppService extends TcService { /** * 设置OAuth的设置信息 */ - async setAppOAuthInfo( + async setAppOAuthInfo( ctx: TcContext<{ appId: string; - fieldName: string; - fieldValue: any; + fieldName: T; + fieldValue: OpenAppOAuth[T]; }> ) { const { appId, fieldName, fieldValue } = ctx.params; @@ -233,6 +242,42 @@ class OpenAppService extends TcService { } ); } + + /** + * 设置Bot的设置信息 + */ + async setAppBotInfo( + ctx: TcContext<{ + appId: string; + fieldName: T; + fieldValue: OpenAppBot[T]; + }> + ) { + const { appId, fieldName, fieldValue } = ctx.params; + const { userId } = ctx.meta; + + if (!['callbackUrl'].includes(fieldName)) { + throw new Error('Not allowed fields'); + } + + if (fieldName === 'callbackUrl') { + if (typeof fieldValue !== 'string') { + throw new Error('`callbackUrl` should be a string'); + } + } + + await this.adapter.model.findOneAndUpdate( + { + appId, + owner: userId, + }, + { + $set: { + [`bot.${fieldName}`]: fieldValue, + }, + } + ); + } } export default OpenAppService;