From e5da67afbe316f728e371df16ea2d1460a02e681 Mon Sep 17 00:00:00 2001 From: charlesxie Date: Fri, 28 Jan 2022 16:09:30 +0800 Subject: [PATCH] feature:first commit --- .idea/.gitignore | 8 + .idea/bamboo_engine_playground.iml | 30 + .idea/dataSources.xml | 15 + .../19ee76cb-3424-4654-855f-f68454aff13a.xml | 3969 ++++++++++++ .../schema/information_schema.FNRwLQ.meta | 2 + .idea/inspectionProfiles/Project_Default.xml | 57 + .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 4 + .idea/modules.xml | 8 + __pycache__/manage.cpython-36.pyc | Bin 0 -> 813 bytes applications/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 150 bytes applications/flow/__init__.py | 0 .../flow/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 155 bytes .../flow/__pycache__/admin.cpython-36.pyc | Bin 0 -> 196 bytes .../flow/__pycache__/constants.cpython-36.pyc | Bin 0 -> 548 bytes .../flow/__pycache__/models.cpython-36.pyc | Bin 0 -> 2476 bytes .../__pycache__/serializers.cpython-36.pyc | Bin 0 -> 3642 bytes .../flow/__pycache__/urls.cpython-36.pyc | Bin 0 -> 347 bytes .../flow/__pycache__/views.cpython-36.pyc | Bin 0 -> 3415 bytes applications/flow/admin.py | 3 + applications/flow/apps.py | 6 + applications/flow/constants.py | 14 + applications/flow/migrations/0001_initial.py | 65 + .../migrations/0002_auto_20220128_1556.py | 18 + applications/flow/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-36.pyc | Bin 0 -> 2580 bytes .../0002_auto_20220128_1556.cpython-36.pyc | Bin 0 -> 620 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 166 bytes applications/flow/models.py | 52 + applications/flow/serializers.py | 100 + applications/flow/tests.py | 3 + applications/flow/urls.py | 6 + applications/flow/views.py | 103 + applications/utils/__init__.py | 0 .../utils/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 156 bytes .../__pycache__/dag_helper.cpython-36.pyc | Bin 0 -> 7249 bytes applications/utils/dag_helper.py | 205 + component/__init__.py | 0 component/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 147 bytes component/drf/__init__.py | 1 + .../drf/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 141 bytes .../drf/__pycache__/constants.cpython-36.pyc | Bin 0 -> 717 bytes .../drf/__pycache__/mixins.cpython-36.pyc | Bin 0 -> 1969 bytes .../drf/__pycache__/pagination.cpython-36.pyc | Bin 0 -> 1201 bytes .../drf/__pycache__/viewsets.cpython-36.pyc | Bin 0 -> 4963 bytes component/drf/authentication.py | 6 + component/drf/constants.py | 31 + component/drf/filters.py | 37 + component/drf/generics.py | 66 + component/drf/mapping.py | 18 + component/drf/middleware.py | 104 + component/drf/mixins.py | 82 + component/drf/pagination.py | 37 + component/drf/renderers.py | 64 + component/drf/viewsets.py | 136 + component/utils/__init__.py | 4 + .../utils/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 190 bytes .../utils/__pycache__/basic.cpython-36.pyc | Bin 0 -> 867 bytes .../utils/__pycache__/drf.cpython-36.pyc | Bin 0 -> 917 bytes component/utils/basic.py | 18 + component/utils/drf.py | 24 + component/utils/exceptions.py | 117 + custom_plugins/__init__.py | 2 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 152 bytes .../__pycache__/apps.cpython-36.pyc | Bin 0 -> 440 bytes custom_plugins/apps.py | 7 + custom_plugins/components/__init__.py | 10 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 398 bytes .../components/collections/__init__.py | 10 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 410 bytes .../__pycache__/plugins.cpython-36.pyc | Bin 0 -> 999 bytes .../components/collections/plugins.py | 22 + custom_plugins/migrations/__init__.py | 1 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 163 bytes .../static/custom_plugins/plugins.js | 12 + custom_plugins/tests/__init__.py | 21 + custom_plugins/tests/components/__init__.py | 21 + .../tests/components/collections/__init__.py | 21 + .../collections/plugins_test/__init__.py | 21 + db.sqlite3 | Bin 0 -> 626688 bytes dj_flow/__init__.py | 3 + dj_flow/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 210 bytes dj_flow/__pycache__/celery_app.cpython-36.pyc | Bin 0 -> 1623 bytes dj_flow/__pycache__/settings.cpython-36.pyc | Bin 0 -> 3514 bytes dj_flow/__pycache__/urls.cpython-36.pyc | Bin 0 -> 1014 bytes dj_flow/__pycache__/wsgi.cpython-36.pyc | Bin 0 -> 541 bytes dj_flow/celery_app.py | 41 + dj_flow/settings.py | 146 + dj_flow/urls.py | 24 + dj_flow/wsgi.py | 16 + manage.py | 22 + requirements.txt | 9 + templates/index.html | 25 + web/.babelrc | 15 + web/.editorconfig | 9 + web/.eslintignore | 8 + web/.eslintrc.js | 1325 ++++ web/.gitignore | 14 + web/.postcssrc.js | 10 + web/.stylelintrc.js | 214 + web/README.md | 9 + web/build/build.js | 41 + web/build/check-versions.js | 54 + web/build/logo.png | Bin 0 -> 6849 bytes web/build/utils.js | 108 + web/build/vue-loader.conf.js | 22 + web/build/webpack.base.conf.js | 111 + web/build/webpack.dev.conf.js | 103 + web/build/webpack.prod.conf.js | 150 + web/config/dev.env.js | 7 + web/config/index.js | 86 + web/config/prod.env.js | 4 + web/debug.log | 5 + web/docs/install.md | 38 + web/docs/use.md | 41 + web/index.html | 16 + web/index.prod.html | 3 + web/package.json | 111 + web/src/App.vue | 122 + web/src/api/apiUrl/history/node_history.js | 10 + web/src/api/apiUrl/history/process_history.js | 10 + web/src/api/apiUrl/monitor/node_run.js | 19 + web/src/api/apiUrl/monitor/process_run.js | 29 + web/src/api/apiUrl/report/process_report.js | 16 + web/src/api/apiUrl/system/alarm_center.js | 7 + web/src/api/apiUrl/system/audit_log.js | 11 + web/src/api/apiUrl/system/category.js | 26 + web/src/api/apiUrl/system/home.js | 19 + web/src/api/apiUrl/system/setting.js | 23 + web/src/api/apiUrl/system/show_table.js | 11 + web/src/api/apiUrl/system/user.js | 29 + web/src/api/apiUrl/template/calendar.js | 23 + web/src/api/apiUrl/template/content.js | 35 + web/src/api/apiUrl/template/node.js | 7 + web/src/api/apiUrl/template/process.js | 45 + web/src/api/apiUrl/template/station.js | 29 + web/src/api/apiUrl/template/station_state.js | 8 + web/src/api/apiUrl/template/var_table.js | 20 + web/src/api/axiosconfig/Interceptor.js | 58 + web/src/api/axiosconfig/axiosconfig.js | 116 + web/src/api/index.js | 45 + web/src/assets/ECharts/dataTool.min.js | 21 + web/src/assets/base/css/base.scss | 52 + web/src/assets/base/css/color.scss | 50 + web/src/assets/base/css/headMenu.scss | 64 + web/src/assets/base/css/leftMenu.scss | 117 + web/src/assets/base/css/other.scss | 225 + web/src/assets/base/css/unify.scss | 465 ++ web/src/assets/base/font/bkicon/Read Me.txt | 7 + .../base/font/bkicon/demo-files/demo.css | 152 + .../base/font/bkicon/demo-files/demo.js | 30 + web/src/assets/base/font/bkicon/demo.html | 886 +++ .../assets/base/font/bkicon/fonts/icomoon.eot | Bin 0 -> 15740 bytes .../assets/base/font/bkicon/fonts/icomoon.svg | 63 + .../assets/base/font/bkicon/fonts/icomoon.ttf | Bin 0 -> 15576 bytes .../base/font/bkicon/fonts/icomoon.woff | Bin 0 -> 15652 bytes .../assets/base/font/bkicon/selection.json | 2427 +++++++ web/src/assets/base/font/bkicon/style.css | 238 + web/src/assets/base/img/back_forward_16.svg | 1 + .../assets/base/img/base_information_32.svg | 1 + web/src/assets/base/img/branch_28.svg | 1 + web/src/assets/base/img/branch_32.svg | 1 + web/src/assets/base/img/branch_40.svg | 1 + web/src/assets/base/img/branch_48.svg | 1 + web/src/assets/base/img/execute.png | Bin 0 -> 2508 bytes web/src/assets/base/img/flow_1x.png | Bin 0 -> 402 bytes web/src/assets/base/img/full_screen_16.png | Bin 0 -> 237 bytes web/src/assets/base/img/full_screen_16.svg | 1 + web/src/assets/base/img/job.png | Bin 0 -> 483 bytes web/src/assets/base/img/jobFlow.png | Bin 0 -> 606 bytes web/src/assets/base/img/jobFlow_16.png | Bin 0 -> 259 bytes web/src/assets/base/img/jobFlow_16.svg | 1 + web/src/assets/base/img/jobFlow_16_dark.png | Bin 0 -> 244 bytes web/src/assets/base/img/jobFlow_16_dark.svg | 1 + web/src/assets/base/img/jobFlow_22.png | Bin 0 -> 337 bytes web/src/assets/base/img/jobFlow_22.svg | 1 + web/src/assets/base/img/jobFlow_22_dark.png | Bin 0 -> 389 bytes web/src/assets/base/img/jobFlow_22_dark.svg | 1 + web/src/assets/base/img/jobFlow_28.png | Bin 0 -> 380 bytes web/src/assets/base/img/jobFlow_28_dark.png | Bin 0 -> 424 bytes web/src/assets/base/img/jobFlow_32.png | Bin 0 -> 493 bytes web/src/assets/base/img/jobFlow_32_dark.png | Bin 0 -> 587 bytes web/src/assets/base/img/jobFlow_dark.png | Bin 0 -> 580 bytes web/src/assets/base/img/job_2x.png | Bin 0 -> 973 bytes web/src/assets/base/img/job_dark_16_new.svg | 1 + web/src/assets/base/img/logo.png | Bin 0 -> 47032 bytes web/src/assets/base/img/photo.jpg | Bin 0 -> 2300 bytes web/src/assets/base/img/red_cross.png | Bin 0 -> 533 bytes web/src/assets/base/img/run-batch.png | Bin 0 -> 9355 bytes web/src/assets/base/img/save_16.svg | 1 + web/src/assets/base/img/system.png | Bin 0 -> 414 bytes web/src/assets/base/img/system_16.png | Bin 0 -> 160 bytes web/src/assets/base/img/system_16.svg | 1 + web/src/assets/base/img/system_16_dark.png | Bin 0 -> 163 bytes web/src/assets/base/img/system_16_dark.svg | 1 + web/src/assets/base/img/system_28.png | Bin 0 -> 256 bytes web/src/assets/base/img/system_28.svg | 1 + web/src/assets/base/img/system_28_dark.png | Bin 0 -> 265 bytes web/src/assets/base/img/system_28_dark.svg | 1 + web/src/assets/base/img/system_blue.svg | 1 + web/src/assets/base/img/system_design.png | Bin 0 -> 387 bytes web/src/assets/base/img/system_new.png | Bin 0 -> 501 bytes web/src/assets/base/img/table.svg | 1 + web/src/assets/base/img/task_format_32.svg | 1 + web/src/assets/base/img/white_logo.png | Bin 0 -> 41392 bytes web/src/assets/custom/css/common.scss | 144 + web/src/assets/custom_icon/demo.css | 539 ++ web/src/assets/custom_icon/demo_index.html | 5593 +++++++++++++++++ web/src/assets/custom_icon/iconfont.css | 954 +++ web/src/assets/custom_icon/iconfont.js | 1 + web/src/assets/custom_icon/iconfont.json | 1654 +++++ web/src/assets/custom_icon/iconfont.ttf | Bin 0 -> 59556 bytes web/src/assets/custom_icon/iconfont.woff | Bin 0 -> 32496 bytes web/src/assets/custom_icon/iconfont.woff2 | Bin 0 -> 27144 bytes web/src/assets/index.js | 8 + web/src/common/date.js | 55 + web/src/common/message.js | 39 + web/src/common/store.js | 62 + web/src/common/util.js | 116 + web/src/common/validate.js | 253 + .../components/FullYearCalendar/calendar.vue | 181 + .../FullYearCalendar/css/datePacker.css | 88 + .../FullYearCalendar/js/fullYearPicker.js | 339 + .../FullYearCalendar/new_calendar.vue | 181 + .../FullYearCalendar/old_calendar.vue | 189 + .../FullYearCalendar/work_holiday_compute.js | 368 ++ .../components/base/magicMenu/container.vue | 36 + web/src/components/base/magicMenu/header.vue | 248 + web/src/components/base/magicMenu/index.vue | 81 + .../components/base/magicMenu/leftMenu.vue | 152 + .../components/graph/behavior/active-edge.js | 26 + .../components/graph/behavior/drag-node.js | 365 ++ web/src/components/graph/behavior/exports.js | 13 + .../components/graph/behavior/hover-edge.js | 41 + .../components/graph/behavior/hover-node.js | 35 + .../components/graph/behavior/select-node.js | 57 + web/src/components/graph/graph.js | 89 + web/src/components/graph/register-factory.js | 12 + .../components/graph/shape/defaultStyle.js | 85 + .../components/graph/shape/edges/base-edge.js | 198 + .../graph/shape/edges/item-event.js | 81 + web/src/components/graph/shape/exports.js | 8 + .../graph/shape/items/anchor-event.js | 51 + .../components/graph/shape/items/base-node.js | 384 ++ .../components/graph/shape/items/colorList.js | 95 + .../graph/shape/items/item-event.js | 144 + web/src/components/graph/shape/node.js | 75 + web/src/components/index.js | 34 + web/src/components/iview/index.js | 11 + web/src/components/monacoEditor/index.vue | 86 + web/src/fiter/index.js | 1 + web/src/fiter/validator/validator.js | 48 + web/src/main.js | 79 + web/src/promission.js | 611 ++ web/src/router/_import_development.js | 1 + web/src/router/_import_production.js | 1 + web/src/router/index.js | 14 + web/src/views/agent_mgmt/agent_dialog.vue | 215 + web/src/views/agent_mgmt/agent_list.vue | 308 + web/src/views/agent_mgmt/agent_monitor.vue | 247 + web/src/views/alarm_center/alarm_list.vue | 228 + web/src/views/home/home.vue | 697 ++ .../views/job_flow_mgmt/add_calendar_mgmt.vue | 439 ++ web/src/views/job_flow_mgmt/calendar_mgmt.vue | 346 + web/src/views/job_flow_mgmt/import_file.vue | 143 + web/src/views/job_flow_mgmt/job_flow_list.vue | 487 ++ .../views/job_flow_mgmt/multiple_job_flow.vue | 140 + .../job_flow_mgmt/new_add_calendar_mgmt.vue | 392 ++ web/src/views/job_flow_mgmt/new_job_flow.vue | 105 + .../job_flow_mgmt/old_add_calendar_mgmt.vue | 596 ++ .../views/job_flow_mgmt/single_job_flow.vue | 766 +++ .../single_job_flow/baseInfo.vue | 512 ++ .../job_flow_mgmt/single_job_flow/baseNode.js | 69 + .../single_job_flow/edgeInfo.vue | 144 + .../single_job_flow/headerPanel.vue | 537 ++ .../single_job_flow/nodeInfo.vue | 343 + .../job_flow_mgmt/single_job_flow/options.js | 91 + .../single_job_flow/taskMake.vue | 373 ++ .../views/job_flow_mgmt/variable_change.vue | 243 + web/src/views/job_flow_mgmt/variable_mgmt.vue | 230 + web/src/views/job_mgmt/job_dialog.vue | 268 + web/src/views/job_mgmt/job_list.vue | 526 ++ web/src/views/job_mgmt/multiple_job.vue | 140 + web/src/views/job_mgmt/new_job.vue | 104 + web/src/views/job_mgmt/scan_file.vue | 152 + web/src/views/job_mgmt/single_job.vue | 664 ++ .../job_monitor/history/job_flow_detail.vue | 497 ++ .../history/job_flow_detail/nodeInfo.vue | 244 + .../history/job_flow_detail/statusList.js | 72 + .../history/job_flow_detail/statusList.vue | 55 + .../history/job_flow_view_history.vue | 262 + .../views/job_monitor/history/job_history.vue | 54 + .../job_monitor/history/job_view_detail.vue | 215 + .../job_monitor/history/job_view_history.vue | 236 + .../views/job_monitor/monitor/job_detail.vue | 227 + .../job_monitor/monitor/job_flow_view.vue | 668 ++ .../monitor/job_flow_view_detail/nodeInfo.vue | 245 + .../job_flow_view_detail/statusList.js | 71 + .../job_flow_view_detail/statusList.vue | 56 + .../views/job_monitor/monitor/job_monitor.vue | 55 + .../views/job_monitor/monitor/job_view.vue | 647 ++ .../views/job_monitor/monitor/view_detail.vue | 696 ++ .../job_monitor_large_screen/large_screen.vue | 430 ++ .../job_monitor_large_screen/statusList.js | 53 + .../job_monitor_large_screen/statusList.vue | 56 + .../job_monitor_large_screen/topMenu.vue | 79 + .../views/job_monitor_large_screen/tree.vue | 73 + web/src/views/report/job_flow_view_report.vue | 580 ++ web/src/views/report/job_view_report.vue | 595 ++ web/src/views/report/report.vue | 76 + web/src/views/system/log.vue | 226 + web/src/views/system/log_mange.vue | 9 + web/src/views/system/sys_setup.vue | 268 + web/src/views/system/system_class_manage.vue | 220 + .../system_class_manage/systemDialog.vue | 51 + web/src/views/system/user_and_permissions.vue | 290 + .../user_and_permissions/addUserDialog.vue | 160 + .../system/user_and_permissions/userInfo.vue | 130 + web/src/vuex/actions.js | 4 + web/src/vuex/getters.js | 8 + web/src/vuex/index.js | 21 + web/src/vuex/module/common.js | 12 + web/src/vuex/module/history.js | 34 + web/src/vuex/module/monitor.js | 34 + web/src/vuex/module/permission.js | 13 + web/static/css/.gitkeep | 14 + web/static/img/.gitkeep | 14 + web/static/img/flow_1x.png | Bin 0 -> 402 bytes web/static/img/full_screen_16.png | Bin 0 -> 237 bytes web/static/img/job.png | Bin 0 -> 483 bytes web/static/img/jobFlow.png | Bin 0 -> 606 bytes web/static/img/jobFlow_16.png | Bin 0 -> 259 bytes web/static/img/jobFlow_16_dark.png | Bin 0 -> 244 bytes web/static/img/jobFlow_22.png | Bin 0 -> 337 bytes web/static/img/jobFlow_22_dark.png | Bin 0 -> 389 bytes web/static/img/jobFlow_28.png | Bin 0 -> 380 bytes web/static/img/jobFlow_28_dark.png | Bin 0 -> 424 bytes web/static/img/jobFlow_32.png | Bin 0 -> 493 bytes web/static/img/jobFlow_32_dark.png | Bin 0 -> 587 bytes web/static/img/jobFlow_dark.png | Bin 0 -> 580 bytes web/static/img/job_2x.png | Bin 0 -> 973 bytes web/static/img/red_cross.png | Bin 0 -> 533 bytes web/static/img/system.png | Bin 0 -> 414 bytes web/static/img/system_16.png | Bin 0 -> 160 bytes web/static/img/system_16_dark.png | Bin 0 -> 163 bytes web/static/img/system_28.png | Bin 0 -> 256 bytes web/static/img/system_28_dark.png | Bin 0 -> 265 bytes web/static/img/system_blue.svg | 1 + web/static/img/system_design.png | Bin 0 -> 387 bytes web/static/img/system_new.png | Bin 0 -> 501 bytes web/static/js/.gitkeep | 14 + 352 files changed, 45088 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/bamboo_engine_playground.iml create mode 100644 .idea/dataSources.xml create mode 100644 .idea/dataSources/19ee76cb-3424-4654-855f-f68454aff13a.xml create mode 100644 .idea/dataSources/19ee76cb-3424-4654-855f-f68454aff13a/storage_v2/_src_/schema/information_schema.FNRwLQ.meta create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 __pycache__/manage.cpython-36.pyc create mode 100644 applications/__init__.py create mode 100644 applications/__pycache__/__init__.cpython-36.pyc create mode 100644 applications/flow/__init__.py create mode 100644 applications/flow/__pycache__/__init__.cpython-36.pyc create mode 100644 applications/flow/__pycache__/admin.cpython-36.pyc create mode 100644 applications/flow/__pycache__/constants.cpython-36.pyc create mode 100644 applications/flow/__pycache__/models.cpython-36.pyc create mode 100644 applications/flow/__pycache__/serializers.cpython-36.pyc create mode 100644 applications/flow/__pycache__/urls.cpython-36.pyc create mode 100644 applications/flow/__pycache__/views.cpython-36.pyc create mode 100644 applications/flow/admin.py create mode 100644 applications/flow/apps.py create mode 100644 applications/flow/constants.py create mode 100644 applications/flow/migrations/0001_initial.py create mode 100644 applications/flow/migrations/0002_auto_20220128_1556.py create mode 100644 applications/flow/migrations/__init__.py create mode 100644 applications/flow/migrations/__pycache__/0001_initial.cpython-36.pyc create mode 100644 applications/flow/migrations/__pycache__/0002_auto_20220128_1556.cpython-36.pyc create mode 100644 applications/flow/migrations/__pycache__/__init__.cpython-36.pyc create mode 100644 applications/flow/models.py create mode 100644 applications/flow/serializers.py create mode 100644 applications/flow/tests.py create mode 100644 applications/flow/urls.py create mode 100644 applications/flow/views.py create mode 100644 applications/utils/__init__.py create mode 100644 applications/utils/__pycache__/__init__.cpython-36.pyc create mode 100644 applications/utils/__pycache__/dag_helper.cpython-36.pyc create mode 100644 applications/utils/dag_helper.py create mode 100644 component/__init__.py create mode 100644 component/__pycache__/__init__.cpython-36.pyc create mode 100644 component/drf/__init__.py create mode 100644 component/drf/__pycache__/__init__.cpython-36.pyc create mode 100644 component/drf/__pycache__/constants.cpython-36.pyc create mode 100644 component/drf/__pycache__/mixins.cpython-36.pyc create mode 100644 component/drf/__pycache__/pagination.cpython-36.pyc create mode 100644 component/drf/__pycache__/viewsets.cpython-36.pyc create mode 100644 component/drf/authentication.py create mode 100644 component/drf/constants.py create mode 100644 component/drf/filters.py create mode 100644 component/drf/generics.py create mode 100644 component/drf/mapping.py create mode 100644 component/drf/middleware.py create mode 100644 component/drf/mixins.py create mode 100644 component/drf/pagination.py create mode 100644 component/drf/renderers.py create mode 100644 component/drf/viewsets.py create mode 100644 component/utils/__init__.py create mode 100644 component/utils/__pycache__/__init__.cpython-36.pyc create mode 100644 component/utils/__pycache__/basic.cpython-36.pyc create mode 100644 component/utils/__pycache__/drf.cpython-36.pyc create mode 100644 component/utils/basic.py create mode 100644 component/utils/drf.py create mode 100644 component/utils/exceptions.py create mode 100644 custom_plugins/__init__.py create mode 100644 custom_plugins/__pycache__/__init__.cpython-36.pyc create mode 100644 custom_plugins/__pycache__/apps.cpython-36.pyc create mode 100644 custom_plugins/apps.py create mode 100644 custom_plugins/components/__init__.py create mode 100644 custom_plugins/components/__pycache__/__init__.cpython-36.pyc create mode 100644 custom_plugins/components/collections/__init__.py create mode 100644 custom_plugins/components/collections/__pycache__/__init__.cpython-36.pyc create mode 100644 custom_plugins/components/collections/__pycache__/plugins.cpython-36.pyc create mode 100644 custom_plugins/components/collections/plugins.py create mode 100644 custom_plugins/migrations/__init__.py create mode 100644 custom_plugins/migrations/__pycache__/__init__.cpython-36.pyc create mode 100644 custom_plugins/static/custom_plugins/plugins.js create mode 100644 custom_plugins/tests/__init__.py create mode 100644 custom_plugins/tests/components/__init__.py create mode 100644 custom_plugins/tests/components/collections/__init__.py create mode 100644 custom_plugins/tests/components/collections/plugins_test/__init__.py create mode 100644 db.sqlite3 create mode 100644 dj_flow/__init__.py create mode 100644 dj_flow/__pycache__/__init__.cpython-36.pyc create mode 100644 dj_flow/__pycache__/celery_app.cpython-36.pyc create mode 100644 dj_flow/__pycache__/settings.cpython-36.pyc create mode 100644 dj_flow/__pycache__/urls.cpython-36.pyc create mode 100644 dj_flow/__pycache__/wsgi.cpython-36.pyc create mode 100644 dj_flow/celery_app.py create mode 100644 dj_flow/settings.py create mode 100644 dj_flow/urls.py create mode 100644 dj_flow/wsgi.py create mode 100644 manage.py create mode 100644 requirements.txt create mode 100644 templates/index.html create mode 100644 web/.babelrc create mode 100644 web/.editorconfig create mode 100644 web/.eslintignore create mode 100644 web/.eslintrc.js create mode 100644 web/.gitignore create mode 100644 web/.postcssrc.js create mode 100644 web/.stylelintrc.js create mode 100644 web/README.md create mode 100644 web/build/build.js create mode 100644 web/build/check-versions.js create mode 100644 web/build/logo.png create mode 100644 web/build/utils.js create mode 100644 web/build/vue-loader.conf.js create mode 100644 web/build/webpack.base.conf.js create mode 100644 web/build/webpack.dev.conf.js create mode 100644 web/build/webpack.prod.conf.js create mode 100644 web/config/dev.env.js create mode 100644 web/config/index.js create mode 100644 web/config/prod.env.js create mode 100644 web/debug.log create mode 100644 web/docs/install.md create mode 100644 web/docs/use.md create mode 100644 web/index.html create mode 100644 web/index.prod.html create mode 100644 web/package.json create mode 100644 web/src/App.vue create mode 100644 web/src/api/apiUrl/history/node_history.js create mode 100644 web/src/api/apiUrl/history/process_history.js create mode 100644 web/src/api/apiUrl/monitor/node_run.js create mode 100644 web/src/api/apiUrl/monitor/process_run.js create mode 100644 web/src/api/apiUrl/report/process_report.js create mode 100644 web/src/api/apiUrl/system/alarm_center.js create mode 100644 web/src/api/apiUrl/system/audit_log.js create mode 100644 web/src/api/apiUrl/system/category.js create mode 100644 web/src/api/apiUrl/system/home.js create mode 100644 web/src/api/apiUrl/system/setting.js create mode 100644 web/src/api/apiUrl/system/show_table.js create mode 100644 web/src/api/apiUrl/system/user.js create mode 100644 web/src/api/apiUrl/template/calendar.js create mode 100644 web/src/api/apiUrl/template/content.js create mode 100644 web/src/api/apiUrl/template/node.js create mode 100644 web/src/api/apiUrl/template/process.js create mode 100644 web/src/api/apiUrl/template/station.js create mode 100644 web/src/api/apiUrl/template/station_state.js create mode 100644 web/src/api/apiUrl/template/var_table.js create mode 100644 web/src/api/axiosconfig/Interceptor.js create mode 100644 web/src/api/axiosconfig/axiosconfig.js create mode 100644 web/src/api/index.js create mode 100644 web/src/assets/ECharts/dataTool.min.js create mode 100644 web/src/assets/base/css/base.scss create mode 100644 web/src/assets/base/css/color.scss create mode 100644 web/src/assets/base/css/headMenu.scss create mode 100644 web/src/assets/base/css/leftMenu.scss create mode 100644 web/src/assets/base/css/other.scss create mode 100644 web/src/assets/base/css/unify.scss create mode 100644 web/src/assets/base/font/bkicon/Read Me.txt create mode 100644 web/src/assets/base/font/bkicon/demo-files/demo.css create mode 100644 web/src/assets/base/font/bkicon/demo-files/demo.js create mode 100644 web/src/assets/base/font/bkicon/demo.html create mode 100644 web/src/assets/base/font/bkicon/fonts/icomoon.eot create mode 100644 web/src/assets/base/font/bkicon/fonts/icomoon.svg create mode 100644 web/src/assets/base/font/bkicon/fonts/icomoon.ttf create mode 100644 web/src/assets/base/font/bkicon/fonts/icomoon.woff create mode 100644 web/src/assets/base/font/bkicon/selection.json create mode 100644 web/src/assets/base/font/bkicon/style.css create mode 100644 web/src/assets/base/img/back_forward_16.svg create mode 100644 web/src/assets/base/img/base_information_32.svg create mode 100644 web/src/assets/base/img/branch_28.svg create mode 100644 web/src/assets/base/img/branch_32.svg create mode 100644 web/src/assets/base/img/branch_40.svg create mode 100644 web/src/assets/base/img/branch_48.svg create mode 100644 web/src/assets/base/img/execute.png create mode 100644 web/src/assets/base/img/flow_1x.png create mode 100644 web/src/assets/base/img/full_screen_16.png create mode 100644 web/src/assets/base/img/full_screen_16.svg create mode 100644 web/src/assets/base/img/job.png create mode 100644 web/src/assets/base/img/jobFlow.png create mode 100644 web/src/assets/base/img/jobFlow_16.png create mode 100644 web/src/assets/base/img/jobFlow_16.svg create mode 100644 web/src/assets/base/img/jobFlow_16_dark.png create mode 100644 web/src/assets/base/img/jobFlow_16_dark.svg create mode 100644 web/src/assets/base/img/jobFlow_22.png create mode 100644 web/src/assets/base/img/jobFlow_22.svg create mode 100644 web/src/assets/base/img/jobFlow_22_dark.png create mode 100644 web/src/assets/base/img/jobFlow_22_dark.svg create mode 100644 web/src/assets/base/img/jobFlow_28.png create mode 100644 web/src/assets/base/img/jobFlow_28_dark.png create mode 100644 web/src/assets/base/img/jobFlow_32.png create mode 100644 web/src/assets/base/img/jobFlow_32_dark.png create mode 100644 web/src/assets/base/img/jobFlow_dark.png create mode 100644 web/src/assets/base/img/job_2x.png create mode 100644 web/src/assets/base/img/job_dark_16_new.svg create mode 100644 web/src/assets/base/img/logo.png create mode 100644 web/src/assets/base/img/photo.jpg create mode 100644 web/src/assets/base/img/red_cross.png create mode 100644 web/src/assets/base/img/run-batch.png create mode 100644 web/src/assets/base/img/save_16.svg create mode 100644 web/src/assets/base/img/system.png create mode 100644 web/src/assets/base/img/system_16.png create mode 100644 web/src/assets/base/img/system_16.svg create mode 100644 web/src/assets/base/img/system_16_dark.png create mode 100644 web/src/assets/base/img/system_16_dark.svg create mode 100644 web/src/assets/base/img/system_28.png create mode 100644 web/src/assets/base/img/system_28.svg create mode 100644 web/src/assets/base/img/system_28_dark.png create mode 100644 web/src/assets/base/img/system_28_dark.svg create mode 100644 web/src/assets/base/img/system_blue.svg create mode 100644 web/src/assets/base/img/system_design.png create mode 100644 web/src/assets/base/img/system_new.png create mode 100644 web/src/assets/base/img/table.svg create mode 100644 web/src/assets/base/img/task_format_32.svg create mode 100644 web/src/assets/base/img/white_logo.png create mode 100644 web/src/assets/custom/css/common.scss create mode 100644 web/src/assets/custom_icon/demo.css create mode 100644 web/src/assets/custom_icon/demo_index.html create mode 100644 web/src/assets/custom_icon/iconfont.css create mode 100644 web/src/assets/custom_icon/iconfont.js create mode 100644 web/src/assets/custom_icon/iconfont.json create mode 100644 web/src/assets/custom_icon/iconfont.ttf create mode 100644 web/src/assets/custom_icon/iconfont.woff create mode 100644 web/src/assets/custom_icon/iconfont.woff2 create mode 100644 web/src/assets/index.js create mode 100644 web/src/common/date.js create mode 100644 web/src/common/message.js create mode 100644 web/src/common/store.js create mode 100644 web/src/common/util.js create mode 100644 web/src/common/validate.js create mode 100644 web/src/components/FullYearCalendar/calendar.vue create mode 100644 web/src/components/FullYearCalendar/css/datePacker.css create mode 100644 web/src/components/FullYearCalendar/js/fullYearPicker.js create mode 100644 web/src/components/FullYearCalendar/new_calendar.vue create mode 100644 web/src/components/FullYearCalendar/old_calendar.vue create mode 100644 web/src/components/FullYearCalendar/work_holiday_compute.js create mode 100644 web/src/components/base/magicMenu/container.vue create mode 100644 web/src/components/base/magicMenu/header.vue create mode 100644 web/src/components/base/magicMenu/index.vue create mode 100644 web/src/components/base/magicMenu/leftMenu.vue create mode 100644 web/src/components/graph/behavior/active-edge.js create mode 100644 web/src/components/graph/behavior/drag-node.js create mode 100644 web/src/components/graph/behavior/exports.js create mode 100644 web/src/components/graph/behavior/hover-edge.js create mode 100644 web/src/components/graph/behavior/hover-node.js create mode 100644 web/src/components/graph/behavior/select-node.js create mode 100644 web/src/components/graph/graph.js create mode 100644 web/src/components/graph/register-factory.js create mode 100644 web/src/components/graph/shape/defaultStyle.js create mode 100644 web/src/components/graph/shape/edges/base-edge.js create mode 100644 web/src/components/graph/shape/edges/item-event.js create mode 100644 web/src/components/graph/shape/exports.js create mode 100644 web/src/components/graph/shape/items/anchor-event.js create mode 100644 web/src/components/graph/shape/items/base-node.js create mode 100644 web/src/components/graph/shape/items/colorList.js create mode 100644 web/src/components/graph/shape/items/item-event.js create mode 100644 web/src/components/graph/shape/node.js create mode 100644 web/src/components/index.js create mode 100644 web/src/components/iview/index.js create mode 100644 web/src/components/monacoEditor/index.vue create mode 100644 web/src/fiter/index.js create mode 100644 web/src/fiter/validator/validator.js create mode 100644 web/src/main.js create mode 100644 web/src/promission.js create mode 100644 web/src/router/_import_development.js create mode 100644 web/src/router/_import_production.js create mode 100644 web/src/router/index.js create mode 100644 web/src/views/agent_mgmt/agent_dialog.vue create mode 100644 web/src/views/agent_mgmt/agent_list.vue create mode 100644 web/src/views/agent_mgmt/agent_monitor.vue create mode 100644 web/src/views/alarm_center/alarm_list.vue create mode 100644 web/src/views/home/home.vue create mode 100644 web/src/views/job_flow_mgmt/add_calendar_mgmt.vue create mode 100644 web/src/views/job_flow_mgmt/calendar_mgmt.vue create mode 100644 web/src/views/job_flow_mgmt/import_file.vue create mode 100644 web/src/views/job_flow_mgmt/job_flow_list.vue create mode 100644 web/src/views/job_flow_mgmt/multiple_job_flow.vue create mode 100644 web/src/views/job_flow_mgmt/new_add_calendar_mgmt.vue create mode 100644 web/src/views/job_flow_mgmt/new_job_flow.vue create mode 100644 web/src/views/job_flow_mgmt/old_add_calendar_mgmt.vue create mode 100644 web/src/views/job_flow_mgmt/single_job_flow.vue create mode 100644 web/src/views/job_flow_mgmt/single_job_flow/baseInfo.vue create mode 100644 web/src/views/job_flow_mgmt/single_job_flow/baseNode.js create mode 100644 web/src/views/job_flow_mgmt/single_job_flow/edgeInfo.vue create mode 100644 web/src/views/job_flow_mgmt/single_job_flow/headerPanel.vue create mode 100644 web/src/views/job_flow_mgmt/single_job_flow/nodeInfo.vue create mode 100644 web/src/views/job_flow_mgmt/single_job_flow/options.js create mode 100644 web/src/views/job_flow_mgmt/single_job_flow/taskMake.vue create mode 100644 web/src/views/job_flow_mgmt/variable_change.vue create mode 100644 web/src/views/job_flow_mgmt/variable_mgmt.vue create mode 100644 web/src/views/job_mgmt/job_dialog.vue create mode 100644 web/src/views/job_mgmt/job_list.vue create mode 100644 web/src/views/job_mgmt/multiple_job.vue create mode 100644 web/src/views/job_mgmt/new_job.vue create mode 100644 web/src/views/job_mgmt/scan_file.vue create mode 100644 web/src/views/job_mgmt/single_job.vue create mode 100644 web/src/views/job_monitor/history/job_flow_detail.vue create mode 100644 web/src/views/job_monitor/history/job_flow_detail/nodeInfo.vue create mode 100644 web/src/views/job_monitor/history/job_flow_detail/statusList.js create mode 100644 web/src/views/job_monitor/history/job_flow_detail/statusList.vue create mode 100644 web/src/views/job_monitor/history/job_flow_view_history.vue create mode 100644 web/src/views/job_monitor/history/job_history.vue create mode 100644 web/src/views/job_monitor/history/job_view_detail.vue create mode 100644 web/src/views/job_monitor/history/job_view_history.vue create mode 100644 web/src/views/job_monitor/monitor/job_detail.vue create mode 100644 web/src/views/job_monitor/monitor/job_flow_view.vue create mode 100644 web/src/views/job_monitor/monitor/job_flow_view_detail/nodeInfo.vue create mode 100644 web/src/views/job_monitor/monitor/job_flow_view_detail/statusList.js create mode 100644 web/src/views/job_monitor/monitor/job_flow_view_detail/statusList.vue create mode 100644 web/src/views/job_monitor/monitor/job_monitor.vue create mode 100644 web/src/views/job_monitor/monitor/job_view.vue create mode 100644 web/src/views/job_monitor/monitor/view_detail.vue create mode 100644 web/src/views/job_monitor_large_screen/large_screen.vue create mode 100644 web/src/views/job_monitor_large_screen/statusList.js create mode 100644 web/src/views/job_monitor_large_screen/statusList.vue create mode 100644 web/src/views/job_monitor_large_screen/topMenu.vue create mode 100644 web/src/views/job_monitor_large_screen/tree.vue create mode 100644 web/src/views/report/job_flow_view_report.vue create mode 100644 web/src/views/report/job_view_report.vue create mode 100644 web/src/views/report/report.vue create mode 100644 web/src/views/system/log.vue create mode 100644 web/src/views/system/log_mange.vue create mode 100644 web/src/views/system/sys_setup.vue create mode 100644 web/src/views/system/system_class_manage.vue create mode 100644 web/src/views/system/system_class_manage/systemDialog.vue create mode 100644 web/src/views/system/user_and_permissions.vue create mode 100644 web/src/views/system/user_and_permissions/addUserDialog.vue create mode 100644 web/src/views/system/user_and_permissions/userInfo.vue create mode 100644 web/src/vuex/actions.js create mode 100644 web/src/vuex/getters.js create mode 100644 web/src/vuex/index.js create mode 100644 web/src/vuex/module/common.js create mode 100644 web/src/vuex/module/history.js create mode 100644 web/src/vuex/module/monitor.js create mode 100644 web/src/vuex/module/permission.js create mode 100644 web/static/css/.gitkeep create mode 100644 web/static/img/.gitkeep create mode 100644 web/static/img/flow_1x.png create mode 100644 web/static/img/full_screen_16.png create mode 100644 web/static/img/job.png create mode 100644 web/static/img/jobFlow.png create mode 100644 web/static/img/jobFlow_16.png create mode 100644 web/static/img/jobFlow_16_dark.png create mode 100644 web/static/img/jobFlow_22.png create mode 100644 web/static/img/jobFlow_22_dark.png create mode 100644 web/static/img/jobFlow_28.png create mode 100644 web/static/img/jobFlow_28_dark.png create mode 100644 web/static/img/jobFlow_32.png create mode 100644 web/static/img/jobFlow_32_dark.png create mode 100644 web/static/img/jobFlow_dark.png create mode 100644 web/static/img/job_2x.png create mode 100644 web/static/img/red_cross.png create mode 100644 web/static/img/system.png create mode 100644 web/static/img/system_16.png create mode 100644 web/static/img/system_16_dark.png create mode 100644 web/static/img/system_28.png create mode 100644 web/static/img/system_28_dark.png create mode 100644 web/static/img/system_blue.svg create mode 100644 web/static/img/system_design.png create mode 100644 web/static/img/system_new.png create mode 100644 web/static/js/.gitkeep diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..e0e2910 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 数据源本地存储已忽略文件 +/../../../../../:\charles\coding\bamboo_engine_playground\.idea/dataSources/ +/dataSources.local.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ diff --git a/.idea/bamboo_engine_playground.iml b/.idea/bamboo_engine_playground.iml new file mode 100644 index 0000000..057e3ba --- /dev/null +++ b/.idea/bamboo_engine_playground.iml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..30c95db --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,15 @@ + + + + + mysql.8 + true + com.mysql.cj.jdbc.Driver + jdbc:mysql://localhost:3306/bomboo + $ProjectFileDir$ + + + + + + \ No newline at end of file diff --git a/.idea/dataSources/19ee76cb-3424-4654-855f-f68454aff13a.xml b/.idea/dataSources/19ee76cb-3424-4654-855f-f68454aff13a.xml new file mode 100644 index 0000000..6afb4ef --- /dev/null +++ b/.idea/dataSources/19ee76cb-3424-4654-855f-f68454aff13a.xml @@ -0,0 +1,3969 @@ + + + + + 8.0.19 + InnoDB + InnoDB + lower/lower + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + 1 + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8mb4_0900_ai_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8mb4_0900_ai_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8mb4_0900_ai_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8mb4_0900_ai_ci + + + utf8_general_ci + + + utf8mb4_0900_ai_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8_general_ci + + + utf8mb4_0900_ai_ci + + + armscii8 + + + armscii8 + 1 + + + ascii + + + ascii + 1 + + + big5 + + + big5 + 1 + + + binary + 1 + + + cp1250 + + + cp1250 + + + cp1250 + + + cp1250 + 1 + + + cp1250 + + + cp1251 + + + cp1251 + + + cp1251 + 1 + + + cp1251 + + + cp1251 + + + cp1256 + + + cp1256 + 1 + + + cp1257 + + + cp1257 + 1 + + + cp1257 + + + cp850 + + + cp850 + 1 + + + cp852 + + + cp852 + 1 + + + cp866 + + + cp866 + 1 + + + cp932 + + + cp932 + 1 + + + dec8 + + + dec8 + 1 + + + eucjpms + + + eucjpms + 1 + + + euckr + + + euckr + 1 + + + gb18030 + + + gb18030 + 1 + + + gb18030 + + + gb2312 + + + gb2312 + 1 + + + gbk + + + gbk + 1 + + + geostd8 + + + geostd8 + 1 + + + greek + + + greek + 1 + + + hebrew + + + hebrew + 1 + + + hp8 + + + hp8 + 1 + + + keybcs2 + + + keybcs2 + 1 + + + koi8r + + + koi8r + 1 + + + koi8u + + + koi8u + 1 + + + latin1 + + + latin1 + + + latin1 + + + latin1 + + + latin1 + + + latin1 + + + latin1 + + + latin1 + 1 + + + latin2 + + + latin2 + + + latin2 + + + latin2 + 1 + + + latin2 + + + latin5 + + + latin5 + 1 + + + latin7 + + + latin7 + + + latin7 + 1 + + + latin7 + + + macce + + + macce + 1 + + + macroman + + + macroman + 1 + + + sjis + + + sjis + 1 + + + swe7 + + + swe7 + 1 + + + tis620 + + + tis620 + 1 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + 1 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ucs2 + + + ujis + + + ujis + 1 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + 1 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16 + + + utf16le + + + utf16le + 1 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + 1 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf32 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + 1 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8 + + + utf8mb4 + 1 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + utf8mb4 + + + localhost + SELECT + + + + localhost + SHUTDOWN,SUPER +BACKUP_ADMIN,CLONE_ADMIN,CONNECTION_ADMIN,PERSIST_RO_VARIABLES_ADMIN,SESSION_VARIABLES_ADMIN,SYSTEM_USER,SYSTEM_VARIABLES_ADMIN +SELECT|performance_schema +SELECT|mysql.user + + + + localhost + TRIGGER|sys +SELECT|sys.sys_config + + + + localhost + SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,RELOAD,SHUTDOWN,PROCESS,FILE,REFERENCES,INDEX,ALTER,SHOW DATABASES,SUPER,CREATE TEMPORARY TABLES,LOCK TABLES,EXECUTE,REPLICATION SLAVE,REPLICATION CLIENT,CREATE VIEW,SHOW VIEW,CREATE ROUTINE,ALTER ROUTINE,CREATE USER,EVENT,TRIGGER,CREATE TABLESPACE,CREATE ROLE,DROP ROLE! +APPLICATION_PASSWORD_ADMIN,AUDIT_ADMIN,BACKUP_ADMIN,BINLOG_ADMIN,BINLOG_ENCRYPTION_ADMIN,CLONE_ADMIN,CONNECTION_ADMIN,ENCRYPTION_KEY_ADMIN,GROUP_REPLICATION_ADMIN,INNODB_REDO_LOG_ARCHIVE,PERSIST_RO_VARIABLES_ADMIN,REPLICATION_APPLIER,REPLICATION_SLAVE_ADMIN,RESOURCE_GROUP_ADMIN,RESOURCE_GROUP_USER,ROLE_ADMIN,SERVICE_CONNECTION_ADMIN,SESSION_VARIABLES_ADMIN,SET_USER_ID,SYSTEM_USER,SYSTEM_VARIABLES_ADMIN,TABLE_ENCRYPTION_ADMIN,XA_RECOVER_ADMIN! + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + 1 + int|0s + 1 + null + + + 2 + varchar(150)|0s + 1 + + + name + 1 + btree + + + 1 + id + 1 + + + name + name + + + 1 + bigint|0s + 1 + null + + + 2 + int|0s + 1 + + + 3 + int|0s + 1 + + + group_id +permission_id + 1 + btree + + + permission_id + btree + + + 1 + id + 1 + + + group_id +permission_id + auth_group_permissions_group_id_permission_id_0cd325b0_uniq + + + group_id + auth_group + id + + + permission_id + auth_permission + id + + + 1 + int|0s + 1 + null + + + 2 + varchar(255)|0s + 1 + + + 3 + int|0s + 1 + + + 4 + varchar(100)|0s + 1 + + + content_type_id +codename + 1 + btree + + + 1 + id + 1 + + + content_type_id +codename + auth_permission_content_type_id_codename_01ab375a_uniq + + + content_type_id + django_content_type + id + + + 1 + int|0s + 1 + null + + + 2 + varchar(128)|0s + 1 + + + 3 + datetime(6)|0s + + + 4 + tinyint(1)|0s + 1 + + + 5 + varchar(150)|0s + 1 + + + 6 + varchar(150)|0s + 1 + + + 7 + varchar(150)|0s + 1 + + + 8 + varchar(254)|0s + 1 + + + 9 + tinyint(1)|0s + 1 + + + 10 + tinyint(1)|0s + 1 + + + 11 + datetime(6)|0s + 1 + + + username + 1 + btree + + + 1 + id + 1 + + + username + username + + + 1 + bigint|0s + 1 + null + + + 2 + int|0s + 1 + + + 3 + int|0s + 1 + + + user_id +group_id + 1 + btree + + + group_id + btree + + + 1 + id + 1 + + + user_id +group_id + auth_user_groups_user_id_group_id_94350c0c_uniq + + + user_id + auth_user + id + + + group_id + auth_group + id + + + 1 + bigint|0s + 1 + null + + + 2 + int|0s + 1 + + + 3 + int|0s + 1 + + + user_id +permission_id + 1 + btree + + + permission_id + btree + + + 1 + id + 1 + + + user_id +permission_id + auth_user_user_permissions_user_id_permission_id_14a6b632_uniq + + + user_id + auth_user + id + + + permission_id + auth_permission + id + + + 1 + int|0s + 1 + null + + + 2 + varchar(255)|0s + 1 + + + 3 + varchar(255)|0s + 1 + + + 4 + tinyint(1)|0s + 1 + + + 5 + varchar(64)|0s + 1 + + + code +version + 1 + btree + + + code + btree + + + version + btree + + + 1 + id + 1 + + + code +version + component_framework_componentmodel_code_version_1b8e366c_uniq + + + 1 + int|0s + 1 + null + + + 2 + datetime(6)|0s + 1 + + + 3 + longtext|0s + + + 4 + varchar(200)|0s + 1 + + + 5 + smallint unsigned|0s + 1 + + + 6 + longtext|0s + 1 + + + 7 + int|0s + + + 8 + int|0s + 1 + + + content_type_id + btree + + + user_id + btree + + + 1 + id + 1 + + + content_type_id + django_content_type + id + + + user_id + auth_user + id + + + 1 + int|0s + 1 + null + + + 2 + datetime(6)|0s + 1 + + + 1 + id + 1 + + + 1 + int|0s + 1 + null + + + 2 + varchar(240)|0s + 1 + + + 3 + varchar(96)|0s + 1 + + + 4 + varchar(64)|0s + 1 + + + 5 + varchar(124)|0s + 1 + + + 6 + varchar(64)|0s + 1 + + + 7 + varchar(63)|0s + 1 + + + 1 + id + 1 + + + 1 + int|0s + 1 + null + + + 2 + int|0s + 1 + + + 3 + varchar(24)|0s + 1 + + + 1 + id + 1 + + + 1 + int|0s + 1 + null + + + 2 + varchar(200)|0s + 1 + + + 3 + varchar(200)|0s + 1 + + + 4 + longtext|0s + 1 + + + 5 + longtext|0s + 1 + + + 6 + varchar(200)|0s + + + 7 + varchar(200)|0s + + + 8 + varchar(200)|0s + + + 9 + datetime(6)|0s + + + 10 + tinyint(1)|0s + 1 + + + 11 + datetime(6)|0s + + + 12 + int unsigned|0s + 1 + + + 13 + datetime(6)|0s + 1 + + + 14 + longtext|0s + 1 + + + 15 + int|0s + + + 16 + int|0s + + + 17 + int|0s + + + 18 + tinyint(1)|0s + 1 + + + 19 + datetime(6)|0s + + + 20 + int unsigned|0s + + + 21 + longtext|0s + 1 + + + 22 + int|0s + + + 23 + int unsigned|0s + + + name + 1 + btree + + + crontab_id + btree + + + interval_id + btree + + + solar_id + btree + + + clocked_id + btree + + + 1 + id + 1 + + + name + name + + + crontab_id + django_celery_beat_crontabschedule + id + + + interval_id + django_celery_beat_intervalschedule + id + + + solar_id + django_celery_beat_solarschedule + id + + + clocked_id + django_celery_beat_clockedschedule + id + + + 1 + smallint|0s + 1 + + + 2 + datetime(6)|0s + 1 + + + 1 + ident + 1 + + + 1 + int|0s + 1 + null + + + 2 + varchar(24)|0s + 1 + + + 3 + decimal(9,6 digit)|0s + 1 + + + 4 + decimal(9,6 digit)|0s + 1 + + + event +latitude +longitude + 1 + btree + + + 1 + id + 1 + + + event +latitude +longitude + django_celery_beat_solar_event_latitude_longitude_ba64999a_uniq + + + 1 + int|0s + 1 + null + + + 2 + varchar(255)|0s + 1 + + + 3 + varchar(50)|0s + 1 + + + 4 + varchar(128)|0s + 1 + + + 5 + varchar(64)|0s + 1 + + + 6 + longtext|0s + + + 7 + datetime(6)|0s + 1 + + + 8 + longtext|0s + + + 9 + longtext|0s + + + 10 + longtext|0s + + + 11 + longtext|0s + + + 12 + varchar(255)|0s + + + 13 + varchar(100)|0s + + + 14 + datetime(6)|0s + 1 + + + task_id + 1 + btree + + + status + btree + + + date_done + btree + + + task_name + btree + + + worker + btree + + + date_created + btree + + + 1 + id + 1 + + + task_id + task_id + + + 1 + int|0s + 1 + null + + + 2 + varchar(100)|0s + 1 + + + 3 + varchar(100)|0s + 1 + + + app_label +model + 1 + btree + + + 1 + id + 1 + + + app_label +model + django_content_type_app_label_model_76bd3d3b_uniq + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(255)|0s + 1 + + + 3 + varchar(255)|0s + 1 + + + 4 + datetime(6)|0s + 1 + + + 1 + id + 1 + + + 1 + varchar(40)|0s + 1 + + + 2 + longtext|0s + 1 + + + 3 + datetime(6)|0s + 1 + + + expire_date + btree + + + 1 + session_key + 1 + + + 1 + varchar(32)|0s + 1 + + + 2 + longblob|0s + 1 + + + 3 + longblob|0s + 1 + + + 4 + longblob|0s + 1 + + + 1 + id + 1 + + + 1 + varchar(255)|0s + 1 + + + 2 + longblob|0s + 1 + + + 1 + key + 1 + + + 1 + int|0s + 1 + null + + + 2 + varchar(32)|0s + 1 + + + 3 + longtext|0s + 1 + + + 4 + tinyint(1)|0s + 1 + + + name + 1 + btree + + + 1 + id + 1 + + + name + engine_functionswitch_name_4eaabfd5_uniq + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(32)|0s + 1 + + + 3 + datetime(6)|0s + 1 + + + 4 + datetime(6)|0s + 1 + + + 5 + bigint|0s + + + 6 + int|0s + 1 + + + 7 + tinyint(1)|0s + 1 + + + identifier + btree + + + data_id + btree + + + 1 + id + 1 + + + data_id + engine_historydata + id + + + 1 + bigint|0s + 1 + null + + + 2 + longblob|0s + 1 + + + 3 + longblob|0s + 1 + + + 4 + longblob|0s + 1 + + + 1 + id + 1 + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(64)|0s + 1 + + + 3 + longblob|0s + 1 + + + 1 + id + 1 + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(32)|0s + 1 + + + 3 + varchar(40)|0s + 1 + + + node_id + 1 + btree + + + 1 + id + 1 + + + node_id + node_id + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(32)|0s + 1 + + + 3 + varchar(32)|0s + 1 + + + 4 + int|0s + 1 + + + ancestor_id + btree + + + descendant_id + btree + + + distance + btree + + + 1 + id + 1 + + + 1 + varchar(32)|0s + 1 + + + 2 + varchar(32)|0s + + + 3 + int|0s + 1 + + + 4 + varchar(512)|0s + 1 + + + process_id + btree + + + 1 + id + 1 + + + process_id + engine_pipelineprocess + id + + + 1 + varchar(32)|0s + 1 + + + 2 + varchar(32)|0s + 1 + + + 3 + varchar(32)|0s + 1 + + + 4 + varchar(32)|0s + 1 + + + 5 + varchar(32)|0s + 1 + + + 6 + int|0s + 1 + + + 7 + int|0s + 1 + + + 8 + tinyint(1)|0s + 1 + + + 9 + tinyint(1)|0s + 1 + + + 10 + bigint|0s + + + 11 + tinyint(1)|0s + 1 + + + root_pipeline_id + btree + + + current_node_id + btree + + + parent_id + btree + + + is_alive + btree + + + is_sleep + btree + + + snapshot_id + btree + + + is_frozen + btree + + + 1 + id + 1 + + + snapshot_id + engine_processsnapshot + id + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(32)|0s + 1 + + + 3 + varchar(40)|0s + 1 + + + process_id + 1 + btree + + + 1 + id + 1 + + + process_id + process_id + + + 1 + bigint|0s + 1 + null + + + 2 + longblob|0s + 1 + + + 1 + id + 1 + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(64)|0s + 1 + + + 3 + varchar(40)|0s + 1 + + + schedule_id + 1 + btree + + + 1 + id + 1 + + + schedule_id + schedule_id + + + 1 + varchar(64)|0s + 1 + + + 2 + varchar(32)|0s + 1 + + + 3 + varchar(32)|0s + 1 + + + 4 + int|0s + 1 + + + 5 + tinyint(1)|0s + 1 + + + 6 + longblob|0s + 1 + + + 7 + longblob|0s + 1 + + + 8 + tinyint(1)|0s + 1 + + + 9 + varchar(32)|0s + 1 + + + 10 + tinyint(1)|0s + 1 + + + 11 + tinyint(1)|0s + 1 + + + activity_id + btree + + + version + btree + + + is_scheduling + btree + + + 1 + id + 1 + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(1024)|0s + 1 + + + 3 + longtext|0s + 1 + + + 4 + int|0s + 1 + + + 5 + longtext|0s + 1 + + + 6 + longtext|0s + 1 + + + 7 + datetime(6)|0s + 1 + + + 1 + id + 1 + + + 1 + varchar(32)|0s + 1 + + + 2 + varchar(10)|0s + 1 + + + 3 + varchar(64)|0s + 1 + + + 4 + int|0s + 1 + + + 5 + int|0s + 1 + + + 6 + tinyint(1)|0s + 1 + + + 7 + datetime(6)|0s + 1 + + + 8 + datetime(6)|0s + + + 9 + datetime(6)|0s + + + 10 + varchar(32)|0s + 1 + + + 11 + tinyint(1)|0s + 1 + + + 12 + datetime(6)|0s + + + created_time + btree + + + 1 + id + 1 + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(32)|0s + 1 + + + 3 + varchar(32)|0s + 1 + + + subprocess_id + btree + + + 1 + id + 1 + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(33)|0s + 1 + + + 3 + varchar(33)|0s + 1 + + + 4 + longtext|0s + 1 + + + 1 + id + 1 + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(33)|0s + 1 + + + 3 + longtext|0s + 1 + + + pipeline_id + 1 + btree + + + 1 + id + 1 + + + pipeline_id + pipeline_id + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(33)|0s + 1 + + + 3 + varchar(128)|0s + 1 + + + 4 + int|0s + 1 + + + 5 + varchar(32)|0s + 1 + + + 6 + varchar(128)|0s + 1 + + + 7 + longtext|0s + 1 + + + 8 + longtext|0s + 1 + + + pipeline_id +key + 1 + btree + + + 1 + id + 1 + + + pipeline_id +key + eri_contextvalue_pipeline_id_key_df86ad76_uniq + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(33)|0s + 1 + + + 3 + longtext|0s + 1 + + + 4 + longtext|0s + 1 + + + node_id + 1 + btree + + + 1 + id + 1 + + + node_id + node_id + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(33)|0s + 1 + + + 3 + varchar(32)|0s + 1 + + + 4 + varchar(32)|0s + 1 + + + 5 + longtext|0s + 1 + + + 6 + longtext|0s + 1 + + + node_id + 1 + btree + + + 1 + id + 1 + + + node_id + node_id + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(33)|0s + 1 + + + 3 + int|0s + 1 + + + 4 + int|0s + 1 + + + 5 + tinyint(1)|0s + 1 + + + 6 + varchar(33)|0s + 1 + + + 7 + datetime(6)|0s + 1 + + + 8 + datetime(6)|0s + 1 + + + 9 + varchar(32)|0s + 1 + + + 10 + varchar(32)|0s + 1 + + + 11 + longtext|0s + 1 + + + 12 + longtext|0s + 1 + + + node_id +loop + btree + + + 1 + id + 1 + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(33)|0s + 1 + + + 3 + int|0s + 1 + + + 4 + varchar(128)|0s + 1 + + + 5 + varchar(32)|0s + 1 + + + 6 + longtext|0s + + + 7 + datetime(6)|0s + 1 + + + 8 + varchar(33)|0s + 1 + + + node_id +loop + btree + + + logged_at + btree + + + 1 + id + 1 + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(33)|0s + 1 + + + 3 + longtext|0s + 1 + + + node_id + btree + + + 1 + id + 1 + + + 1 + bigint|0s + 1 + null + + + 2 + bigint|0s + 1 + + + 3 + int|0s + 1 + + + 4 + int|0s + 1 + + + 5 + tinyint(1)|0s + 1 + + + 6 + tinyint(1)|0s + 1 + + + 7 + tinyint(1)|0s + 1 + + + 8 + tinyint(1)|0s + 1 + + + 9 + datetime(6)|0s + 1 + + + 10 + varchar(33)|0s + 1 + + + 11 + varchar(33)|0s + 1 + + + 12 + varchar(33)|0s + 1 + + + 13 + varchar(33)|0s + 1 + + + 14 + int|0s + 1 + + + 15 + varchar(128)|0s + 1 + + + 16 + longtext|0s + 1 + + + parent_id + btree + + + last_heartbeat + btree + + + current_node_id + btree + + + root_pipeline_id + btree + + + suspended_by + btree + + + 1 + id + 1 + + + 1 + bigint|0s + 1 + null + + + 2 + int|0s + 1 + + + 3 + bigint|0s + 1 + + + 4 + varchar(33)|0s + 1 + + + 5 + tinyint(1)|0s + 1 + + + 6 + tinyint(1)|0s + 1 + + + 7 + tinyint(1)|0s + 1 + + + 8 + varchar(33)|0s + 1 + + + 9 + int|0s + 1 + + + node_id +version + 1 + btree + + + 1 + id + 1 + + + node_id +version + eri_schedule_node_id_version_41a8c75a_uniq + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(33)|0s + 1 + + + 3 + varchar(33)|0s + 1 + + + 4 + varchar(33)|0s + 1 + + + 5 + varchar(64)|0s + 1 + + + 6 + varchar(33)|0s + 1 + + + 7 + int|0s + 1 + + + 8 + int|0s + 1 + + + 9 + tinyint(1)|0s + 1 + + + 10 + tinyint(1)|0s + 1 + + + 11 + datetime(6)|0s + 1 + + + 12 + datetime(6)|0s + + + 13 + datetime(6)|0s + + + 14 + int|0s + 1 + + + node_id + 1 + btree + + + root_id + btree + + + parent_id + btree + + + 1 + id + 1 + + + node_id + node_id + + + 1 + int|0s + 1 + null + + + 2 + varchar(255)|0s + 1 + + + 1 + id + 1 + + + 1 + int|0s + 1 + null + + + 2 + varchar(255)|0s + 1 + + + 3 + varchar(255)|0s + 1 + + + 4 + varchar(255)|0s + + + 5 + int|0s + 1 + + + 6 + int|0s + 1 + + + 7 + varchar(32)|0s + 1 + + + 8 + int|0s + 1 + + + 9 + varchar(255)|0s + 1 + + + 10 + tinyint(1)|0s + 1 + + + 11 + tinyint(1)|0s + 1 + + + 12 + json|0s + 1 + + + 13 + json|0s + 1 + + + 14 + int|0s + + + process_id + btree + + + 1 + id + 1 + + + 1 + int|0s + 1 + null + + + 2 + varchar(255)|0s + 1 + + + 3 + varchar(255)|0s + + + 4 + varchar(32)|0s + 1 + + + 5 + int unsigned|0s + 1 + + + 6 + json|0s + 1 + + + 7 + json|0s + 1 + + + 8 + json|0s + 1 + + + 9 + varchar(64)|0s + + + 10 + datetime(6)|0s + 1 + + + 11 + datetime(6)|0s + 1 + + + 12 + varchar(64)|0s + + + 1 + id + 1 + + + 1 + int|0s + 1 + null + + + 2 + int|0s + 1 + + + 3 + int|0s + 1 + + + process_id +category_id + 1 + btree + + + category_id + btree + + + 1 + id + 1 + + + process_id +category_id + flow_process_category_process_id_category_id_e1ab1b26_uniq + + + process_id + flow_process + id + + + category_id + flow_category + id + + + 1 + bigint|0s + 1 + null + + + 2 + varchar(128)|0s + 1 + + + 3 + varchar(32)|0s + 1 + + + 4 + longtext|0s + + + 5 + longtext|0s + + + 6 + datetime(6)|0s + 1 + + + 7 + varchar(32)|0s + 1 + + + 8 + int|0s + 1 + + + logger_name + btree + + + level_name + btree + + + logged_at + btree + + + node_id + btree + + + 1 + id + 1 + + + 1 + int|0s + 1 + null + + + 2 + varchar(32)|0s + 1 + + + 3 + varchar(128)|0s + 1 + + + 4 + varchar(32)|0s + 1 + + + 5 + datetime(6)|0s + 1 + + + 6 + varchar(32)|0s + 1 + + + 7 + datetime(6)|0s + + + 8 + datetime(6)|0s + + + 9 + longtext|0s + 1 + + + 10 + tinyint(1)|0s + 1 + + + 11 + tinyint(1)|0s + 1 + + + 12 + tinyint(1)|0s + 1 + + + 13 + int|0s + + + 14 + int|0s + + + 15 + int|0s + + + 16 + int|0s + + + 17 + tinyint(1)|0s + 1 + + + 18 + tinyint(1)|0s + 1 + + + instance_id + 1 + btree + + + create_time + btree + + + execution_snapshot_id + btree + + + snapshot_id + btree + + + template_id + btree + + + tree_info_id + btree + + + 1 + id + 1 + + + instance_id + instance_id + + + execution_snapshot_id + pipeline_snapshot + id + + + snapshot_id + pipeline_snapshot + id + + + template_id + pipeline_pipelinetemplate + id + + + tree_info_id + pipeline_treeinfo + id + + + 1 + int|0s + 1 + null + + + 2 + varchar(32)|0s + 1 + + + 3 + varchar(128)|0s + 1 + + + 4 + datetime(6)|0s + 1 + + + 5 + varchar(32)|0s + 1 + + + 6 + longtext|0s + + + 7 + varchar(32)|0s + + + 8 + datetime(6)|0s + 1 + + + 9 + tinyint(1)|0s + 1 + + + 10 + int|0s + 1 + + + 11 + tinyint(1)|0s + 1 + + + template_id + 1 + btree + + + name + btree + + + create_time + btree + + + edit_time + btree + + + snapshot_id + btree + + + 1 + id + 1 + + + template_id + template_id + + + snapshot_id + pipeline_snapshot + id + + + 1 + int|0s + 1 + null + + + 2 + longtext|0s + 1 + + + 3 + varchar(64)|0s + 1 + + + 4 + longblob|0s + 1 + + + 1 + id + 1 + + + 1 + int|0s + 1 + null + + + 2 + varchar(32)|0s + 1 + + + 3 + datetime(6)|0s + 1 + + + 4 + longblob|0s + + + md5sum + btree + + + 1 + id + 1 + + + 1 + int|0s + 1 + null + + + 2 + varchar(32)|0s + 1 + + + 3 + varchar(32)|0s + 1 + + + template_id + btree + + + 1 + id + 1 + + + 1 + int|0s + 1 + null + + + 2 + varchar(32)|0s + 1 + + + 3 + varchar(32)|0s + 1 + + + 4 + varchar(32)|0s + 1 + + + 5 + varchar(32)|0s + 1 + + + 6 + tinyint(1)|0s + 1 + + + ancestor_template_id + btree + + + descendant_template_id + btree + + + 1 + id + 1 + + + 1 + int|0s + 1 + null + + + 2 + varchar(97)|0s + 1 + + + 3 + varchar(64)|0s + 1 + + + 4 + datetime(6)|0s + 1 + + + 5 + longblob|0s + 1 + + + 6 + int|0s + 1 + + + unique_id + 1 + btree + + + template_id + btree + + + 1 + id + 1 + + + unique_id + unique_id + + + template_id + pipeline_pipelinetemplate + id + + + 1 + int|0s + 1 + null + + + 2 + int|0s + 1 + + + 3 + int|0s + 1 + + + templatescheme_id +templaterelationship_id + 1 + btree + + + templaterelationship_id + btree + + + 1 + id + 1 + + + templatescheme_id +templaterelationship_id + pipeline_templatescheme__templatescheme_id_templa_dff0f4f6_uniq + + + templatescheme_id + pipeline_templatescheme + id + + + templaterelationship_id + pipeline_templaterelationship + id + + + 1 + int|0s + 1 + null + + + 2 + varchar(32)|0s + 1 + + + 3 + datetime(6)|0s + 1 + + + 4 + int|0s + 1 + + + 5 + int|0s + 1 + + + md5 + btree + + + snapshot_id + btree + + + template_id + btree + + + 1 + id + 1 + + + snapshot_id + pipeline_snapshot + id + + + template_id + pipeline_pipelinetemplate + id + + + 1 + int|0s + 1 + null + + + 2 + longblob|0s + + + 1 + id + 1 + + + \ No newline at end of file diff --git a/.idea/dataSources/19ee76cb-3424-4654-855f-f68454aff13a/storage_v2/_src_/schema/information_schema.FNRwLQ.meta b/.idea/dataSources/19ee76cb-3424-4654-855f-f68454aff13a/storage_v2/_src_/schema/information_schema.FNRwLQ.meta new file mode 100644 index 0000000..1ff3db2 --- /dev/null +++ b/.idea/dataSources/19ee76cb-3424-4654-855f-f68454aff13a/storage_v2/_src_/schema/information_schema.FNRwLQ.meta @@ -0,0 +1,2 @@ +#n:information_schema +! [null, 0, null, null, -2147483648, -2147483648] diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..fcd40a3 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,57 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..b7d2a8c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..f295c06 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/__pycache__/manage.cpython-36.pyc b/__pycache__/manage.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5f11fc5a408ab391d95fc4c9e721e0e0102ba7f3 GIT binary patch literal 813 zcmZuv%We}f6tz8*M+2?0s??o#RS--UAR!?{shX${L0ZwEwh@x$j-9Dfk6qcG&_pc@ z!dD=EfCWD^TUIRDvf@r!q%QF2o|*A|oqO!3%ge2=OTYOKg3wQNZ^1u$4dxR7frdz6 zK{OuX#hVO?h(!Da4I>$g+68fsWHd(@337xw_1W|8n48S5dz#uj=SDoy%1BxSrB#^H zk#&@dTp8tq<3UX%4cuS&4F-Gtog?=4p!@z!Z`KxLHq!QE;$;ZRWZq$5*}>(Sypm}VBpW%K zvpW%3CBp36wk@w&8L(z-xzwMyuglXPke>I?W#0mM_r2d=dg6eOg4!jz$Cm1d%xHMul_PPkK5+$QZRu_y_GXEM-WDNjLe9wg-y5<38HFLg=4oy%!tlId@w6jnoRzZR3pRXVx-lGLVQ}YCg@JEsXeZ+a|f3mT}IN zX+XZOt^^`0nBX=%1jo@Tb}O(~HW{m;80*x^24ljejJX&*ZmEKQF^1<792J>+u)L`7 XGPk18@>O;Bd literal 0 HcmV?d00001 diff --git a/applications/__init__.py b/applications/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/applications/__pycache__/__init__.cpython-36.pyc b/applications/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e46db66935f9aa4849b9fc2566d1872ee7aeee6a GIT binary patch literal 150 zcmXr!<>lfP`IyK61dl-k3@`#24nSPY0whuxf*CX!{Z=v*frJsnFK1V)nBd;D_>{;11dl-k3@`#24nSPY0whuxf*CX!{Z=v*frJsnFArC%nBL_~zHE^Z}I)1<~ok{6N|=}&U=_jGk~a(6O1c<|jl z-f*|fvKhU`L~?*Uea0{3WSlTzl-=h^H5V6VB^DfQ z=T+ms1vl_%jGw*Baz*)>dEExeQ79{E!%Tx%w^l0K)=slQdhD&B%sH(%>lE5RPa3cE Tw^O)boURRuUbh<(n?nRXO;$Bf literal 0 HcmV?d00001 diff --git a/applications/flow/__pycache__/constants.cpython-36.pyc b/applications/flow/__pycache__/constants.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..89e176511a4f71aaebba42aaf2816db5456b4df2 GIT binary patch literal 548 zcmYk2yGz4R6o+pg+E%TPs;v*~;?%{(O+=K^VnOWCx=0|zCbog}-f)v5-Bj>_U3`I1 zEaFrWZ&9m&H4+Q zV_rVAd;ZeLqtCsv)i`S%JgwK96sA#V&K$Z?sAmoZw3i{`qNCtrfN=)42&X{3w!?JV zXL~<5{1DsY2OqS32z=P~5%2&*q?ZQ4Lx2guBwz|K%@A=Kq4-K-jZenosaTrdSWl$+ z=xQ<%jTt^nM2Xjns#HTX3>ARyL~Mb}%&kz?v>#U7J&jhIcVf#DXF%!P#i=?Z|-~Za2`re*hYmoVox2 literal 0 HcmV?d00001 diff --git a/applications/flow/__pycache__/models.cpython-36.pyc b/applications/flow/__pycache__/models.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8ffb0ff58e5bcafe96641da7c4fa1912bcb64738 GIT binary patch literal 2476 zcmZ`*&2Jk;6yNo(?X|sjT<5c22q7+(P%hk1g;LVG1X{OJlglX5YU7zWo33}=+1(c3 zpdoE3SZSeAtAdas^#dfJsi>+pRhs`}u4J9~%#91YnQ?V_8M{L+ShJz)!$ma0v)ju<9xe1t}`$6Rz4wpoHKxS8M1<7rgE!8!40$e9}!f z3}mRvDFvr+`b!0;Nn$axq@gTm44eT?rl-k)CW~{R$@MfQHqR^Nd>8gs$|^Ik9g@&# z5a3e{9}_nK&iu&tU1EC`hqxHz%qQp1R$mLFmE%*Vt+SQN`IFPuOm%A7n*8|e)a1z; zU-I=Y1Q0@#^6MOU}8rcY*0%tbZP z(n2*@hh-)gY%0zHlVQfs3OxXNLH??o{9v{Qc9#URH6J@(eRj@n%=x|ryE-1Rny%fd zQ$O6^k$hi_EfEcQf_rIIx;PC%jxWXmMD~8xislSchT7QQU9FRW0&dSQ}*7~&2?5;1x8xMKLfBd@pHu#lQF;N&hUp?Ag`=;~DT4!~gs=~<9 zn9SRe8w!V=&0F#E@7r5zoi83oC2)wZE_auHidXJ-udPTm(oP&d74cZ&>)*#OH+DZ? z?oRNf5;DNO*rd60=UMm8QyJ{mZ=KsOq=JLRjzZt^{L5moZDHKr*r=8dQeL+-&q;w3 zUTt)MlOhn7!z8Ftr^)Mu4VJ1!ql5hXg@|Hh8qo@k z6f%vo^hn6EV=C`2vPeW(Dto=)A|aX6-&qWgz!5AoI15eKu(`p_6C)%qZEj&^pO~Rb z*15x7eDU>{dQ5&crV>r=asNvews-&!8>&4u{?}COZ-}bgICJfDcvBuWe99!IKvwLiB_3a3!J2>)HRNvlV{%7*S!>D!+n}&tD^{DScgQ zyQ*nh(`%Z((MFc|b$;VySx56Vq6rW~bL{b({3j=-!H^&J8GFROz#F^w=DJ!KrbCgX zxriz$gmQ9J5DIBDO8MDlnAij=qz&2(oD!HBvnP#-(PLxdpXQ#u!T!VKB0iuP&F-(2 zv8!jAeE;!--)|;6vCKrdnG`(Ddz)MFV5=x1k@v{(FpCd+vKZxjGae4JG>NIq%gt@n z$>v<8cZY}HH}3H?sghzayibmlbcFXvw=-$hUB+knF-I=&@C~AbdEsKFN zs{+Ls4}@wW{zRrj@&V;L%A@LVC_1)$4W{JlM6QA;i^n|`P`V->SMhYHRV;1CX%;-R4@VUi zlsm<~vZ`XJ>`ZJ|%1V<$wRWm%2&;P|QC6L0Ki@ZX-T%_M2UYzR2R$L`J zQ3;&twAA8LAQn<3c%3kNR~(kg#g>blOWH_Gs$!5Pl8O!5xB4PMxNaf^#FPsKh)p{5 z)#@RM&8<KzMv`bG+azYwrppe7VM7b+dY9M0n3b$t z)=Q~!sHn>|5N6oMs`k?~nos^F8ftTa>kI6|UV$iuo+gNGY` zUayxo5sCaG5sGY%P{`5+A&@RxAimK;G%fm@`pdb-LVm2#QcB%vV?i53TR|H$kIfK( z2Z*uN4f5-S!Jkt~$3!b#ol`2T5Zx+txCwRE(XE%N>wYS57QG0in?=!j$CdY?O1?{k zG}oo&Ah`nPX`515&SgO-rQUr~bQcmO6{C;cmmguU4j_0=Be5@1As^tw+julc`G%gK z3->ICzr?E398%joW(ZejGIWtsi`&Sljhv!6BMGkh=_7zkDxQiL=ami={iu@?RKAC& z{4WSPmWjtYcxP<%S=}d}+}<=N_QW~3K6cQ>Rwphxnu#vya^sn)yUDG`y1!C?>^qQj z>HdHl4)wo-u?MLkdY%O-pSm%qt*N6aIxjfrxS;5^py;W*aW
    hqSS=$;r;&-D2v zO_#8C`B{MZ3PzWo`P!o|9y8thSD#U3Tv^8rgX%_J0U`96;$M{Vi_l9_((B{%7LBO( zE&@o6it-NW3^Wvmx+x4|xhvmzrHmxp?f4fu@Fq#?uA<>buQcUl;?ntpl!h!Pt;C>| zzac(BpQNg!+RZ8XJq1qc=HfnsRl~Q7rK+@-;~5VmrJs-hNq-U%sl2y zulLRrwXZ%n5Xq=I1(=yrxYg^6`~}#m{cnAgqxXnud!qaMg-M~iBsq2pjx?tp81R0a z_lhpxs;>l#61N!?G5X?ufg`7FT%ErscIlqj)rekdc&{%AjhV~3d#OvG66nuy37>U> eBpJWROXc6I+wgrt2i+B^8!lNZcUIh$J3jy~CsD2d literal 0 HcmV?d00001 diff --git a/applications/flow/__pycache__/urls.cpython-36.pyc b/applications/flow/__pycache__/urls.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f02156fe0efdd8ac1375b178ed9ecee17cbd292e GIT binary patch literal 347 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 literal 0 HcmV?d00001 diff --git a/applications/flow/admin.py b/applications/flow/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/applications/flow/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/applications/flow/apps.py b/applications/flow/apps.py new file mode 100644 index 0000000..a702df1 --- /dev/null +++ b/applications/flow/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class FlowConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'applications.flow' diff --git a/applications/flow/constants.py b/applications/flow/constants.py new file mode 100644 index 0000000..eec3cab --- /dev/null +++ b/applications/flow/constants.py @@ -0,0 +1,14 @@ +FAIL_OFFSET_UNIT_CHOICE = ( + ("seconds", "秒"), + ("hours", "时"), + ("minutes", "分"), + +) +node_type = ( + (0, "开始节点"), + (1, "结束节点"), + (2, "作业节点"), + (3, "子流程"), + (4, "条件分支"), + (5, "汇聚网关"), +) diff --git a/applications/flow/migrations/0001_initial.py b/applications/flow/migrations/0001_initial.py new file mode 100644 index 0000000..5b90741 --- /dev/null +++ b/applications/flow/migrations/0001_initial.py @@ -0,0 +1,65 @@ +# Generated by Django 2.2.6 on 2022-01-28 07:05 + +import datetime +from django.db import migrations, models +import django.db.models.deletion +import django_mysql.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Category', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='分类名称')), + ], + ), + migrations.CreateModel( + name='Process', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='作业名称')), + ('description', models.CharField(blank=True, max_length=255, null=True, verbose_name='作业描述')), + ('run_type', models.CharField(max_length=32, verbose_name='调度类型')), + ('total_run_count', models.PositiveIntegerField(default=0, verbose_name='执行次数')), + ('gateways', django_mysql.models.JSONField(default=dict, verbose_name='网关信息')), + ('constants', django_mysql.models.JSONField(default=dict, verbose_name='内部变量信息')), + ('dag', django_mysql.models.JSONField(default=dict, verbose_name='DAG')), + ('create_by', models.CharField(max_length=64, null=True, verbose_name='创建者')), + ('create_time', models.DateTimeField(default=datetime.datetime.now, verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')), + ('update_by', models.CharField(max_length=64, null=True, verbose_name='修改人')), + ('category', models.ManyToManyField(to='flow.Category')), + ], + ), + migrations.CreateModel( + name='Node', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='节点名称')), + ('uuid', models.CharField(max_length=255, verbose_name='UUID')), + ('description', models.CharField(blank=True, max_length=255, null=True, verbose_name='节点描述')), + ('show', models.BooleanField(default=True, verbose_name='是否显示')), + ('top', models.IntegerField(default=300)), + ('left', models.IntegerField(default=300)), + ('ico', models.CharField(blank=True, max_length=64, null=True, verbose_name='icon')), + ('fail_retry_count', models.IntegerField(default=0, verbose_name='失败重试次数')), + ('fail_offset', models.IntegerField(default=0, verbose_name='失败重试间隔')), + ('fail_offset_unit', models.CharField(choices=[('seconds', '秒'), ('hours', '时'), ('minutes', '分')], max_length=32, verbose_name='重试间隔单位')), + ('node_type', models.IntegerField(default=2)), + ('component_code', models.CharField(max_length=255, verbose_name='插件名称')), + ('is_skip_fail', models.BooleanField(default=False, verbose_name='忽略失败')), + ('is_timeout_alarm', models.BooleanField(default=False, verbose_name='超时告警')), + ('inputs', django_mysql.models.JSONField(default=dict, verbose_name='输入参数')), + ('outputs', django_mysql.models.JSONField(default=dict, verbose_name='输出参数')), + ('process', models.ForeignKey(db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='nodes', to='flow.Process')), + ], + ), + ] diff --git a/applications/flow/migrations/0002_auto_20220128_1556.py b/applications/flow/migrations/0002_auto_20220128_1556.py new file mode 100644 index 0000000..06d6c1c --- /dev/null +++ b/applications/flow/migrations/0002_auto_20220128_1556.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.6 on 2022-01-28 07:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('flow', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='node', + name='uuid', + field=models.CharField(max_length=255, unique=True, verbose_name='UUID'), + ), + ] diff --git a/applications/flow/migrations/__init__.py b/applications/flow/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/applications/flow/migrations/__pycache__/0001_initial.cpython-36.pyc b/applications/flow/migrations/__pycache__/0001_initial.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..015bcb65ddad5dcbfce05af0c8a8203eec92d1ba GIT binary patch literal 2580 zcmaJ@>vI!T6wf}=Y?}08TV5)P;wy@!Jba-tCU+0YAVO4?~3mbcCS~16Gq%DN#z34p<{8_qHhaNy_~#%34WzfNOma?W}`` zY8vW!7%82ktJGEMhV>Hl2%{n9QFx5odb}m|gp|r4C+ZG_rg|qhFOGX?>Ifj^(nyOdS1%Ez!588o0NZ1o?nvZ zm$}SgcpKg+YS06Nu#4woH^=Rfc3$Hs1BRrhuj9D~E5BE2*(cBY<$1W3@dJ`_utj-8 zQr<+FKGdO*6{VF}!&Rl#a0o_Vv=+x)_OM(Qwd@*r3wt+9llzx?c7z%`t&kKwze-gb zc2jj|Fr(A76@{Le_X+ZVrYgQ&w*0Djgj8uVAiixm_Ax@!?-4)e1;li%GNC$KoBv>| zM`>K@r%x{YbgO=*ws7qRzb4lErbFCfIPRyAol$*;qHP76I1tdpLEp=hAmFm|vtQ2t zdP&IA6p$eA+ZA@jmT?hav)bJzM467B=T!$PkxOn44 zeda3j>Z?y_SLlV7V=`3Ui`>vxmSByKuPt8wtnvNj#x(Oh0i<9>PAJtDF(ngLRXDmZ zd$vCL^ZeZ9#)sEwGLJJLwA?U=dQeyW2xAm!u%~Mknp@CJT+TbgD5X*CG=Bmvd z%x;nioc^MIYi99-$&ALM@q3XdtfnM9w97uP1lvL-kW~oIj@L)z^qZd+f4R~;Ra?A1Eeb?a9OxAa0SW(u!R$0IotMf4#*AD$ zq=|r_6$t*)(E7r)b2L8gMZP#<-e{t1yHQ940b7}C7IuZsdTn}swwBRoB0uig*tw!) zthH&<#YBnT!Z0`W9r=et(!81X*)23BX-4Pv55N4%`Qw|sq=7Y zH?mo6y(ly-$MVY}&o?L0)B4#@7Js-(+ibTIVdJqowfOtz^~o#sspHtcG=V~Qa8AuE zaVp}*(KvHAIF{x$m)9^8ryY<(cd?^=%f{=$nvo_w*Tg3r3Gwp##9`BcUw(f*a`9>C zZ^VCp02kbEV*AZvzlH6$vi-f(Fu9Cr(st9tCuZaj+^0?RXkj zXO^qMQHLg9KXhPNz;&?mA?+B%phhs+f@rXd#d1$Iyg#&SzvWg(Jhlpc`c=)D z9hTa6dp@y??p~alZNe&5Ax90KL7ZmPIJ9fT93I`bkG6XiBHtpui}_iWEw=o9c-OYE zJVxY@U<`Z5c8g;m(umUgU7qw^Jl`?=lhNCDBdW PSyKcCE(W?|D2Dbg)NWZG literal 0 HcmV?d00001 diff --git a/applications/flow/migrations/__pycache__/0002_auto_20220128_1556.cpython-36.pyc b/applications/flow/migrations/__pycache__/0002_auto_20220128_1556.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9ddc40fe09b807e2398c86330cf8c10bd29c0c06 GIT binary patch literal 620 zcmYjOJ8#u66n0`K%?-B_Bm4oRELCn$5kd&H;w1*UK$j?z<>a`juN*tg1LzEEe*{AZ z{*qUw&TK4joJ&<~`RF{qbH3xp`}^tj_g~^VAmk_c?=aMl@Qsg90D(Z0E+~U8EW?1j zB@hDrMu5s-OTW^R0{cL+=mv917P_=k?I0#)&FJFJg4AQisRgV`tiacI!OPH(VJtDWM%R*wV3i zR&etNJA8EP^z_}UjN)M83)j-L)47Xhqb_FY)}Q21+fi~OI=STdffoyr(C4BvB{iI6 z;SeF(5TnReF5ycK=PuK&_> z=VE8O)b{e<-hPnbfp6x;@A~z#s=+KR$EvZQOk35WtF7foMH$I^EiT)^&IT&c_gXc( ziXm@IHY72p)q77+?f49Dul(1xTbY1T$zd`mJOr0tq9CU%{?cG07Q;MLDU( zG0FKUnR)3kNr|~h`T6mwdFh#XsqqCliIwR^`K5U&F^L5QIho0cC7Jno#W86)`Q&ryk0@&Ee@O9{FKt1R6CGm#X!se0L)-6rvLx| literal 0 HcmV?d00001 diff --git a/applications/flow/models.py b/applications/flow/models.py new file mode 100644 index 0000000..bffc055 --- /dev/null +++ b/applications/flow/models.py @@ -0,0 +1,52 @@ +from datetime import datetime + +from django.db import models +from django.forms import BooleanField +from django_mysql.models import JSONField + +from applications.flow.constants import FAIL_OFFSET_UNIT_CHOICE + + +class Category(models.Model): + name = models.CharField("分类名称", max_length=255, blank=False, null=False) + + +class Process(models.Model): + name = models.CharField("作业名称", max_length=255, blank=False, null=False) + description = models.CharField("作业描述", max_length=255, blank=True, null=True) + category = models.ManyToManyField(Category) + run_type = models.CharField("调度类型", max_length=32) + total_run_count = models.PositiveIntegerField("执行次数", default=0) + gateways = JSONField("网关信息", default=dict) + constants = JSONField("内部变量信息", default=dict) + dag = JSONField("DAG", default=dict) + + create_by = models.CharField("创建者", max_length=64, null=True) + create_time = models.DateTimeField("创建时间", default=datetime.now) + update_time = models.DateTimeField("修改时间", auto_now=True) + update_by = models.CharField("修改人", max_length=64, null=True) + + +class Node(models.Model): + process = models.ForeignKey(Process, on_delete=models.SET_NULL, null=True, db_constraint=False, + related_name="nodes") + name = models.CharField("节点名称", max_length=255, blank=False, null=False) + uuid = models.CharField("UUID", max_length=255, unique=True) + description = models.CharField("节点描述", max_length=255, blank=True, null=True) + + show = models.BooleanField("是否显示", default=True) + top = models.IntegerField(default=300) + left = models.IntegerField(default=300) + ico = models.CharField("icon", max_length=64, blank=True, null=True) + + fail_retry_count = models.IntegerField("失败重试次数", default=0) + fail_offset = models.IntegerField("失败重试间隔", default=0) + fail_offset_unit = models.CharField("重试间隔单位", choices=FAIL_OFFSET_UNIT_CHOICE, max_length=32) + # 0:开始节点,1:结束节点,2:作业节点,3:其他作业流4:分支,5:汇聚 + node_type = models.IntegerField(default=2) + component_code = models.CharField("插件名称", max_length=255, blank=False, null=False) + is_skip_fail = models.BooleanField("忽略失败", default=False) + is_timeout_alarm = models.BooleanField("超时告警", default=False) + + inputs = JSONField("输入参数", default=dict) + outputs = JSONField("输出参数", default=dict) diff --git a/applications/flow/serializers.py b/applications/flow/serializers.py new file mode 100644 index 0000000..c7dd925 --- /dev/null +++ b/applications/flow/serializers.py @@ -0,0 +1,100 @@ +from django.db import transaction +from rest_framework import serializers + +from applications.flow.models import Process, Node + + +class ProcessViewSetsSerializer(serializers.Serializer): + name = serializers.CharField(required=True) + description = serializers.CharField(required=False, allow_blank=True) + category = serializers.ListField(default="null") + run_type = serializers.CharField(default="null") + pipeline_tree = serializers.JSONField(required=True) + + def save(self, **kwargs): + node_map = {} + for node in self.validated_data["pipeline_tree"]["nodes"]: + node_map[node["uuid"]] = node + dag = {k: [] for k in node_map.keys()} + for line in self.validated_data["pipeline_tree"]["lines"]: + dag[line["from"]].append(line["to"]) + with transaction.atomic(): + process = Process.objects.create(name=self.validated_data["name"], + description=self.validated_data["description"], + run_type=self.validated_data["run_type"], + dag=dag) + bulk_nodes = [] + for node in node_map.values(): + node_data = node["node_data"] + bulk_nodes.append(Node(process=process, + name=node_data["node_name"], + uuid=node["uuid"], + description=node_data["description"], + fail_retry_count=node_data.get("fail_retry_count", 0) or 0, + fail_offset=node_data.get("fail_offset", 0) or 0, + fail_offset_unit=node_data.get("fail_offset_unit", "seconds"), + node_type=node.get("type", 3), + is_skip_fail=node_data["is_skip_fail"], + is_timeout_alarm=node_data["is_skip_fail"], + inputs=node_data["inputs"], + show=node["show"], + top=node["top"], + left=node["left"], + ico=node["ico"], + outputs={}, + component_code="http_request" + )) + Node.objects.bulk_create(bulk_nodes, batch_size=500) + + +class ListProcessViewSetsSerializer(serializers.ModelSerializer): + class Meta: + model = Process + fields = "__all__" + + +class RetrieveProcessViewSetsSerializer(serializers.ModelSerializer): + pipeline_tree = serializers.SerializerMethodField() + + # category = serializers.SerializerMethodField() + # + # def get_category(self, obj): + # return obj.category.all() + + def get_pipeline_tree(self, obj): + lines = [] + nodes = [] + for _from, to_list in obj.dag.items(): + for _to in to_list: + lines.append({ + "from": _from, + "to": _to + }) + node_list = Node.objects.filter(process_id=obj.id).values() + for node in node_list: + nodes.append({"show": node["show"], + "top": node["top"], + "left": node["left"], + "ico": node["ico"], + "type": node["node_type"], + "name": node["name"], + "node_data": { + "inputs": node["inputs"], + "run_mark": 0, + "node_name": node["name"], + "description": node["description"], + "fail_retry_count": node["fail_retry_count"], + "fail_offset": node["fail_offset"], + "fail_offset_unit": node["fail_offset_unit"], + "is_skip_fail": node["is_skip_fail"], + "is_timeout_alarm": node["is_timeout_alarm"]}, + "uuid": node["uuid"]}) + return {"lines": lines, "nodes": nodes} + + class Meta: + model = Process + fields = ("id", "name", "description", "category", "run_type", "pipeline_tree") + + +class ExecuteProcessSerializer(serializers.Serializer): + process_id = serializers.IntegerField(required=True) diff --git a/applications/flow/tests.py b/applications/flow/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/applications/flow/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/applications/flow/urls.py b/applications/flow/urls.py new file mode 100644 index 0000000..58a00c3 --- /dev/null +++ b/applications/flow/urls.py @@ -0,0 +1,6 @@ +from rest_framework.routers import DefaultRouter + +from . import views + +flow_router = DefaultRouter() +flow_router.register(r"", viewset=views.ProcessViewSets, base_name="flow") diff --git a/applications/flow/views.py b/applications/flow/views.py new file mode 100644 index 0000000..cc3e9fc --- /dev/null +++ b/applications/flow/views.py @@ -0,0 +1,103 @@ +from bamboo_engine import api +from bamboo_engine.builder import * +from django.http import JsonResponse +from pipeline.eri.runtime import BambooDjangoRuntime +from rest_framework import mixins +from rest_framework.decorators import action +from rest_framework.response import Response + +from applications.flow.models import Process, Node +from applications.flow.serializers import ProcessViewSetsSerializer, ListProcessViewSetsSerializer, \ + RetrieveProcessViewSetsSerializer, ExecuteProcessSerializer +from applications.utils.dag_helper import DAG +from component.drf.viewsets import GenericViewSet + + +class ProcessViewSets(mixins.ListModelMixin, + mixins.CreateModelMixin, + mixins.RetrieveModelMixin, + GenericViewSet): + serializer_class = ProcessViewSetsSerializer + queryset = Process.objects.order_by("-update_time") + + def get_serializer_class(self): + if self.action == "list": + return ListProcessViewSetsSerializer + elif self.action == "retrieve": + return RetrieveProcessViewSetsSerializer + elif self.action == "execute": + return ExecuteProcessSerializer + return ProcessViewSetsSerializer + + @action(methods=["POST"], detail=False) + def execute(self, request, *args, **kwargs): + validated_data = self.is_validated_data(request.data) + process_id = validated_data["process_id"] + process = Process.objects.filter(id=process_id).first() + node_map = Node.objects.filter(process_id=process_id).in_bulk(field_name="uuid") + dag_obj = DAG() + dag_obj.from_dict(process.dag) + topological_sort = dag_obj.topological_sort() + start = pipeline_tree = EmptyStartEvent() + + for pipeline_id in topological_sort[1:]: + if node_map[pipeline_id].node_type == 0: + act = EmptyStartEvent() + elif node_map[pipeline_id].node_type == 1: + act = EmptyEndEvent() + else: + act = ServiceActivity(component_code="http_request") + pipeline_tree = getattr(pipeline_tree, "extend")(act) + + pipeline_data = Data() + pipeline = builder.build_tree(start, data=pipeline_data) + print(pipeline) + runtime = BambooDjangoRuntime() + api.run_pipeline(runtime=runtime, pipeline=pipeline) + return Response({}) + + +# Create your views here. +def flow(request): + # 使用 builder 构造出流程描述结构 + start = EmptyStartEvent() + act = ServiceActivity(component_code="http_request") + + act2 = ServiceActivity(component_code="fac_cal_comp") + act2.component.inputs.n = Var(type=Var.PLAIN, value=50) + + act3 = ServiceActivity(component_code="fac_cal_comp") + act3.component.inputs.n = Var(type=Var.PLAIN, value=5) + + act4 = ServiceActivity(component_code="fast_execute_job") + act5 = ServiceActivity(component_code="fast_execute_job") + eg = ExclusiveGateway( + conditions={ + 0: '${exe_res} >= 0', + 1: '${exe_res} < 0' + }, + name='act_2 or act_3' + ) + pg = ParallelGateway() + cg = ConvergeGateway() + + end = EmptyEndEvent() + + start.extend(act).extend(eg).connect(act2, act3).to(eg).converge(pg).connect(act4, act5).to(pg).converge(cg).extend( + end) + # 全局变量 + pipeline_data = Data() + pipeline_data.inputs['${exe_res}'] = NodeOutput(type=Var.PLAIN, source_act=act.id, source_key='exe_res') + + pipeline = builder.build_tree(start, data=pipeline_data) + print(pipeline) + # 执行流程对象 + runtime = BambooDjangoRuntime() + + api.run_pipeline(runtime=runtime, pipeline=pipeline) + + result = api.get_pipeline_states(runtime=runtime, root_id=pipeline["id"]) + + result_output = api.get_execution_data_outputs(runtime, act.id).data + # api.pause_pipeline(runtime=runtime, pipeline_id=pipeline["id"]) + return JsonResponse({}) diff --git a/applications/utils/__init__.py b/applications/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/applications/utils/__pycache__/__init__.cpython-36.pyc b/applications/utils/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..53ea54764f542060757072b9a89fbb1dcd65e94a GIT binary patch literal 156 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 PDWy57b|5p0ftUdR4Fe-+ literal 0 HcmV?d00001 diff --git a/component/drf/__pycache__/constants.cpython-36.pyc b/component/drf/__pycache__/constants.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ba477aa649bfb878b708a8e018cdb476048ccda GIT binary patch literal 717 zcmYk2Pj8zr7{(2u4IxQG67AmGmP=J>+GU!iGO${21R`*{%!*{u*iD)E69GB&HfbMY zpI~2!>n_W2*IhQdFfCa8{5Dnvh3SFWnVF=8|WVFfCU7qo* zy4Y87QWhd>P>5-OjBVe6G{hEOh7>OsE+o_Al6~VN8;12H;H4N*ayw@{tfFdPlAa4a z8j3J5F{JeTU~ajMo+HN*vvgT^eeb%dt{UB!)m3W-jcHvE&KLL-MII)DMus>*-gRv> z&K2SO(+;xncTh~_&q(}+@b!B05ETh8*PEQh*>-&wrFVHwdA5x+PIpQ4xGnO1#zeo3 sWX+0u;j*%dvZ}n;J=Xf0G-vySzm*AWbdcl%v(Uzs`uh0RR91 literal 0 HcmV?d00001 diff --git a/component/drf/__pycache__/mixins.cpython-36.pyc b/component/drf/__pycache__/mixins.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db2a5718ec473467485d6ede2c9aee9ad1c667ae GIT binary patch literal 1969 zcmb_dOK%)S5T5RN?t1-*K{4T(n1{3|vaBQ*9zuj*B?z#i*oSCksWqAI-OPG+*6Hq* z<7kBfj_`%Y#ehhnU<4v?NDQ|?O!ymUu4Mfe)30%mIn9x?EjV-CbS%eYHpX z`-^q*TliI8SAf-^$RH&Z1*AMWWVnp{kqhzJ+-KD(=^ zr$7-_g>b7vIjPuHtKuwMRl+H^uLKo$*>bFk2M0RY;PLtRq)3H~qc`J=aoTza)*e6o z+Sbi?JJ;@Qes_2K^3~0iuRF^>ZhZ7@)H}h2ARL1*)XyNa)ux&(Q8mz})1cSk+_^v= z=2Y8thubx{{&lBK8BI0D)~R;2SEWl-p6SJyRlTUmZj=uZtK3E3oG;(nGj`OhbPrf~ z7V7nYdrM^ZexMh0vEDaF<-Inkm$;7_So$HSf*#O=ZEK0vhuW~JO564g+IBu5P@%vS zWb^K4_wQVW3T(W8d+Vo_&b1pGtLvTh4<~0bU$vr0ChBc8n zJk+7|p-Qph;V?Vx==zx8@VvC607v z*M!dca&#~}MpBG^;MB~_X?A4%7@M48C#EK6CLlAfA@uns&-%K~aRz(3sx>d9#K+6_ zRpT^F;!A=-;yK9N%uyn#X1){`S^`cFdald~Wld$?+yedwG!__(l29qezOjCPW#akS z=zJ&>p=KeiIIYc|3mfN}O(xP>oC-Fdgo`!VY^5Ch4LD4sdX~%TYy(lJ#^x902;^h{ zbr=-OE)s_n$%ABwQqU+Fpe0i5=}ut0CAyyk^wOcffq3kn7xS}#u{3N5#+jw=5=p|Cd>k@0qDDRU6$M0F}+|ikI4DljXBoq7tjgb;U4z~vez$s!_4x!kO;u#c(?XoMexyl15 z9!Bv9ibp~8&|~0aAcPBEfT7T2$Uuu^*pPu5GK>Nh@ULX&@ZW`sz2Gko!Zz{{icu6# zqQKt?lbU=QwY|ZN`5%FigV}W`fEjI*va%Qr^?6< z{l|d*V-fteK?Bq(Z+l+zTwO%kuqChDPEvV#Sez_)G3W0~Sb2r-Q6eQ;vWLol09RlW AS^xk5 literal 0 HcmV?d00001 diff --git a/component/drf/__pycache__/pagination.cpython-36.pyc b/component/drf/__pycache__/pagination.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e1aa31e3516f916564c3391077d1dc4cab889b03 GIT binary patch literal 1201 zcma)5&1(}u6rY*hO*UzwwN^zz@Fokk_;nB|QmEoBir$vMxZRngiTe>}HfT!^N{dz~ zC?3T_J?g=m2Qh!iTs797ynFJ!X=1HZaF%)d+czKYz2E!orFy;k_|4+Ii!LEw$R7i~ z$vjMb1&knqCM2aHrHEO=QYUmQb`m%BLXVQ0M7Y9RC&H7?niG~p=`IP%J8+r=)J)t` zLMkb)cj5v*r*B7X+32T>QUU5@QPIgW@cVb9?&X=5F`gR_24EhhJ_kmUkO~qqK|@Ed z&=pST2^ZpdqO?xJvM385-oB_n{Hi&%(APzt9u%*C8Lq3If${y>`{9SzUq3w`Zam$2 z`|;b>U^sa3W3ajXc`$sr0iNxxC&O2peU;elJ02V~l^)c; zQ)7sN6jabv(q&zz#RRj+?RtQn5iS9CS80p2-8H&KA#<-`Tnu2UMP5V+x7dsGepVQ- zQ^-^YWra;r7*F|NOewRB+RTvCT$u{E>{+dKcoGd(wQHsTnW_CbBdMpsuaRr0dtCL*e^-q+G=hrp zInSb0a&D@er@81Sh-;ib=ts$DrOdg=W6l+-Ej)$_v2uhxQY}MERFsDGG{VhBmZMPDs3hAr-*K5s;bDHwt~7$OnTYcwkumtlWFiWegul#21^cB{UI^48e*8UqD6zW|UdJ{14} literal 0 HcmV?d00001 diff --git a/component/drf/__pycache__/viewsets.cpython-36.pyc b/component/drf/__pycache__/viewsets.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63a2277057ca557bd427ba285682411e43b3b800 GIT binary patch literal 4963 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 literal 0 HcmV?d00001 diff --git a/component/drf/authentication.py b/component/drf/authentication.py new file mode 100644 index 0000000..1edb4ab --- /dev/null +++ b/component/drf/authentication.py @@ -0,0 +1,6 @@ +from rest_framework.authentication import SessionAuthentication + + +class CsrfExemptSessionAuthentication(SessionAuthentication): + def enforce_csrf(self, request): + return diff --git a/component/drf/constants.py b/component/drf/constants.py new file mode 100644 index 0000000..9e60a5d --- /dev/null +++ b/component/drf/constants.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +from component.utils import choices_to_namedtuple, tuple_choices + +# 返回状态码 +CODE_STATUS_TUPLE = ( + "OK", + "UNAUTHORIZED", + "VALIDATE_ERROR", + "METHOD_NOT_ALLOWED", + "PERMISSION_DENIED", + "SERVER_500_ERROR", + "OBJECT_NOT_EXIST", +) +CODE_STATUS_CHOICES = tuple_choices(CODE_STATUS_TUPLE) +ResponseCodeStatus = choices_to_namedtuple(CODE_STATUS_CHOICES) + +# 常规字段长度定义 +LEN_SHORT = 32 +LEN_NORMAL = 64 +LEN_MIDDLE = 128 +LEN_LONG = 255 +LEN_X_LONG = 1000 +LEN_XX_LONG = 10000 +LEN_XXX_LONG = 20000 + +# 字段默认值 +EMPTY_INT = 0 +EMPTY_STRING = "" +EMPTY_LIST = [] +EMPTY_DICT = {} diff --git a/component/drf/filters.py b/component/drf/filters.py new file mode 100644 index 0000000..35aa906 --- /dev/null +++ b/component/drf/filters.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +from rest_framework import filters + + +class OrderingFilter(filters.OrderingFilter): + def filter_queryset(self, request, queryset, view): + orderings = self.get_ordering(request, queryset, view) + + if orderings: + custom_ordering = self.get_custom_ordering(request, view, orderings) + return queryset.extra(select=custom_ordering, order_by=orderings) + + return queryset + + @staticmethod + def get_ordering_class(view): + return getattr(view, "ordering_class", None) + + def get_custom_ordering(self, request, view, orderings): + custom_ordering = {} + ordering_class = self.get_ordering_class(view) + + # viewset whether to define ordering class + if ordering_class: + for index, order_name in enumerate(orderings): + reverse = order_name.startswith("-") + order_func = getattr(ordering_class, order_name.lstrip("-"), None) + + # ordering class whether to define order method, Note: method name cannot be the same as field name + if order_func: + custom_order = order_func(reverse, request) + custom_order_name = order_name.lstrip("-") + custom_ordering.update({custom_order_name: custom_order}) + orderings[index] = custom_order_name + + return custom_ordering diff --git a/component/drf/generics.py b/component/drf/generics.py new file mode 100644 index 0000000..a217761 --- /dev/null +++ b/component/drf/generics.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +""" +框架补充相关代码 +""" + +from django.http import Http404 +from rest_framework import exceptions +from rest_framework.exceptions import PermissionDenied +from rest_framework.response import Response +from rest_framework.settings import api_settings +from rest_framework.views import set_rollback + +from component.drf.mapping import exception_mapping + + +def exception_handler(exc, context): + """ + Returns the response that should be used for any given exception. + + By default we handle the REST framework `APIException`, and also + Django's built-in `Http404` and `PermissionDenied` exceptions. + + Any unhandled exceptions may return `None`, which will cause a 500 error + to be raised. + (Rewrite default method exception_handler) + """ + if isinstance(exc, Http404): + exc = exceptions.NotFound() + elif isinstance(exc, PermissionDenied): + exc = exceptions.PermissionDenied() + + if isinstance(exc, exceptions.APIException): + headers = {} + if getattr(exc, "auth_header", None): + headers["WWW-Authenticate"] = exc.auth_header + if getattr(exc, "wait", None): + headers["Retry-After"] = "%d" % exc.wait + + if isinstance(exc.detail, (list, dict)): + data = exc.detail + else: + data = {"detail": exc.detail} + + set_rollback() + # code is added blow + exc_class_name = exc.__class__.__name__ + if exc_class_name in exception_mapping: + message_list = [] + # data type is in (list, dict) + if isinstance(data, dict): + for (k, v) in data.items(): + if isinstance(v, list): + # remove 'non_field_errors' key name + if k in (api_settings.NON_FIELD_ERRORS_KEY, "detail"): + message_list.extend([str(i) for i in v]) + else: + message_list.extend(["{0}: {1}".format(str(k), str(i)) for i in v]) + else: + message_list.append(str(v)) + elif isinstance(data, list): + message_list.extend([str(item) for item in data]) + raise exception_mapping[exc_class_name](";".join(message_list)) + else: + return Response(data, status=exc.status_code, headers=headers) + + return None diff --git a/component/drf/mapping.py b/component/drf/mapping.py new file mode 100644 index 0000000..3c72cf5 --- /dev/null +++ b/component/drf/mapping.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from component.utils.exceptions import (AuthenticationError, NotAuthenticatedError, + PermissionDeniedError, MethodNotAllowedError, + NotAcceptableError, UnsupportedMediaTypeError, + ThrottledError, ParamValidationError, ResourceNotFound) + +# drf exception to blueapps exception +exception_mapping = { + "ValidationError": ParamValidationError, + "AuthenticationFailed": AuthenticationError, + "NotAuthenticated": NotAuthenticatedError, + "PermissionDenied": PermissionDeniedError, + "NotFound": ResourceNotFound, + "MethodNotAllowed": MethodNotAllowedError, + "NotAcceptable": NotAcceptableError, + "UnsupportedMediaType": UnsupportedMediaTypeError, + "Throttled": ThrottledError +} diff --git a/component/drf/middleware.py b/component/drf/middleware.py new file mode 100644 index 0000000..faf420d --- /dev/null +++ b/component/drf/middleware.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +""" +Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community +Edition) available. +Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" + +import json +import logging +import traceback + +from django.conf import settings +from django.http import Http404, JsonResponse +from django.utils.deprecation import MiddlewareMixin +from django.utils.translation import gettext_lazy as _ + +from component.utils.exceptions import BlueException + +try: + from raven.contrib.django.raven_compat.models import \ + sentry_exception_handler +# 兼容未有安装sentry的情况 +except ImportError: + sentry_exception_handler = None + +logger = logging.getLogger('blueapps') + + +class AppExceptionMiddleware(MiddlewareMixin): + + def process_exception(self, request, exception): + """ + app后台错误统一处理 + """ + + self.exception = exception + self.request = request + + # 用户自我感知的异常抛出 + if isinstance(exception, BlueException): + logger.log( + exception.LOG_LEVEL, + (u"""捕获主动抛出异常, 具体异常堆栈->[%s] status_code->[%s] & """ + u"""client_message->[%s] & args->[%s] """) % ( + traceback.format_exc(), + exception.ERROR_CODE, + exception.message, + exception.args + ) + ) + + response = JsonResponse(exception.response_data()) + + response.status_code = exception.STATUS_CODE + return response + + # 用户未主动捕获的异常 + logger.error( + (u"""捕获未处理异常,异常具体堆栈->[%s], 请求URL->[%s], """ + u"""请求方法->[%s] 请求参数->[%s]""") % ( + traceback.format_exc(), + request.path, + request.method, + json.dumps(getattr(request, request.method, None)) + ) + ) + + # 对于check开头函数进行遍历调用,如有满足条件的函数,则不屏蔽异常 + check_funtions = self.get_check_functions() + for check_function in check_funtions: + if check_function(): + return None + + response = JsonResponse({ + "result": False, + 'code': "50000", + 'message': _(u"系统异常,请联系管理员处理"), + 'data': None + }) + response.status_code = 500 + + # notify sentry + if sentry_exception_handler is not None: + sentry_exception_handler(request=request) + + return response + + def get_check_functions(self): + """获取需要判断的函数列表""" + return [getattr(self, func) for func in dir(self) if func.startswith('check') and callable(getattr(self, func))] + + def check_is_debug(self): + """判断是否是开发模式""" + return settings.DEBUG + + def check_is_http404(self): + """判断是否基于Http404异常""" + return isinstance(self.exception, Http404) diff --git a/component/drf/mixins.py b/component/drf/mixins.py new file mode 100644 index 0000000..56a91cc --- /dev/null +++ b/component/drf/mixins.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- + +from rest_framework import status +from rest_framework.response import Response + +from component.drf.constants import ResponseCodeStatus + + +class ApiGenericMixin(object): + """API视图类通用函数""" + + # TODO 权限部分加载基类中 + permission_classes = () + + def finalize_response(self, request, response, *args, **kwargs): + """统一数据返回格式""" + # 文件导出时response {HttpResponse} + if not isinstance(response, Response): + return response + if response.data is None: + response.data = {"result": True, "code": ResponseCodeStatus.OK, "message": "success", "data": []} + elif isinstance(response.data, (list, tuple)): + response.data = { + "result": True, + "code": ResponseCodeStatus.OK, + "message": "success", + "data": response.data, + } + elif isinstance(response.data, dict): + if not ("result" in response.data): + response.data = { + "result": True, + "code": ResponseCodeStatus.OK, + "message": "success", + "data": response.data, + } + else: + response.data = { + "result": response.data["result"], + "code": ResponseCodeStatus.OK, + "message": response.data.get("message"), + "data": response.data, + } + if response.status_code == status.HTTP_204_NO_CONTENT and request.method == "DELETE": + response.status_code = status.HTTP_200_OK + + return super(ApiGenericMixin, self).finalize_response(request, response, *args, **kwargs) + + +class ApiGatewayMixin(object): + """对外开放API返回格式统一 + 错误码返回规范为数字: + 正确:0 + 错误:39XXXXX + """ + + permission_classes = () + + def finalize_response(self, request, response, *args, **kwargs): + """统一数据返回格式""" + + if not isinstance(response, Response): + return response + + if response.data is None: + response.data = {"result": True, "code": 0, "message": "success", "data": []} + elif isinstance(response.data, (list, tuple)): + response.data = { + "result": True, + "code": 0, + "message": "success", + "data": response.data, + } + elif isinstance(response.data, dict) and not ("code" in response.data and "result" in response.data): + response.data = { + "result": True, + "code": 0, + "message": "success", + "data": response.data, + } + + return super(ApiGatewayMixin, self).finalize_response(request, response, *args, **kwargs) diff --git a/component/drf/pagination.py b/component/drf/pagination.py new file mode 100644 index 0000000..2abef2e --- /dev/null +++ b/component/drf/pagination.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +from collections import OrderedDict + +from rest_framework.pagination import PageNumberPagination +from rest_framework.response import Response + + +class CustomPageNumberPagination(PageNumberPagination): + """ + 自定义分页格式,综合页码和url + """ + + page_size = 5 + page_size_query_param = "page_size" + max_page_size = 10000 + + def get_paginated_response(self, data): + return Response( + OrderedDict( + [ + ("page", self.page.number), + ("total_page", self.page.paginator.num_pages), + ("count", self.page.paginator.count), + ("items", data), + ] + ) + ) + + def get_paginated_data(self, data): + return OrderedDict( + [ + ("page", self.page.number), + ("total_page", self.page.paginator.num_pages), + ("count", self.page.paginator.count), + ("items", data), + ] + ) diff --git a/component/drf/renderers.py b/component/drf/renderers.py new file mode 100644 index 0000000..b2b3c15 --- /dev/null +++ b/component/drf/renderers.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +""" +自定义drf renderers 使返回格式和ESB接口返回格式相同 +使用方法: +django settings 中添加 rest_framework配置 +REST_FRAMEWORK = { + "DEFAULT_RENDERER_CLASSES": ("component.drf.renderers.CustomRenderer",), +} + +""" +from rest_framework import status +from rest_framework.renderers import JSONRenderer + + +class CustomRenderer(JSONRenderer): + @staticmethod + def _format_validation_message(detail): + """格式化drf校验错误信息""" + + if isinstance(detail, list): + message = "; ".join(["{}:{}".format(k, v) for k, v in enumerate(detail)]) + elif isinstance(detail, dict): + messages = [] + for k, v in detail.items(): + if isinstance(v, list): + try: + messages.append("{}:{}".format(k, ",".join(v))) + except TypeError: + messages.append("{}:{}".format(k, "部分列表元素的参数不合法,请检查")) + else: + messages.append("{}:{}".format(k, v)) + message = ";".join(messages) + else: + message = detail + + return message + + def render(self, data, accepted_media_type=None, renderer_context=None): + """重构render方法""" + + request = renderer_context.get("request") + response = renderer_context.get("response") + + # 更改删除成功的状态码, 204 --> 200 + if response.status_code == status.HTTP_204_NO_CONTENT and request.method == "DELETE": + response.status_code = status.HTTP_200_OK + + # 重新构建返回的JSON字典 + if response and status.is_success(response.status_code): + ret = { + "result": True, + "code": str(response.status_code * 100), + "message": "success", + "data": data, + } + else: + ret = { + "result": False, + "code": str((response.status_code if response else 500) * 100), + "message": self._format_validation_message(detail=data.get("detail", "") or data), + "data": data, + } + # 返回JSON数据 + return super(CustomRenderer, self).render(ret, accepted_media_type, renderer_context) diff --git a/component/drf/viewsets.py b/component/drf/viewsets.py new file mode 100644 index 0000000..e856e7b --- /dev/null +++ b/component/drf/viewsets.py @@ -0,0 +1,136 @@ +# -*- coding: utf-8 -*- +""" +views相关模块代码 +""" +import math +from collections import OrderedDict + +from django.db import transaction +from rest_framework import mixins, viewsets +from rest_framework.response import Response +from rest_framework.views import APIView as _APIView + +from component.drf.mixins import ApiGenericMixin + + +class APIView(ApiGenericMixin, _APIView): + """APIView""" + + pass + + +class ModelViewSet(ApiGenericMixin, viewsets.ModelViewSet): + """按需改造DRF默认的ModelViewSet类""" + + def perform_create(self, serializer): + """创建时补充基础Model中的字段""" + user = serializer.context.get("request").user + username = getattr(user, "username", "guest") + serializer.save(creator=username, updated_by=username) + + def perform_update(self, serializer): + """更新时补充基础Model中的字段""" + user = serializer.context.get("request").user + username = getattr(user, "username", "guest") + serializer.save(updated_by=username) + + +class ReadOnlyModelViewSet(ApiGenericMixin, viewsets.ReadOnlyModelViewSet): + """按需改造DRF默认的ModelViewSet类""" + + pass + + +class ViewSet(ApiGenericMixin, viewsets.ViewSet): + """按需改造DRF默认的ViewSet类""" + + pass + + +class GenericViewSet(ApiGenericMixin, viewsets.GenericViewSet): + """按需改造DRF默认的GenericViewSet类""" + + def is_validated_data(self, data): + serializer = self.get_serializer(data=data) + serializer.is_valid(raise_exception=True) + return serializer.validated_data + + def get_page_info(self, validated_data): + page = validated_data.get("page", 1) + page_size = validated_data.get("page_size", 5) + start = (int(page) - 1) * int(page_size) + end = start + int(page_size) + return start, end + + def my_paginated_response(self, validated_data, total_count, return_data): + page = int(validated_data.get("page", 1)) + page_size = int(validated_data.get("page_size", 5)) + total_page = math.ceil(total_count / page_size) + return Response( + OrderedDict( + [ + ("page", page), + ("total_page", total_page), + ("count", total_count), + ("items", return_data), + ] + ) + ) + + def convert_post_to_get(self, request): + data = request.query_params + _mutable = data._mutable + data._mutable = True + data.update(request.data) + data._mutable = _mutable + + +class CreateModelAndLogMixin(mixins.CreateModelMixin): + """ + Create a model instance and log. + """ + + @transaction.atomic() + def perform_create(self, serializer): + # 补充基础Model--MaintainerFieldsMixin中的字段 + user = serializer.context.get("request").user + username = getattr(user, "username", "guest") + instance = serializer.save() + log_type, obj, detail = instance.get_summary_title().split("/") + + +class UpdateModelAndLogMixin(mixins.UpdateModelMixin): + """ + Update a model instance and log. + """ + + @transaction.atomic() + def perform_update(self, serializer): + # 补充基础Model--MaintainerFieldsMixin中的字段 + user = serializer.context.get("request").user + username = getattr(user, "username", "guest") + instance = serializer.save(updated_by=username) + log_type, obj, detail = instance.get_summary_title().split("/") + + +class DestroyModelAndLogMixin(mixins.DestroyModelMixin): + """ + Destroy a model instance and log. + """ + + def perform_destroy(self, instance): + with transaction.atomic(): + log_type, obj, detail = instance.get_summary_title().split("/") + username = getattr(self, "request").user.username + instance.delete() + + +class ModelAndLogViewSet( + mixins.ListModelMixin, + CreateModelAndLogMixin, + mixins.RetrieveModelMixin, + UpdateModelAndLogMixin, + DestroyModelAndLogMixin, + GenericViewSet, +): + pass diff --git a/component/utils/__init__.py b/component/utils/__init__.py new file mode 100644 index 0000000..843e67e --- /dev/null +++ b/component/utils/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- + +from .basic import * # noqa +from .drf import * # noqa diff --git a/component/utils/__pycache__/__init__.cpython-36.pyc b/component/utils/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ff6ada6085515c4f6d7864d0d679a1340dba209 GIT binary patch literal 190 zcmXr!<>i{m_%Sh*fq~&M5W@izkmUfx#Uel=g&~D8ham()GXiO*U6H){Jhk>l95bgKfk;mUp{}&_q*Npx5<;|UnwEq$+?GtzYELW z1|x`|iWGE2DG^KrOEO|26b;w|(G**-hawu1xb+vRNlfc@nHEyGYN{j$X#e1juzRrV z6)=Jdwj^`%h%6{H2h|-2{`h<>4%0HzcMC0~`u%Rn4|L9@{qyDHuQ%_19(}q58ev0N zLs<42m<(W_bzajsy!-4edl?SN2Vw$9#jIw%do^|b%bSzE#}CH*AT>(bG1nq5v+*P? zCR!)5%<@tuQ*`Zlv<|WIjFo8uK;7MF$B+jm%(TGY5Em8j;@$wqfxM2+$st>SybHDu ziX5ZNthxzllsV__5>ZF3ht8Ry(?-UD!9&y`Qmw-ma%N$+0W@A@xr1Pd)5+OzwxM%P zwF~|RRUCw;+5yKABnl*v9{ulI5Ho}Lb%-2*-_}a%iyW`7;+r(DLhG6)`cLCVz0I|P ni|cY-TCafD+W*C1%{gQ|$myV>K3v#J$pMBe4yqGGji~Vt?&944 literal 0 HcmV?d00001 diff --git a/component/utils/__pycache__/drf.cpython-36.pyc b/component/utils/__pycache__/drf.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0cd54956f45ec2b318be24fb3e1fd26c831ddbda GIT binary patch literal 917 zcmZ`&&1(}u6rY*hY(7ZELlKoC9t~(HcxyvZOu>_v3e}RbZZp%k+xcI#KdMJAJAMi3)o3uH3&&fBNsJ%GLd%WHEdtbjddvRze^JDJnt-ONJ zPjuuEurGo5CqYp}v5g!&gE69nDywLQP<0CB5?%1392Unz*DQOK>9!d#ZrFYqOAnj` zNEYM@i2of_fEvic0cjF`j$%vcCk#~iwTX+U2|B{=)&Q3P+}8?<$kLKTSXvVm(X3S> zkrJtZQR7To^^pd#l2o-)4TUBwrJ+I|(u9VmQSH5og7iX$KgUQuN03?{a}zK(P_6jS z1MzWmtvHQn67smt zcU#M3{On&Ufa92sDM`f$s0vUqI}D@Xh)`sq28J@^F{w#z@p57%8e55gU2WdujuGS( zLGq&lF9^K&7V#ux=v|&1E0u2>+-80W7GS!S(wyPUd7jSPis>@FY8&+m_d=I~->G^o zbAwVCn6_Vnj`P)eFH^8hKakFewCqf-UPH?l`bG6c!#1fAn4YUU%=e87%NJ~~3_G3x z<4@$E*&aS0jzWC5x!YcQ&|Z6XxU<{7-#qxVeeiO%y>YLz`CymIIN1+vfN} zGpbeQQZ5M=>Ff0>o8;W%xrD$>BnMrK)WGn$ypvp$N^;m&DH(g}zcb5_cxOn-;t`z1 zDjvoeOu#;dPm>ckOEkje&vFgcl+pG1FbFx*buQ_Q9Y>1AW#fveg5%N9W)l(?Q=e6S E1KC>){Qv*} literal 0 HcmV?d00001 diff --git a/component/utils/basic.py b/component/utils/basic.py new file mode 100644 index 0000000..8f1a66e --- /dev/null +++ b/component/utils/basic.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from collections import namedtuple + + +def tuple_choices(tupl): + """从django-model的choices转换到namedtuple""" + return [(t, t) for t in tupl] + + +def dict_to_namedtuple(dic): + """从dict转换到namedtuple""" + return namedtuple("AttrStore", list(dic.keys()))(**dic) + + +def choices_to_namedtuple(choices): + """从django-model的choices转换到namedtuple""" + return dict_to_namedtuple(dict(choices)) diff --git a/component/utils/drf.py b/component/utils/drf.py new file mode 100644 index 0000000..822535b --- /dev/null +++ b/component/utils/drf.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + + +def format_validation_message(e): + """格式化drf校验错误信息""" + + if isinstance(e.detail, list): + message = "; ".join(["{}:{}".format(k, v) for k, v in enumerate(e.detail)]) + elif isinstance(e.detail, dict): + messages = [] + for k, v in e.detail.items(): + if isinstance(v, list): + try: + messages.append("{}:{}".format(k, ",".join(v))) + except TypeError: + messages.append("{}:{}".format(k, "部分列表元素的参数不合法,请检查")) + else: + messages.append("{}:{}".format(k, v)) + message = ";".join(messages) + else: + message = e.detail + + return message diff --git a/component/utils/exceptions.py b/component/utils/exceptions.py new file mode 100644 index 0000000..54befd7 --- /dev/null +++ b/component/utils/exceptions.py @@ -0,0 +1,117 @@ +# -*- coding: utf-8 -*- +import logging + +from django.utils.translation import ugettext as _ + + +class BlueException(Exception): + ERROR_CODE = "0000000" + MESSAGE = _("APP异常") + STATUS_CODE = 500 + LOG_LEVEL = logging.ERROR + + def __init__(self, message=None, data=None, *args): + """ + :param message: 错误消息 + :param data: 其他数据 + :param context: 错误消息 format dict + :param args: 其他参数 + """ + super(BlueException, self).__init__(*args) + self.message = self.MESSAGE if message is None else message + self.data = data + + def render_data(self): + return self.data + + def response_data(self): + return { + "result": False, + "code": self.ERROR_CODE, + "message": self.message, + "data": self.render_data() + } + + +class ClientBlueException(BlueException): + MESSAGE = _("客户端请求异常") + ERROR_CODE = "40000" + STATUS_CODE = 400 + + +class ServerBlueException(BlueException): + MESSAGE = _("服务端服务异常") + ERROR_CODE = "50000" + STATUS_CODE = 500 + + +class AuthenticationError(ClientBlueException): + MESSAGE = _("认证失败") + ERROR_CODE = "40100" + STATUS_CODE = 401 + + +class NotAuthenticatedError(ClientBlueException): + MESSAGE = _("未提供身份验证凭据") + ERROR_CODE = "40101" + STATUS_CODE = 401 + + +class PermissionDeniedError(ClientBlueException): + MESSAGE = _("您无权执行此操作") + ERROR_CODE = "40302" + STATUS_CODE = 403 + + +class MethodNotAllowedError(ClientBlueException): + MESSAGE = _("请求方法不被允许") + ERROR_CODE = "40504" + STATUS_CODE = 405 + + +class NotAcceptableError(ClientBlueException): + MESSAGE = _("无法满足请求Accept头") + ERROR_CODE = "40600" + STATUS_CODE = 406 + + +class UnsupportedMediaTypeError(ClientBlueException): + MESSAGE = _("不支持的媒体类型") + ERROR_CODE = "41500" + STATUS_CODE = 415 + + +class ThrottledError(ClientBlueException): + MESSAGE = _("请求被限制") + ERROR_CODE = "42900" + STATUS_CODE = 429 + + +class DeleteError(ServerBlueException): + MESSAGE = _("数据删除失败") + ERROR_CODE = "50001" + STATUS_CODE = 500 + + +class UpdateError(ServerBlueException): + MESSAGE = _("数据更新失败") + ERROR_CODE = "50002" + STATUS_CODE = 500 + + +class BkEsbReturnError(ServerBlueException): + MESSAGE = _("ESB调用返回错误") + ERROR_CODE = "50302" + STATUS_CODE = 503 + + +class ParamValidationError(ClientBlueException): + MESSAGE = _("参数验证失败") + ERROR_CODE = "40000" + STATUS_CODE = 400 + + +class ResourceNotFound(ClientBlueException): + MESSAGE = _("找不到请求的资源") + ERROR_CODE = "40400" + STATUS_CODE = 404 diff --git a/custom_plugins/__init__.py b/custom_plugins/__init__.py new file mode 100644 index 0000000..633f866 --- /dev/null +++ b/custom_plugins/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- + diff --git a/custom_plugins/__pycache__/__init__.cpython-36.pyc b/custom_plugins/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e21d54d8e1231cffd712200ac4c9b95b503916d9 GIT binary patch literal 152 zcmXr!<>gxIU6v@#z`*brh~a<{$Z`PUViq8g!Vt`$$>_I|p$H_5Abz>JTE!%1Bo^hQ z7RMy#r)1`($0Q}@CgtbHr{<++=B36LCNS2#(Ly%*KxIro_{0u+AKd^db z;un}WCk2G1dwRON_wLTelS%Y`{V3iDAs-mOFGM!Qutx|$fGSealu~j^r|d!pZR$d$rQsLAV`u@AgH7%gCGrop+o5Q=dE3v>PEFi zscmoabO`rC7bbyaQW=oSCg)`_YuDzolnUH#-f4K|qw)tU=*;;YUo^tD&gM7UuGU$cvoEWZ>IOSb>RR2 literal 0 HcmV?d00001 diff --git a/custom_plugins/apps.py b/custom_plugins/apps.py new file mode 100644 index 0000000..eddd725 --- /dev/null +++ b/custom_plugins/apps.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +from django.apps import AppConfig + + +class CustomPluginsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'custom_plugins' diff --git a/custom_plugins/components/__init__.py b/custom_plugins/components/__init__.py new file mode 100644 index 0000000..ecef9ad --- /dev/null +++ b/custom_plugins/components/__init__.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- + + +import logging + +from pipeline.conf import settings +from pipeline.core.flow.activity import Service +from pipeline.component_framework.component import Component + +logger = logging.getLogger('celery') diff --git a/custom_plugins/components/__pycache__/__init__.cpython-36.pyc b/custom_plugins/components/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..99a94f26aaa59def538b04c7dde9cc65d0ed8b3f GIT binary patch literal 398 zcmYjLO-lnY5KXq*?N;qC@GkVS7jH#G5KoE--j;>1O{Qx!A4`&L*|WdKzm${UNq>ST zC#6Ue=H)T-GVfh37AK$g+xCYL@`d$(GGsSceuW^2po-M#%@oyHozcW6YNGQx-}78e zbx{|T0C}B>={v1UL7&O8_{RU_aY*eZmO5EF={TNKGk?Q1ajBXXQpnfW#RC9g~{GBRUHWOrD@3PBJ-6{+K!D5{e>p^?wjOs92v;HjGH ztj;I_^12Z7cUtFyu1T4F;eYa6(vT0}y)@l`e6a?%lN^v1_g44Tfbk*YpukOK5f;jJ z9eTsEmpv$HpyJkST})M9o@frLt+M;71jS5VrT{ZtrpjAs~UEN4n-3M1v3tiXhNjL8#10mTx`DZSelY>rDu4A|xbU zf(r2pJc?Tof{ucUikZDdTm-xFcsw&6e>30Q8IOk#fBsN+1I9kHwJ$<_8&|zRp_%4} z3EBh0^FRc7C_+x>&_sDG;#TLTCwgscU-Y4WnCR$?i@`3_vF@ES-GksP6hl1sb%N&v zVmxnXzQ-nm@AwXzO#OhC*Ohh`uM`OSB#JTF(Dns|~<23BD&`ybVaMdFe z4*PJ%vDN@DhqGpYwy$qLe0%@y%cnQb5m#KUvzA8F;3->8&Dq>>IFnccuk zzg|4LH&2(!8mQ-Ksk7o>zEJt1EF}~NSpl*#>h!>tO`+#$Q@b)pOM@N??@A}t7)V`K zqPcTVt5e^HSCBRiE)i}blJSJUzWHyd(=Kp^ok*lCR1Q-5p_F;48$d~+nZzav9}#FDVRxZ@+K(61PFb(UYYi{Kv@Pf@)UM*H2|a?w-;!-I z@=>nbQrxPt3Jel7O-l>YeN&!H6*6#~xl>ECVrgjn?X|FuExB(I&q--t;?>S(i5wpt z)@9)nIL09{;KZd2-PXxUIqI{GDJ=nNq5KcGPwuZ6dq5CsYDB^}`3PxGf?>Fs{078v B1+xGE literal 0 HcmV?d00001 diff --git a/custom_plugins/components/collections/plugins.py b/custom_plugins/components/collections/plugins.py new file mode 100644 index 0000000..a27c033 --- /dev/null +++ b/custom_plugins/components/collections/plugins.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +import math +from pipeline.core.flow.activity import Service, StaticIntervalGenerator +from pipeline.component_framework.component import Component +import json +import eventlet + +requests = eventlet.import_patched('requests') + + +class HttpRequestService(Service): + __need_schedule__ = False + + def execute(self, data, parent_data): + print("执行了") + return True + + +class HttpRequestComponent(Component): + name = "HttpRequestComponent" + code = "http_request" + bound_service = HttpRequestService diff --git a/custom_plugins/migrations/__init__.py b/custom_plugins/migrations/__init__.py new file mode 100644 index 0000000..40a96af --- /dev/null +++ b/custom_plugins/migrations/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/custom_plugins/migrations/__pycache__/__init__.cpython-36.pyc b/custom_plugins/migrations/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a083b33b9d809db67551399e2fa8c13e937fe566 GIT binary patch literal 163 zcmXr!<>g}bDNB@OU|@I*#Bjg}WH|tFF$<7LVF+f>Wb|9fPy`Z25WfOktzwch5{q(D zi(``WQ!?|?W0Declk)T9Q}fa@^HSprauO@ki}FkJQeu)zi%arzfg+_qnc|q-%=Dtf klFWP{Gd?~uFS8^*Uaz3?7Kcr4eoARhsvXFtVjyM!0E{9mX#fBK literal 0 HcmV?d00001 diff --git a/custom_plugins/static/custom_plugins/plugins.js b/custom_plugins/static/custom_plugins/plugins.js new file mode 100644 index 0000000..1a35a45 --- /dev/null +++ b/custom_plugins/static/custom_plugins/plugins.js @@ -0,0 +1,12 @@ + +/** +* Tencent is pleased to support the open source community by making PaaSƽ̨ (BlueKing PaaS Community +* Edition) available. +* Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. +* Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://opensource.org/licenses/MIT +* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +* specific language governing permissions and limitations under the License. +*/ diff --git a/custom_plugins/tests/__init__.py b/custom_plugins/tests/__init__.py new file mode 100644 index 0000000..948ef15 --- /dev/null +++ b/custom_plugins/tests/__init__.py @@ -0,0 +1,21 @@ + +# -*- coding: utf-8 -*- +""" +Tencent is pleased to support the open source community by making PaaSƽ̨ (BlueKing PaaS Community +Edition) available. +Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" + +import logging + +from pipeline.conf import settings +from pipeline.core.flow.activity import Service +from pipeline.component_framework.component import Component + +logger = logging.getLogger('celery') diff --git a/custom_plugins/tests/components/__init__.py b/custom_plugins/tests/components/__init__.py new file mode 100644 index 0000000..948ef15 --- /dev/null +++ b/custom_plugins/tests/components/__init__.py @@ -0,0 +1,21 @@ + +# -*- coding: utf-8 -*- +""" +Tencent is pleased to support the open source community by making PaaSƽ̨ (BlueKing PaaS Community +Edition) available. +Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" + +import logging + +from pipeline.conf import settings +from pipeline.core.flow.activity import Service +from pipeline.component_framework.component import Component + +logger = logging.getLogger('celery') diff --git a/custom_plugins/tests/components/collections/__init__.py b/custom_plugins/tests/components/collections/__init__.py new file mode 100644 index 0000000..948ef15 --- /dev/null +++ b/custom_plugins/tests/components/collections/__init__.py @@ -0,0 +1,21 @@ + +# -*- coding: utf-8 -*- +""" +Tencent is pleased to support the open source community by making PaaSƽ̨ (BlueKing PaaS Community +Edition) available. +Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" + +import logging + +from pipeline.conf import settings +from pipeline.core.flow.activity import Service +from pipeline.component_framework.component import Component + +logger = logging.getLogger('celery') diff --git a/custom_plugins/tests/components/collections/plugins_test/__init__.py b/custom_plugins/tests/components/collections/plugins_test/__init__.py new file mode 100644 index 0000000..948ef15 --- /dev/null +++ b/custom_plugins/tests/components/collections/plugins_test/__init__.py @@ -0,0 +1,21 @@ + +# -*- coding: utf-8 -*- +""" +Tencent is pleased to support the open source community by making PaaSƽ̨ (BlueKing PaaS Community +Edition) available. +Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" + +import logging + +from pipeline.conf import settings +from pipeline.core.flow.activity import Service +from pipeline.component_framework.component import Component + +logger = logging.getLogger('celery') diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..e30ca066e7d2aee7fd2c9901be885d3b2c47d027 GIT binary patch literal 626688 zcmeFa349yZec+EFK!OK=kwi%_CDDQ?Q4&mvn)}dUnU-jokwjXulvs5fbTBiZV1WPy zfU*?VO+eYsoita|rcKhM?KWxBZF;0vu20iu({tNw({|JRlWm&VX`0QZ*?y92n|Aa6 zy*D$!%m5^4tt}t<>0>_-@BQBI{oeN-Gw;BA_ntXbtlODFrMh6$Gh$?2gkd6gWHONm z^SMYQ^3(9Y`>!Vtf5g0R@X7f8Ug1yBF?q`$^+ITz{aYgQIQxC}JM6dEud`oazsUaW z!29|>)jJ=1bM&8j{-bA(c}wIkS5UNO@5a#$@${wrOrusTTlQ6BseUoHRI{tO`D$fp zvF7|;w4ARw_(PXOnKL;vw^S}(4vP;TJ3BpfZaQ;*cIM3a>CDXR@#*_AV_~T-O2;yD zv+a?_GJD6UVMS|fUuKM&2lk9*8wc0N)AKshFj_fqLKp4oLa|mWR?4+p>u-_?O)_Ou z7i?--oA3rV7k=~GgjUe#Grlbf$wI&mFn(fPJpBL|e|k0J9Zg_&o)H=;VTymL+F1~QxDOiL8xJlCo@ZG_gXTz}eRTUBzEWY(NFs8Rtn zkl9@+D4K~t(fCBnO1W;A>$&>1MVnM9p&+S>E#+y^wB*r%sCvygffDeH8_O== zmx!mQrkF<$)s1|~X{WUHQ>SG_t<|@LLy~SL&Q0BUYTDnQgarv!=twd}DA0MknwgzD zmzh0(>Qv^Qvoois&R)ozoW78mI)83%W)@VQo}N7ircxyxW1XG8Yx?Z;?6K*4eTlkh zWHZM}=vivg%t(1&43`IkY_6A5ZH#^QhV?U#Bj$ zT9?x>+I$B(lzf}e4OIh2%hO(&fqE-b=dRrAq! zS`?Y(C0gPgVs`L~1xvnz#M4mvydOCj+_JuNsWkJ{IXHVyPamn;7id1+{<3CYUb4%k z9r_v#Bd>zKb}Ud`Oi3`PDp@*0vf{JZ@~Z)Eh))M9bbF2SRa<2a2z=5hkZYn&!XIiBZb zffM-soVuTvGn{x(ln)C0q^Q6@{f@&B|ENE{nycFjizRrvR&8)eNnI>1cGAGB8m|h6 z4uJ-_vxX~nm5jUFBXg6ws%W}!`@yjJir;)5%vS`VQ+!nt1Wmk4hxjM`iOV^UMX?Mo z6;OL~^{NeHvvQ%*Nsp{cx}@E%h3$}hcF4Sv<5i&9hLM|;bXnl#+tqM<(HCFfAigel zCWvJm zQ+Blo)kY+5k}#63UdydiYP>$FX&gk;MTmIFjo36);5ktca-1NFZD~SORgzRrpA;bK zxEpn48$n)?IF(m!=X)a~N2lyEyyZge7SvqLE?Wh7o3t&{F4@&Gt#cx(Gf#VdO%kdJ_qj0f8>Vm4Pl5*$(#MWD}<=nzjsa`aVQYmkkm*B0_=oA?c zsIqW)GMIF;MnTd7G)zwHP@{NlQWtrRm!|eZ?CDn0B6&rwFVQz;c$KZ%g{ob)ncVutY7PtJ}*IuD2KCw^m)CN zJ|qo|goEO2D@}D$m33Ly5AO}eZuOM97aJzlLOms~PRg1niOS(U!Pu%lZLoyrc&<}y zQRH}DI=nj=yIBvRtf3==${@8jZ%A8^6hNztL+k@ha=e@)Rj*by7HbzP9cq9&$xAAz zJ-jQJYOB29*&ssg7r2h8a+0R2nzj>Si>*|-Tp3>0R%><2q^=N!hsT2Ha!ppvbUXAB z%A}@hk|^A<17f%833PsL)wiqFN;OxUFITFhqPEjkCRLS_W#w=tkUl&Uy_&ze^@
  1. ISelcz8(jYJUVm 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

    ;vFb+ANGyVkJkmy^nq4G9%?P=G#64fUhu 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 Tu$A|W6~i#Pv3PG*toZ){BG~u! literal 0 HcmV?d00001 diff --git a/dj_flow/__init__.py b/dj_flow/__init__.py new file mode 100644 index 0000000..3a074b7 --- /dev/null +++ b/dj_flow/__init__.py @@ -0,0 +1,3 @@ +from .celery_app import app as celery_app + +__all__ = ('celery_app',) diff --git a/dj_flow/__pycache__/__init__.cpython-36.pyc b/dj_flow/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e2a21beabae9cdb60374cc45f1e9e0dba6f0dc1 GIT binary patch literal 210 zcmX|5y$ZrG5WX}PrL>zb(Z$70q__x9E^Z}oq)n`qGzqCi`bfS~9i1FqolHA;@ckSg z+CrHCL@li?!%B>xuQYz_s^!}I< zN5_ax;>J_M9FZ%9_y8CBeWGu+->~w+osumpji`0S3f>gPpwv~ZC0fP%%9&0JCa!o^ b=FSjnUEdH_wjUPT#)wYIY;4kwf8yW==npmQ literal 0 HcmV?d00001 diff --git a/dj_flow/__pycache__/celery_app.cpython-36.pyc b/dj_flow/__pycache__/celery_app.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3018b510d3851a3e980f2c59d31ca3f759311b99 GIT binary patch literal 1623 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 literal 0 HcmV?d00001 diff --git a/dj_flow/__pycache__/urls.cpython-36.pyc b/dj_flow/__pycache__/urls.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..df798e8d9e41f2eb59c6a93b85008adc11119da2 GIT binary patch literal 1014 zcma)5O>5jR5VgJD?ADvKJr#P>ZDUAnn%qoVT0%ktC5L`o%z~q}w6+#~7)jeSxrY9j z{v}^~>ao|JI#Rr_6bdm|jOEdr_uh<74i1v<&wt})6a+tmoo5X3TX@YSEF>rc5|W6A zA}XWM#UnlvaT$woIriT%-xHH^5(YFTV;Zfe>qmDH#Cvp1ClH5sQ4^I3nS2V;DQ=@6 z`10`sI#qJTnvKSmDVZdnTZ*nWns?Y*s-?L?oEeL>+E{8395Bc#^p(+Tlc95^kx-f< zCRa)e4}m&Pv7yLNS|kXb*4oY#c}`SqGP1_9QJq$6THCBvBBwGx$&PcYI#!$9CFfAy z&s{uElT(h3d9egxWC!(sER=1jc0@97)RxYB!1C-L$j0So z*i;VWF#U(og{=98Fxh|!zMhj-Lo>JjTzF#;P=WTiTzZ(I)nH|DZ`XZ0GH3XfZC3972{@jx21TFsUk<~ZnQJ4!TMq(H~8l+U0CoYj6XP3CHNPTF0q zJ~qtKK6c{!+0H=x2=vS$xaCiARxIikYZ$~ut(@PBB^FDiDk>W$Y1MIj(*SWv7Gzzy g5(|fzbvOO=l~82E>6<5jWD;27a6fz+?vM7vzepuKX#fBK literal 0 HcmV?d00001 diff --git a/dj_flow/__pycache__/wsgi.cpython-36.pyc b/dj_flow/__pycache__/wsgi.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..adc38a5223516c0525da2e96f32bb9dc752ac747 GIT binary patch literal 541 zcmYjN!H&}~6m*>KwgeV&KzsJJ5+sPdRS2=tmZ}K4hb}^@BDrq-k~(tyqS$TeUiSy~ z%pdSKoO9*Gkt-*hE=aZHdA8qpX7n!3&Z2LRevA8nke}peh5r1`Z~MxFBnu(~Np-LY zd<`|N!bKPm2+Cf0B75@Wj`~}8M;51&&dKof_DA$(KAEx%O|A--W5Zb8U>d;_lytuL~R~lY03lOcHtL-RBBxW|2r7#8l&y-=6fJrXm*U1`p4igEr#(f3G zB|BTFB>Ls&KxV_BeO`d$-5WoO(Vky@xSUO{`FwnHGo4N5{L}T-=a1vtXR_qE#$9Z| zIb{kv?6-Z+eFV;1injHHE=ZjD{BbASP;b=s!E9B7rj7hZ3Axy4*FHXS{7#z46A$ob zG#;hdS~MDLnxXVQ=}J^9L=L7<26(N-zG!e`Wcn{q+IhwGz8$=I81~zNm$M!8=zu<< GPw8JBq^qI; literal 0 HcmV?d00001 diff --git a/dj_flow/celery_app.py b/dj_flow/celery_app.py new file mode 100644 index 0000000..de86087 --- /dev/null +++ b/dj_flow/celery_app.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +""" +Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community +Edition) available. +Copyright (C) 2017-2020 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" + +from __future__ import absolute_import, unicode_literals + +import os +import time +from celery import Celery, platforms +from django.conf import settings + +platforms.C_FORCE_ROOT = True + +# set the default Django settings module for the 'celery' program. +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dj_flow.settings") + +app = Celery("dj_flow") + +# Using a string here means the worker don't have to serialize +# the configuration object to child processes. +# - namespace='CELERY' means all celery-related configuration keys +# should have a `CELERY_` prefix. +app.config_from_object("django.conf:settings") + +# Load task modules from all registered Django app configs. +app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) + + +@app.task(bind=True) +def debug_task(self): + print("Request: {!r}".format(self.request)) + time.sleep(2) diff --git a/dj_flow/settings.py b/dj_flow/settings.py new file mode 100644 index 0000000..f183829 --- /dev/null +++ b/dj_flow/settings.py @@ -0,0 +1,146 @@ +import os +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +BROKER_URL = "redis://localhost:6379/3" +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-u5_r=pekio0@zt!y(kgbufuosb9mddu8*qeejkzj@=7uyvb392' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ["*"] +CORS_ALLOW_CREDENTIALS = True +CSRF_COOKIE_NAME = "dj-flow_csrftoken" +CORS_ORIGIN_WHITELIST = [ + "http://127.0.0.1:8080" +] + +# Application definition + +INSTALLED_APPS = [ + "corsheaders", + "pipeline", + "pipeline.engine", + "pipeline.component_framework", + "pipeline.eri", + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + "custom_plugins", + "rest_framework", + "applications.flow" + +] + +MIDDLEWARE = [ + "corsheaders.middleware.CorsMiddleware", + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "component.drf.middleware.AppExceptionMiddleware" +] + +ROOT_URLCONF = 'dj_flow.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'dj_flow.wsgi.application' +TIME_ZONE = "Asia/Shanghai" +LANGUAGE_CODE = "zh-hans" +# Database +# https://docs.djangoproject.com/en/3.2/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.mysql", + "NAME": "bomboo", # noqa + "USER": "root", + "PASSWORD": "xhongc", + "HOST": "localhost", + "PORT": "3306", + # 单元测试 DB 配置,建议不改动 + "TEST": {"NAME": "test_db", "CHARSET": "utf8", "COLLATION": "utf8_general_ci"}, + }, +} + +# Password validation +# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + +STATIC_URL = '/static/' + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +IS_USE_CELERY = True + +if IS_USE_CELERY: + INSTALLED_APPS += ("django_celery_beat", "django_celery_results") + CELERY_ENABLE_UTC = False + CELERY_TASK_SERIALIZER = "pickle" + CELERY_ACCEPT_CONTENT = ['pickle', ] + CELERYBEAT_SCHEDULER = "django_celery_beat.schedulers.DatabaseScheduler" + +REST_FRAMEWORK = { + "EXCEPTION_HANDLER": "component.drf.generics.exception_handler", + "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",), + "DEFAULT_PAGINATION_CLASS": "component.drf.pagination.CustomPageNumberPagination", + "PAGE_SIZE": 10, + "TEST_REQUEST_DEFAULT_FORMAT": "json", + "DEFAULT_AUTHENTICATION_CLASSES": ("rest_framework.authentication.SessionAuthentication",), + "DEFAULT_FILTER_BACKENDS": ( + "django_filters.rest_framework.DjangoFilterBackend", + "rest_framework.filters.OrderingFilter", + ), + "DATETIME_FORMAT": "%Y-%m-%d %H:%M:%S", + "NON_FIELD_ERRORS_KEY": "params_error", +} diff --git a/dj_flow/urls.py b/dj_flow/urls.py new file mode 100644 index 0000000..9148320 --- /dev/null +++ b/dj_flow/urls.py @@ -0,0 +1,24 @@ +"""URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/3.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include +from applications.flow.urls import flow_router + +urlpatterns = [ + path('admin/', admin.site.urls), + path("process/", include(flow_router.urls)), + +] diff --git a/dj_flow/wsgi.py b/dj_flow/wsgi.py new file mode 100644 index 0000000..f03105e --- /dev/null +++ b/dj_flow/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dj_flow.settings') + +application = get_wsgi_application() diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..62f5adf --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dj_flow.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b170483 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,9 @@ +Django==2.2.6 +bamboo-pipeline==3.14.0 +mysqlclient==1.4.4 +eventlet==0.33.0 +djangorestframework==3.8.1 +pyyaml==6.0 +django-cors-headers==3.2.1 +django-filter==2.0.0 +django-mysql==3.8.1 diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..09b6aa8 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,25 @@ + + + + + + 调度平台 + + + + + +

    + + + + + diff --git a/web/.babelrc b/web/.babelrc new file mode 100644 index 0000000..23a3101 --- /dev/null +++ b/web/.babelrc @@ -0,0 +1,15 @@ +{ + "presets": [ + ["env", { + "modules": false, + "targets": { + "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] + } + }], + "stage-2" + ], + "plugins": ["transform-vue-jsx", "transform-runtime", ["import", { + "libraryName": "view-design", + "libraryDirectory": "src/components" + }]] +} diff --git a/web/.editorconfig b/web/.editorconfig new file mode 100644 index 0000000..e291365 --- /dev/null +++ b/web/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/web/.eslintignore b/web/.eslintignore new file mode 100644 index 0000000..eb7728a --- /dev/null +++ b/web/.eslintignore @@ -0,0 +1,8 @@ +/build/ +/config/ +/dist/ +/*.js +/node_modules/ +/src/assets/ +/src/components/ +/src/common/validate.js diff --git a/web/.eslintrc.js b/web/.eslintrc.js new file mode 100644 index 0000000..9205323 --- /dev/null +++ b/web/.eslintrc.js @@ -0,0 +1,1325 @@ +/** + * @file eslint config + * @author + */ +module.exports = { + // 无需向父目录查找eslint文件 + root: true, + + // 使用babel-eslint解析器 + parserOptions: { + parser: 'babel-eslint', + sourceType: 'module' + }, + + // 指定脚本的运行环境,每种环境都有一组特定的预定义全局变量 + env: { + browser: true + }, + + // 数组形式,每个配置继承它前面的配置 + extends: [ + 'plugin:vue/recommended', + 'standard' + ], + // 省略包名的前缀 eslint-plugin- + // required to lint *.vue files + plugins: [ + 'vue' + ], + + // 配置额外的全局变量 + globals: { + // value 为 true 允许被重写,为 false 不允许被重写 + NODE_ENV: false + }, + + // 自定义规则 + rules: { + // 使用单引号 + /* 示例 + // bad code + let str = "hello world" + + // good code + let str = 'hello world' + */ + 'quotes': ['error', 'single'], + + // 三等号 + /* 示例 + // bad code + if (a == b) {} + + // good code + if (a === b) {} + */ + 'eqeqeq': ['error', 'always'], + + // 禁止出现未使用过的变量 + 'no-unused-vars': 'error', + + // 强制在关键字前后使用一致的空格 + /* 示例 + // bad code + if (foo) { + //... + }else if (bar) { + //... + }else { + //... + } + + // good code + if (foo) { + //... + } else if (bar) { + //... + } else { + //... + } + */ + 'keyword-spacing': [ + 'error', + { + 'overrides': { + 'if': { + 'after': true + }, + 'for': { + 'after': true + }, + 'while': { + 'after': true + }, + 'else': { + 'after': true + } + } + } + ], + + // https://eslint.org/docs/rules/camelcase + 'camelcase': ['error', {'properties': 'never'}], + + // 缩进使用 4 个空格,并且 switch 语句中的 Case 需要缩进 + // https://eslint.org/docs/rules/indent + 'indent': ['error', 4, { + 'SwitchCase': 1, + 'flatTernaryExpressions': true + }], + + // 数组的括号内的前后禁止有空格 + // https://eslint.org/docs/rules/array-bracket-spacing + /* 示例 + // bad code + const foo = [ 'foo' ]; + const foo = [ 'foo']; + const foo = ['foo' ]; + const foo = [ 1 ]; + + // good code + const foo = ['foo']; + const foo = [1]; + */ + 'array-bracket-spacing': ['error', 'never'], + + // 需要在操作符之前放置换行符 + // https://eslint.org/docs/rules/operator-linebreak + // 'operator-linebreak': ['error', 'before'], + + // 在开发阶段打开调试 (区分stag prod) + // https://eslint.org/docs/rules/no-debugger + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', + + // 只有一个参数时,箭头函数体可以省略圆括号 + // https://eslint.org/docs/rules/arrow-parens + 'arrow-parens': 'off', + + // 禁止空语句(可在空语句写注释避免),允许空的 catch 语句 + // https://eslint.org/docs/rules/no-empty + /* 示例 + // bad code + if (foo) { + } + + while (foo) { + } + + // good code + if (foo) { + // empty + } + */ + 'no-empty': ['error', {'allowEmptyCatch': true}], + + // 禁止在语句末尾使用分号 + // https://eslint.org/docs/rules/semi + /* 示例 + // bad code + const obj = {}; + + // good code + const obj = {} + */ + 'semi': ['error', 'never'], + + // 函数圆括号之前没有空格(挺有争议的) + // https://eslint.org/docs/rules/space-before-function-paren + /* 示例 + // bad code + function foo () { + // ... + } + + const bar = function () { + // ... + } + + // good code + function foo() { + // ... + } + + const bar = function() { + // ... + } + */ + 'space-before-function-paren': ['error', { + 'anonymous': 'never', // 匿名函数表达式 + 'named': 'never', // 命名的函数表达式 + 'asyncArrow': 'never' // 异步的箭头函数表达式 + }], + + // 禁止行尾有空格 + // https://eslint.org/docs/rules/no-trailing-spaces + 'no-trailing-spaces': ['error'], + + + // 注释的斜线或 * 后必须有空格 + // https://eslint.org/docs/rules/spaced-comment + /* 示例 + // bad code + //This is a comment with no whitespace at the beginning + + // good code + // This is a comment with a whitespace at the beginning + */ + 'spaced-comment': ['error', 'always', { + 'line': { + 'markers': ['*package', '!', '/', ',', '='] + }, + 'block': { + // 前后空格是否平衡 + 'balanced': false, + 'markers': ['*package', '!', ',', ':', '::', 'flow-include'], + 'exceptions': ['*'] + } + }], + + // https://eslint.org/docs/rules/no-template-curly-in-string + // 禁止在字符串中使用字符串模板。不限制 + 'no-template-curly-in-string': 'off', + + // https://eslint.org/docs/rules/no-useless-escape + // 禁止出现没必要的转义。不限制 + 'no-useless-escape': 'off', + + // https://eslint.org/docs/rules/no-var + // 禁止使用 var + 'no-var': 'error', + + // https://eslint.org/docs/rules/prefer-const + // 如果一个变量不会被重新赋值,必须使用 `const` 进行声明。 + /* 示例 + // bad code + let a = 3 + console.log(a) + + // good code + const a = 3 + console.log(a) + */ + 'prefer-const': 'error', + + // eslint-plugin-vue@7 新增的规则,暂时先全部关闭 + 'vue/no-dupe-v-else-if': 'off', + 'vue/component-definition-name-casing': 'off', + 'vue/one-component-per-file': 'off', + 'vue/v-slot-style': 'off', + 'vue/no-arrow-functions-in-watch': 'off', + 'vue/no-custom-modifiers-on-v-model': 'off', + 'vue/no-multiple-template-root': 'off', + 'vue/no-mutating-props': 'off', + 'vue/no-v-for-template-key': 'off', + 'vue/no-v-model-argument': 'off', + 'vue/valid-v-bind-sync': 'off', + 'vue/valid-v-slot': 'off', + 'vue/experimental-script-setup-vars': 'off', + 'vue/no-lone-template': 'off', + + // 不允许数组括号内有空格 + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/array-bracket-spacing.md + /** + * 示例 + * bad code + * var arr = [ 'foo', 'bar' ]; + * var arr = ['foo', 'bar' ]; + * var [ x, y ] = z; + * + * good code + * var arr = ['foo', 'bar', 'baz']; + * var arr = [['foo'], 'bar', 'baz']; + * var [x, y] = z; + */ + 'vue/array-bracket-spacing': ['error', 'never'], + + // 在箭头函数的箭头之前/之后需要空格 + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/arrow-spacing.md + /** + * 示例 + * bad code + * ()=> {}; + * () =>{}; + * (a)=> {}; + * (a) =>{}; + * + * good code + * () => {}; + * (a) => {}; + * a => a; + * () => {'\n'}; + */ + 'vue/arrow-spacing': ['error', {'before': true, 'after': true}], + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/attribute-hyphenation.md + // vue html 属性小写,连字符 + /** + * 示例 + * bad code + * + * + * good code + * + */ + 'vue/attribute-hyphenation': ['error', 'always'], + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/attributes-order.md + // 属性顺序,不限制 + 'vue/attributes-order': 'off', + + // 在打开块之后和关闭块之前强制块内的空格 + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/block-spacing.md + /** + * 示例 + * bad code + * function foo() {return true;} + * if (foo) { bar = 0;} + * (a) =>{};function baz() {let i = 0; + * return i; + * } + * + * good code + * function foo() { return true; } + * if (foo) { bar = 0; } + */ + 'vue/block-spacing': ['error', 'always'], + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/camelcase.md + // 后端数据字段经常不是驼峰,所以不限制 properties,也不限制解构 + /** + * 示例 + * bad code + * import { no_camelcased } from "external-module" + * var my_favorite_color = "#112C85"; + * obj.do_something = function() { + * // ... + * }; + * + * good code + * import { no_camelcased as camelCased } from "external-module"; + * var myFavoriteColor = "#112C85"; + * var _myFavoriteColor = "#112C85"; + * var myFavoriteColor_ = "#112C85"; + */ + 'vue/camelcase': ['error', {'properties': 'never'}], + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/comma-dangle.md + // 禁止使用拖尾逗号,如 {demo: 'test',} + /** + * 示例 + * bad code + * var foo = { + * bar: "baz", + * qux: "quux", + * var arr = [1,2,]; + * }; + * + * good code + * var foo = { + * bar: "baz", + * qux: "quux" + * var arr = [1,2]; + */ + 'vue/comma-dangle': ['error', 'never'], + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/comment-directive.md + // vue 文件 template 中允许 eslint-disable eslint-enable eslint-disable-line eslint-disable-next-line + // 行内注释启用/禁用某些规则,配置为 1 即允许 + /** + * 示例 + * bad code + *
    + * + * good code + *
    + */ + 'vue/comment-directive': 'error', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/component-name-in-template-casing.md + // 组件 html 标签的形式,连字符形式,所有 html 标签均会检测,如引入第三方不可避免,可通过 ignores 配置,支持正则,不限制 + 'vue/component-name-in-template-casing': 'off', + + // 需要 === 和 !==,不将此规则应用于null + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/eqeqeq.md + /** + * 示例 + * bad code + * if (x == 42) { } + * if ("" == text) { } + * if (obj.getStuff() != undefined) { } + * var arr = [1,2,]; + * }; + * + * good code + * a === b + * foo === true + * bananas !== 1 + * value === undefined + */ + 'vue/eqeqeq': ['error', 'always', {'null': 'ignore'}], + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-closing-bracket-newline.md + // 单行写法不需要换行,多行需要,不限制 + 'vue/html-closing-bracket-newline': 'off', + + // 自关闭标签需要空格 + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-closing-bracket-spacing.md + /* 示例 + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + */ + 'vue/html-closing-bracket-spacing': ['error', { + 'startTag': 'never', + 'endTag': 'never', + 'selfClosingTag': 'always' + }], + + // 标签必须有结束标签 + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-end-tags.md + /* 示例 + +
    +

    + + +

    +

    + */ + 'vue/html-end-tags': 'error', + + // html的缩进.在多行情况下,属性不与第一个属性垂直对齐 + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-indent.md + /* 示例 + +
    + + +
    + */ + 'vue/html-indent': ['error', 4, { + 'attribute': 1, + 'baseIndent': 1, + 'closeBracket': 0, + 'alignAttributesVertically': false, // 在多行情况下,属性是否应与第一个属性垂直对齐 + 'ignores': [] + }], + + // html属性引用采用双引号 + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-quotes.md + /* 示例 + + + + + + */ + 'vue/html-quotes': ['error', 'double'], + + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-self-closing.md + // html tag 是否自闭和,不限制 + 'vue/html-self-closing': 'off', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/jsx-uses-vars.md + // 当变量在 `JSX` 中被使用了,那么 eslint 就不会报出 `no-unused-vars` 的错误。需要开启 eslint no-unused-vars 规则才适用 + /* + import HelloWorld from './HelloWorld'; + + export default { + render () { + return ( + + ) + }, + } + 此时不会报 `no-unused-vars` 的错误,仅警告 + */ + 'vue/jsx-uses-vars': 'warn', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/key-spacing.md + // 属性定义,冒号前没有空格,后面有空格 + /* 示例 + // bad code + const obj = { a:1 } + + // good code + const obj = { a: 1 } + */ + 'vue/key-spacing': ['error', {'beforeColon': false, 'afterColon': true}], + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/match-component-file-name.md + // 组件名称属性与其文件名匹配,不限制 + 'vue/match-component-file-name': 'off', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/max-attributes-per-line.md + // 每行属性的最大个数,不限制 + 'vue/max-attributes-per-line': 'off', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/multiline-html-element-content-newline.md + // 在多行元素的内容前后需要换行符,不限制 + 'vue/multiline-html-element-content-newline': 'off', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/mustache-interpolation-spacing.md + // template 中 {{var}},不限制 + 'vue/mustache-interpolation-spacing': 'off', + + // name属性强制使用连字符形式 + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/name-property-casing.md + /* 示例 + // bad code + export default { + name: 'MyComponent' + } + + // good code + export default { + name: 'my-component' + } + */ + 'vue/name-property-casing': ['error', 'kebab-case'], + + // 禁止在计算属性中执行异步操作 + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-async-in-computed-properties.md + /* 示例 + computed: { + // bad code + pro () { + return Promise.all([new Promise((resolve, reject) => {})]) + }, + foo1: async function () { + return await someFunc() + }, + bar () { + return fetch(url).then(response => {}) + }, + tim () { + setTimeout(() => { }, 0) + }, + inter () { + setInterval(() => { }, 0) + }, + anim () { + requestAnimationFrame(() => {}) + }, + + // good code + foo () { + var bar = 0 + try { + bar = bar / this.a + } catch (e) { + return 0 + } finally { + return bar + } + }, + } + */ + 'vue/no-async-in-computed-properties': 'error', + + // 禁止布尔默认值,不限制 + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-boolean-default.md + 'vue/no-boolean-default': 'off', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-confusing-v-for-v-if.md + 'vue/no-confusing-v-for-v-if': 'off', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-dupe-keys.md + // 属性名禁止重复 + /* 示例 + // bad code + person: { + age: '', + age: '' + } + + // good code + person: { + age: '', + name: '' + } + */ + 'vue/no-dupe-keys': 'error', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-duplicate-attributes.md + // 禁止 html 元素中出现重复的属性 + /* 示例 + // bad code +
    + + // good code +
    + */ + 'vue/no-duplicate-attributes': 'error', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-multi-spaces.md + // 删除 html 标签中连续多个不用于缩进的空格 + /* 示例 + // bad code +
    + + // good code +
    + */ + 'vue/no-multi-spaces': 'error', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-parsing-error.md + // 禁止语法错误 + /* 示例 + // bad code +
    + +
    + + // good code +
    + +
    + */ + 'vue/no-parsing-error': 'error', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-reserved-keys.md + // 禁止使用保留字,包括Vue + /* 示例 + // bad code + props: { + $nextTick () {} + } + + // good code + props: { + next () {} + } + */ + 'vue/no-reserved-keys': 'error', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-restricted-syntax.md + // 禁止使用特定的语法,不限制 + 'vue/no-restricted-syntax': 'off', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-shared-component-data.md + // data 属性必须是函数 + /* 示例 + // bad code + data: { + } + + // good code + data() { + return {} + } + */ + 'vue/no-shared-component-data': 'error', + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-side-effects-in-computed-properties.md + // 禁止在计算属性对属性进行修改,不限制 + 'vue/no-side-effects-in-computed-properties': 'off', + + // 不允许在属性中的等号周围有空格 + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-spaces-around-equal-signs-in-attribute.md + /* 示例 + // bad code +
    + + // good code +
    + */ + 'vue/no-spaces-around-equal-signs-in-attribute': 'error', + + + // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/no-template-key.md + // 禁止在