From 380bc3d960d56509ac16ee32a73926559d1f7d1f Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Sat, 26 Aug 2023 21:31:05 +0800 Subject: [PATCH] feat(openapi): add delete app action --- .../src/MainPanel/AppInfo/Profile.tsx | 18 ++++++--- .../MainPanel/AppInfo/useOpenAppAction.tsx | 27 +++++++++++++- .../src/MainPanel/context.tsx | 3 ++ .../src/MainPanel/index.tsx | 6 ++- .../src/MainPanel/useOpenAppList.ts | 2 +- .../com.msgbyte.openapi/src/translate.ts | 4 ++ client/web/src/utils/url-helper.ts | 13 +++++-- server/services/openapi/app.service.ts | 37 +++++++++++++++++++ 8 files changed, 97 insertions(+), 13 deletions(-) diff --git a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/Profile.tsx b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/Profile.tsx index 1f065b40..63cf3222 100644 --- a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/Profile.tsx +++ b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/Profile.tsx @@ -1,7 +1,13 @@ import { useOpenAppInfo } from '../context'; import React from 'react'; -import { FullModalField, Divider, SensitiveText } from '@capital/component'; +import { + FullModalField, + Divider, + SensitiveText, + Button, +} from '@capital/component'; import { Translate } from '../../translate'; +import { useOpenAppAction } from './useOpenAppAction'; import './Profile.less'; /** @@ -10,6 +16,8 @@ import './Profile.less'; const Profile: React.FC = React.memo(() => { const { appId, appSecret } = useOpenAppInfo(); + const { handleDeleteApp } = useOpenAppAction(); + return (

{Translate.app.appcret}

@@ -22,11 +30,11 @@ const Profile: React.FC = React.memo(() => { />
- {/* */} - - {/*

{Translate.app.basicInfo}

*/} + - {/* TODO */} + ); }); 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 index 72e38e52..45f03dd1 100644 --- a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/useOpenAppAction.tsx +++ b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/AppInfo/useOpenAppAction.tsx @@ -1,4 +1,10 @@ -import { postRequest, useAsyncFn } from '@capital/common'; +import { + openReconfirmModal, + postRequest, + showErrorToasts, + useAsyncFn, + useEvent, +} from '@capital/common'; import { useOpenAppInfo } from '../context'; import type { OpenAppBot, OpenAppCapability, OpenAppOAuth } from '../types'; @@ -6,7 +12,7 @@ import type { OpenAppBot, OpenAppCapability, OpenAppOAuth } from '../types'; * 开放应用操作 */ export function useOpenAppAction() { - const { refresh, appId, capability } = useOpenAppInfo(); + const { refresh, appId, capability, onSelectApp } = useOpenAppInfo(); const [{ loading }, handleChangeAppCapability] = useAsyncFn( async (targetCapability: OpenAppCapability, checked: boolean) => { @@ -56,8 +62,25 @@ export function useOpenAppAction() { [appId, refresh] ); + const handleDeleteApp = useEvent(() => { + openReconfirmModal({ + onConfirm: async () => { + try { + await postRequest('/openapi/app/delete', { + appId, + }); + onSelectApp(null); + await refresh(); + } catch (err) { + showErrorToasts(err); + } + }, + }); + }); + return { loading, + handleDeleteApp, handleChangeAppCapability, handleUpdateOAuthInfo, handleUpdateBotInfo, diff --git a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/context.tsx b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/context.tsx index 928a5bf4..eb7578cb 100644 --- a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/context.tsx +++ b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/context.tsx @@ -3,6 +3,7 @@ import { OpenApp } from './types'; interface OpenAppInfoContextProps extends OpenApp { refresh: () => Promise; + onSelectApp: (appId: string | null) => void; } const OpenAppInfoContext = React.createContext(null); @@ -12,6 +13,7 @@ export const OpenAppInfoProvider: React.FC< React.PropsWithChildren<{ appInfo: OpenApp; refresh: OpenAppInfoContextProps['refresh']; + onSelectApp: OpenAppInfoContextProps['onSelectApp']; }> > = (props) => { return ( @@ -19,6 +21,7 @@ export const OpenAppInfoProvider: React.FC< value={{ ...props.appInfo, refresh: props.refresh, + onSelectApp: props.onSelectApp, }} > {props.children} diff --git a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/index.tsx b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/index.tsx index 13d4a235..ac1211d3 100644 --- a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/index.tsx +++ b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/index.tsx @@ -50,7 +50,11 @@ const OpenApiMainPanel: React.FC = React.memo(() => {
{appInfo ? ( - + ) : ( diff --git a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/useOpenAppList.ts b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/useOpenAppList.ts index 3b61bdc6..f51c8b88 100644 --- a/client/web/plugins/com.msgbyte.openapi/src/MainPanel/useOpenAppList.ts +++ b/client/web/plugins/com.msgbyte.openapi/src/MainPanel/useOpenAppList.ts @@ -47,7 +47,7 @@ export function useOpenAppList() { /** * 设置当前选中的开放app */ - handleSetSelectedApp(appId: string) { + handleSetSelectedApp(appId: string | null) { navigate({ search: appendUrlSearch({ appId, diff --git a/client/web/plugins/com.msgbyte.openapi/src/translate.ts b/client/web/plugins/com.msgbyte.openapi/src/translate.ts index ccb96f69..81f021ea 100644 --- a/client/web/plugins/com.msgbyte.openapi/src/translate.ts +++ b/client/web/plugins/com.msgbyte.openapi/src/translate.ts @@ -18,6 +18,10 @@ export const Translate = { 'zh-CN': '操作', 'en-US': 'Operation', }), + delete: localTrans({ + 'zh-CN': '删除', + 'en-US': 'Delete', + }), enter: localTrans({ 'zh-CN': '进入', 'en-US': 'Enter', diff --git a/client/web/src/utils/url-helper.ts b/client/web/src/utils/url-helper.ts index b76c3c07..3f429bc1 100644 --- a/client/web/src/utils/url-helper.ts +++ b/client/web/src/utils/url-helper.ts @@ -15,10 +15,15 @@ export { urlSearchStringify, urlSearchParse }; * 往当前的url search上追加 */ export function appendUrlSearch(obj: Record): string { - return urlSearchStringify({ - ...urlSearchParse(window.location.search, { ignoreQueryPrefix: true }), - ...obj, - }); + return urlSearchStringify( + { + ...urlSearchParse(window.location.search, { ignoreQueryPrefix: true }), + ...obj, + }, + { + skipNulls: true, + } + ); } /** diff --git a/server/services/openapi/app.service.ts b/server/services/openapi/app.service.ts index 8e697f37..dd03764c 100644 --- a/server/services/openapi/app.service.ts +++ b/server/services/openapi/app.service.ts @@ -4,10 +4,12 @@ import { TcDbService, TcContext, EntityError, + NoPermissionError, } from 'tailchat-server-sdk'; import _ from 'lodash'; import { filterAvailableAppCapability, + OpenApp, OpenAppBot, OpenAppDocument, OpenAppModel, @@ -60,6 +62,11 @@ class OpenAppService extends TcService { appIcon: 'string', }, }); + this.registerAction('delete', this.delete, { + params: { + appId: 'string', + }, + }); this.registerAction('setAppCapability', this.setAppCapability, { params: { appId: 'string', @@ -185,6 +192,36 @@ class OpenAppService extends TcService { return await this.transformDocuments(ctx, {}, doc); } + /** + * 删除开放平台应用 + */ + async delete( + ctx: TcContext<{ + appId: string; + }> + ) { + const { appId } = ctx.params; + const userId = ctx.meta.userId; + const t = ctx.meta.t; + + const appInfo: OpenApp = await this.localCall('get', { + appId, + }); + + if (String(appInfo.owner) !== userId) { + throw new NoPermissionError(t('没有操作权限')); + } + + // 可能会出现ws机器人不会立即中断连接的问题,不重要暂时不处理 + + await this.adapter.model.remove({ + appId, + owner: userId, + }); + + return true; + } + /** * 设置应用开放的能力 */