删除订阅支持自动删除任务和脚本

This commit is contained in:
whyour 2023-07-30 21:15:46 +08:00
parent 2e27d4057e
commit b4e5db9da9
8 changed files with 59 additions and 11 deletions

View File

@ -210,12 +210,16 @@ export default (app: Router) => {
'/', '/',
celebrate({ celebrate({
body: Joi.array().items(Joi.number().required()), body: Joi.array().items(Joi.number().required()),
query: Joi.object({
force: Joi.boolean().optional(),
t: Joi.number()
})
}), }),
async (req: Request, res: Response, next: NextFunction) => { async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger'); const logger: Logger = Container.get('logger');
try { try {
const subscriptionService = Container.get(SubscriptionService); const subscriptionService = Container.get(SubscriptionService);
const data = await subscriptionService.remove(req.body); const data = await subscriptionService.remove(req.body, req.query);
return res.send({ code: 200, data }); return res.send({ code: 200, data });
} catch (e) { } catch (e) {
return next(e); return next(e);

View File

@ -16,10 +16,11 @@ import {
killTask, killTask,
handleLogPath, handleLogPath,
promiseExec, promiseExec,
emptyDir,
} from '../config/util'; } from '../config/util';
import { promises, existsSync } from 'fs'; import { promises, existsSync } from 'fs';
import { FindOptions, Op } from 'sequelize'; import { FindOptions, Op } from 'sequelize';
import path from 'path'; import path, { join } from 'path';
import ScheduleService, { TaskCallbacks } from './schedule'; import ScheduleService, { TaskCallbacks } from './schedule';
import { SimpleIntervalSchedule } from 'toad-scheduler'; import { SimpleIntervalSchedule } from 'toad-scheduler';
import SockService from './sock'; import SockService from './sock';
@ -27,6 +28,8 @@ import SshKeyService from './sshKey';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { LOG_END_SYMBOL } from '../config/const'; import { LOG_END_SYMBOL } from '../config/const';
import { formatCommand, formatUrl } from '../config/subscription'; import { formatCommand, formatUrl } from '../config/subscription';
import { CrontabModel } from '../data/cron';
import CrontabService from './cron';
@Service() @Service()
export default class SubscriptionService { export default class SubscriptionService {
@ -35,7 +38,8 @@ export default class SubscriptionService {
private scheduleService: ScheduleService, private scheduleService: ScheduleService,
private sockService: SockService, private sockService: SockService,
private sshKeyService: SshKeyService, private sshKeyService: SshKeyService,
) {} private crontabService: CrontabService,
) { }
public async list(searchText?: string): Promise<Subscription[]> { public async list(searchText?: string): Promise<Subscription[]> {
let query = {}; let query = {};
@ -253,13 +257,24 @@ export default class SubscriptionService {
); );
} }
public async remove(ids: number[]) { public async remove(ids: number[], query: any) {
const docs = await SubscriptionModel.findAll({ where: { id: ids } }); const docs = await SubscriptionModel.findAll({ where: { id: ids } });
for (const doc of docs) { for (const doc of docs) {
await this.handleTask(doc, false); await this.handleTask(doc, false);
} }
await SubscriptionModel.destroy({ where: { id: ids } }); await SubscriptionModel.destroy({ where: { id: ids } });
await this.setSshConfig(); await this.setSshConfig();
if (query?.force === true) {
const crons = await CrontabModel.findAll({ where: { sub_id: ids } });
if (crons?.length) {
await this.crontabService.remove(crons.map(x => x.id!))
}
for (const doc of docs) {
const filePath = join(config.scriptPath, doc.alias);
emptyDir(filePath);
}
}
} }
public async getDb( public async getDb(

View File

@ -332,7 +332,7 @@ select:-webkit-autofill:focus {
} }
.ant-pro-sider-logo { .ant-pro-sider-logo {
padding-inline: 8px !important; padding-inline: 5px !important;
.title { .title {
display: flex; display: flex;

View File

@ -394,5 +394,18 @@
"强制删除": "Force Delete", "强制删除": "Force Delete",
"全部任务": "All Tasks", "全部任务": "All Tasks",
"关联订阅": "Associate Subscription", "关联订阅": "Associate Subscription",
"订阅": "Subscription" "订阅": "Subscription",
"创建": "Create",
"创建订阅成功": "Subscription created successfully",
"gotify的url地址,例如 https://push.example.de:8080": "Gotify URL address, e.g., https://push.example.de:8080",
"BARK推送图标,自定义推送图标 (需iOS15或以上才能显示)": "BARK push icon, custom push icon (requires iOS 15 or above to display)",
"BARK推送铃声,铃声列表去APP查看复制填写": "BARK push ringtone, check the ringtone list in the APP and copy it",
"BARK推送消息的分组, 默认为qinglong": "BARK push message grouping, default is qinglong",
"telegram代理配置认证参数, 用户名与密码用英文冒号连接 user:password": "Telegram proxy configuration authentication parameters, connect username and password with a colon, e.g., user:password",
"企业微信机器人的 webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770)例如693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa": "WeChat Work Bot webhook (see documentation at https://work.weixin.qq.com/api/doc/90000/90136/91770), e.g., 693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa",
"corpid,corpsecret,touser(注:多个成员ID使用|隔开),agentid,消息类型(选填,不填默认文本消息类型) 注意用,号隔开(英文输入法的逗号)例如wwcfrs,B-76WERQ,qinglong,1000001,2COat": "corpid, corpsecret, touser (note: separate multiple member IDs with |), agentid, message type (optional, defaults to text message type) separated by commas (`,`), e.g., wwcfrs, B-76WERQ, qinglong, 1000001, 2COat",
"密钥key,智能微秘书个人中心获取apikey申请地址https://wechat.aibotk.com/signup?from=ql": "Key, obtain the API key from the Smart WeChat Assistant's personal center, apply at: https://wechat.aibotk.com/signup?from=ql",
"一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)": "The 'Group Code' for one-to-many push (under one-to-many push->Your Group (create one if none exists)->Group Code. If you are the creator of the group, you also need to click 'View QR Code' for scanning and binding, otherwise you cannot receive group message push)",
"同时删除关联任务和脚本": "Delete associated tasks and scripts as well",
"夹及其子文件": "Folder and its sub-files"
} }

View File

@ -394,5 +394,7 @@
"强制删除": "强制删除", "强制删除": "强制删除",
"全部任务": "全部任务", "全部任务": "全部任务",
"关联订阅": "关联订阅", "关联订阅": "关联订阅",
"订阅": "订阅" "订阅": "订阅",
"创建": "创建",
"同时删除关联任务和脚本": "同时删除关联任务和脚本"
} }

View File

@ -106,7 +106,7 @@ const Dependence = () => {
{ {
title: intl.get('状态'), title: intl.get('状态'),
key: 'status', key: 'status',
width: 100, width: 120,
dataIndex: 'status', dataIndex: 'status',
render: (text: string, record: any, index: number) => { render: (text: string, record: any, index: number) => {
return ( return (

View File

@ -195,7 +195,7 @@ const EditModal = ({
> >
{intl.get('清空日志')} {intl.get('清空日志')}
</Button> </Button>
<Button {/* <Button
type="primary" type="primary"
style={{ marginRight: 8 }} style={{ marginRight: 8 }}
onClick={() => { onClick={() => {
@ -203,7 +203,7 @@ const EditModal = ({
}} }}
> >
{intl.get('设置')} {intl.get('设置')}
</Button> </Button> */}
<Button <Button
type="primary" type="primary"
style={{ marginRight: 8 }} style={{ marginRight: 8 }}

View File

@ -12,6 +12,7 @@ import {
Typography, Typography,
Input, Input,
Tooltip, Tooltip,
Checkbox,
} from 'antd'; } from 'antd';
import { import {
ClockCircleOutlined, ClockCircleOutlined,
@ -240,6 +241,7 @@ const Subscription = () => {
const [logSubscription, setLogSubscription] = useState<any>(); const [logSubscription, setLogSubscription] = useState<any>();
const tableRef = useRef<HTMLDivElement>(null); const tableRef = useRef<HTMLDivElement>(null);
const tableScrollHeight = useTableScrollHeight(tableRef); const tableScrollHeight = useTableScrollHeight(tableRef);
const deleteCheckRef = useRef(false);
const runSubscription = (record: any, index: number) => { const runSubscription = (record: any, index: number) => {
Modal.confirm({ Modal.confirm({
@ -335,6 +337,10 @@ const Subscription = () => {
setIsModalVisible(true); setIsModalVisible(true);
}; };
const onCheckChange = (e) => {
deleteCheckRef.current = e.target.checked;
};
const delSubscription = (record: any, index: number) => { const delSubscription = (record: any, index: number) => {
Modal.confirm({ Modal.confirm({
title: intl.get('确认删除'), title: intl.get('确认删除'),
@ -345,11 +351,19 @@ const Subscription = () => {
{record.name} {record.name}
</Text>{' '} </Text>{' '}
{intl.get('吗')} {intl.get('吗')}
<div style={{ marginTop: 20 }}>
<Checkbox onChange={onCheckChange}>
{intl.get('同时删除关联任务和脚本')}
</Checkbox>
</div>
</> </>
), ),
onOk() { onOk() {
request request
.delete(`${config.apiPrefix}subscriptions`, { data: [record.id] }) .delete(`${config.apiPrefix}subscriptions`, {
data: [record.id],
params: { force: deleteCheckRef.current },
})
.then(({ code, data }) => { .then(({ code, data }) => {
if (code === 200) { if (code === 200) {
message.success('删除成功'); message.success('删除成功');