From 4e45fe9136f76b8d5f887b83c56f47defe71df5b Mon Sep 17 00:00:00 2001 From: vapao Date: Fri, 27 Aug 2021 13:14:30 +0800 Subject: [PATCH] fix issue --- spug_api/apps/app/models.py | 12 +- spug_api/apps/app/views.py | 11 +- spug_api/apps/deploy/models.py | 13 ++ spug_api/apps/deploy/views.py | 49 ++++---- spug_api/apps/repository/models.py | 11 +- spug_api/apps/repository/views.py | 6 - spug_api/spug/settings.py | 1 + .../src/pages/deploy/request/BatchDelete.js | 111 ++++++++++++++++++ spug_web/src/pages/deploy/request/index.js | 37 +----- spug_web/src/pages/deploy/request/store.js | 1 + 10 files changed, 182 insertions(+), 70 deletions(-) create mode 100644 spug_web/src/pages/deploy/request/BatchDelete.js diff --git a/spug_api/apps/app/models.py b/spug_api/apps/app/models.py index d69b3c7..a32e97c 100644 --- a/spug_api/apps/app/models.py +++ b/spug_api/apps/app/models.py @@ -2,10 +2,13 @@ # Copyright: (c) # Released under the AGPL-3.0 License. from django.db import models +from django.conf import settings from libs import ModelMixin, human_datetime from apps.account.models import User from apps.config.models import Environment +import subprocess import json +import os class App(models.Model, ModelMixin): @@ -62,8 +65,15 @@ class Deploy(models.Model, ModelMixin): deploy.update(self.extend_obj.to_dict()) return deploy + def delete(self, using=None, keep_parents=False): + deploy_id = self.id + super().delete(using, keep_parents) + repo_dir = os.path.join(settings.REPOS_DIR, str(deploy_id)) + build_dir = os.path.join(settings.BUILD_DIR, f'{deploy_id}_*') + subprocess.Popen(f'rm -rf {repo_dir} {repo_dir + "_*"} {build_dir}', shell=True) + def __repr__(self): - return '' % self.app_id + return '' % (self.app_id, self.env_id) class Meta: db_table = 'deploys' diff --git a/spug_api/apps/app/views.py b/spug_api/apps/app/views.py index 0e52b5d..a6e8375 100644 --- a/spug_api/apps/app/views.py +++ b/spug_api/apps/app/views.py @@ -3,15 +3,12 @@ # Released under the AGPL-3.0 License. from django.views.generic import View from django.db.models import F -from django.conf import settings from libs import JsonParser, Argument, json_response from apps.app.models import App, Deploy, DeployExtend1, DeployExtend2 from apps.config.models import Config from apps.app.utils import fetch_versions, remove_repo from apps.setting.utils import AppSetting -import subprocess import json -import os import re @@ -164,11 +161,11 @@ class DeployView(View): ).parse(request.GET) if error is None: deploy = Deploy.objects.get(pk=form.id) - if deploy.repository_set.exists(): - return json_response(error='已存在关联的构建版本,请删除关联的构建版本后再尝试删除发布配置') + if deploy.deployrequest_set.exists(): + return json_response(error='已存在关联的发布记录,请删除关联的发布记录后再尝试删除发布配置') + for item in deploy.repository_set.all(): + item.delete() deploy.delete() - repo_dir = os.path.join(settings.REPOS_DIR, str(form.id)) - subprocess.Popen(f'rm -rf {repo_dir} {repo_dir + "_*"}', shell=True) return json_response(error=error) diff --git a/spug_api/apps/deploy/models.py b/spug_api/apps/deploy/models.py index c55d5d8..e6f3a8e 100644 --- a/spug_api/apps/deploy/models.py +++ b/spug_api/apps/deploy/models.py @@ -2,11 +2,13 @@ # Copyright: (c) # Released under the AGPL-3.0 License. from django.db import models +from django.conf import settings from libs import ModelMixin, human_datetime from apps.account.models import User from apps.app.models import Deploy from apps.repository.models import Repository import json +import os class DeployRequest(models.Model, ModelMixin): @@ -50,6 +52,17 @@ class DeployRequest(models.Model, ModelMixin): return extra[0] in ('branch', 'tag') return False + def delete(self, using=None, keep_parents=False): + super().delete(using, keep_parents) + if self.repository_id: + if not DeployRequest.objects.filter(repository=self.repository).exists(): + self.repository.delete() + if self.deploy.extend == '2': + try: + os.remove(os.path.join(settings.REPOS_DIR, str(self.deploy_id), self.spug_version)) + except FileNotFoundError: + pass + def __repr__(self): return f'' diff --git a/spug_api/apps/deploy/views.py b/spug_api/apps/deploy/views.py index 9d1c9c6..8d8c9f2 100644 --- a/spug_api/apps/deploy/views.py +++ b/spug_api/apps/deploy/views.py @@ -85,36 +85,37 @@ class RequestView(View): def delete(self, request): form, error = JsonParser( Argument('id', type=int, required=False), - Argument('expire', required=False), - Argument('count', type=int, required=False, help='请输入数字') + Argument('mode', filter=lambda x: x in ('count', 'expire', 'deploy'), required=False, help='参数错误'), + Argument('value', required=False), ).parse(request.GET) if error is None: - rds = get_redis_connection() if form.id: - DeployRequest.objects.filter(pk=form.id, status__in=('0', '1', '-1')).delete() + deploy = DeployRequest.objects.filter(pk=form.id).first() + if not deploy or deploy.status not in ('0', '1', '-1'): + return json_response(error='未找到指定发布申请或当前状态不允许删除') + deploy.delete() return json_response() - elif form.count: - if form.count < 1: + + count = 0 + if form.mode == 'count': + if not str(form.value).isdigit() or int(form.value) < 1: return json_response(error='请输入正确的保留数量') - counter, ids = defaultdict(int), [] + counter, form.value = defaultdict(int), int(form.value) for item in DeployRequest.objects.all(): - if counter[item.deploy_id] == form.count: - ids.append(item.id) - else: - counter[item.deploy_id] += 1 - count, _ = DeployRequest.objects.filter(id__in=ids).delete() - if ids: - rds.delete(*(f'{settings.REQUEST_KEY}:{x}' for x in ids)) - return json_response(count) - elif form.expire: - requests = DeployRequest.objects.filter(created_at__lt=form.expire) - ids = [x.id for x in requests] - count, _ = requests.delete() - if ids: - rds.delete(*(f'{settings.REQUEST_KEY}:{x}' for x in ids)) - return json_response(count) - else: - return json_response(error='请至少使用一个删除条件') + counter[item.deploy_id] += 1 + if counter[item.deploy_id] > form.value: + count += 1 + item.delete() + elif form.mode == 'expire': + for item in DeployRequest.objects.filter(created_at__lt=form.value): + count += 1 + item.delete() + elif form.mode == 'deploy': + app_id, env_id = str(form.value).split(',') + for item in DeployRequest.objects.filter(deploy__app_id=app_id, deploy__env_id=env_id): + count += 1 + item.delete() + return json_response(count) return json_response(error=error) diff --git a/spug_api/apps/repository/models.py b/spug_api/apps/repository/models.py index 9cbc8b8..66a3919 100644 --- a/spug_api/apps/repository/models.py +++ b/spug_api/apps/repository/models.py @@ -2,11 +2,13 @@ # Copyright: (c) # Released under the AGPL-3.0 License. from django.db import models +from django.conf import settings from libs.mixins import ModelMixin from apps.app.models import App, Environment, Deploy from apps.account.models import User from datetime import datetime import json +import os class Repository(models.Model, ModelMixin): @@ -43,7 +45,14 @@ class Repository(models.Model, ModelMixin): tmp['created_by_user'] = self.created_by_user return tmp + def delete(self, using=None, keep_parents=False): + super().delete(using, keep_parents) + try: + build_file = f'{self.spug_version}.tar.gz' + os.remove(os.path.join(settings.BUILD_DIR, build_file)) + except FileNotFoundError: + pass + class Meta: db_table = 'repositories' ordering = ('-id',) - diff --git a/spug_api/apps/repository/views.py b/spug_api/apps/repository/views.py index bbf0b2f..40a64d7 100644 --- a/spug_api/apps/repository/views.py +++ b/spug_api/apps/repository/views.py @@ -12,7 +12,6 @@ from apps.repository.utils import dispatch from apps.app.models import Deploy from threading import Thread import json -import os class RepositoryView(View): @@ -83,11 +82,6 @@ class RepositoryView(View): if repository.deployrequest_set.exists(): return json_response(error='已关联发布申请无法删除') repository.delete() - build_file = f'{repository.spug_version}.tar.gz' - try: - os.remove(os.path.join(settings.REPOS_DIR, 'build', build_file)) - except FileNotFoundError: - pass return json_response(error=error) diff --git a/spug_api/spug/settings.py b/spug_api/spug/settings.py index a920bbb..cdce16f 100644 --- a/spug_api/spug/settings.py +++ b/spug_api/spug/settings.py @@ -110,6 +110,7 @@ EXEC_WORKER_KEY = 'spug:exec:worker' REQUEST_KEY = 'spug:request' BUILD_KEY = 'spug:build' REPOS_DIR = os.path.join(BASE_DIR, 'repos') +BUILD_DIR = os.path.join(REPOS_DIR, 'build') # Internationalization # https://docs.djangoproject.com/en/2.2/topics/i18n/ diff --git a/spug_web/src/pages/deploy/request/BatchDelete.js b/spug_web/src/pages/deploy/request/BatchDelete.js new file mode 100644 index 0000000..e509ce8 --- /dev/null +++ b/spug_web/src/pages/deploy/request/BatchDelete.js @@ -0,0 +1,111 @@ +/** + * Copyright (c) OpenSpug Organization. https://github.com/openspug/spug + * Copyright (c) + * Released under the AGPL-3.0 License. + */ +import React, { useState, useEffect } from 'react'; +import { observer } from 'mobx-react'; +import { Modal, Form, Input, Select, Radio, DatePicker, Space, message } from 'antd'; +import { http, includes } from 'libs'; +import store from './store'; +import appStore from '../app/store'; +import envStore from 'pages/config/environment/store'; + +export default observer(function () { + const [mode, setMode] = useState('expire') + const [value, setValue] = useState() + const [appId, setAppId] = useState() + const [envId, setEnvId] = useState() + const [loading, setLoading] = useState() + + useEffect(() => { + if (Object.keys(appStore.records).length === 0) appStore.fetchRecords() + if (envStore.records.length === 0) envStore.fetchRecords() + }, []) + + function handleSubmit() { + const formData = {mode, value}; + if (mode === 'deploy') { + if (!appId || !envId) return message.error('请选择要删除的应用和环境') + formData.value = `${appId},${envId}` + } else if (mode === 'expire') { + if (!value) return message.error('请选择截止日期') + formData.value = value.format('YYYY-MM-DD') + } else if (!value) { + return message.error('请输入保留个数') + } + setLoading(true); + http.delete('/api/deploy/request/', {params: formData}) + .then(res => { + message.success(`删除 ${res} 条发布记录`); + store.batchVisible = false; + store.fetchRecords() + }, () => setLoading(false)) + } + + function handleChange(e) { + setMode(e.target.value) + setValue() + } + + return ( + store.batchVisible = false} + confirmLoading={loading} + onOk={handleSubmit}> +
+ + + 截止时间 + 保留记录 + 发布配置 + + + {mode === 'expire' && ( + 将删除截止日期之前的所有发布申请记录。}> + + + )} + {mode === 'count' && ( + + setValue(e.target.value)} placeholder="请输入保留个数"/> + + )} + {mode === 'deploy' && ( + + + + + + + )} +
+
+ ) +}) \ No newline at end of file diff --git a/spug_web/src/pages/deploy/request/index.js b/spug_web/src/pages/deploy/request/index.js index b33794d..0298f01 100644 --- a/spug_web/src/pages/deploy/request/index.js +++ b/spug_web/src/pages/deploy/request/index.js @@ -5,8 +5,8 @@ */ import React, { useEffect } from 'react'; import { observer } from 'mobx-react'; -import { ExclamationCircleOutlined, DeleteOutlined } from '@ant-design/icons'; -import { Form, Select, DatePicker, Modal, Input, Space, message } from 'antd'; +import { DeleteOutlined } from '@ant-design/icons'; +import { Select, DatePicker, Space } from 'antd'; import { SearchForm, AuthDiv, AuthButton, Breadcrumb, AppSelector } from 'components'; import Ext1Form from './Ext1Form'; import Ext2Form from './Ext2Form'; @@ -14,7 +14,8 @@ import Approve from './Approve'; import ComTable from './Table'; import Ext1Console from './Ext1Console'; import Ext2Console from './Ext2Console'; -import { http, includes } from 'libs'; +import BatchDelete from './BatchDelete'; +import { includes } from 'libs'; import envStore from 'pages/config/environment/store'; import appStore from 'pages/config/app/store'; import store from './store'; @@ -29,33 +30,6 @@ function Index() { return () => store.leaveConsole() }, []) - function handleBatchDel() { - let [expire, count] = []; - Modal.confirm({ - icon: , - title: '批量删除发布申请', - content: ( -
- 将删除截止日期之前的所有发布申请记录。}> - expire = val.format('YYYY-MM-DD')}/> - - - count = e.target.value}/> - -
- ), - onOk: () => { - return http.delete('/api/deploy/request/', {params: {expire, count}}) - .then(res => { - message.success(`成功删除${res}条记录`); - store.fetchRecords() - }) - }, - }) - } - return ( @@ -100,7 +74,7 @@ function Index() { auth="deploy.request.del" type="danger" icon={} - onClick={handleBatchDel}>批量删除 + onClick={() => store.batchVisible = true}>批量删除 @@ -110,6 +84,7 @@ function Index() { onSelect={store.confirmAdd}/> {store.ext1Visible && } {store.ext2Visible && } + {store.batchVisible && } {store.approveVisible && } {store.tabs.length > 0 && ( diff --git a/spug_web/src/pages/deploy/request/store.js b/spug_web/src/pages/deploy/request/store.js index 3b823fc..4a1b27f 100644 --- a/spug_web/src/pages/deploy/request/store.js +++ b/spug_web/src/pages/deploy/request/store.js @@ -19,6 +19,7 @@ class Store { @observable addVisible = false; @observable ext1Visible = false; @observable ext2Visible = false; + @observable batchVisible = false; @observable approveVisible = false; @observable f_status = 'all';